diff options
1107 files changed, 16680 insertions, 10160 deletions
diff --git a/Cargo.lock b/Cargo.lock index 01e814e7d7f..fc16ccf0a67 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -720,6 +720,7 @@ dependencies = [ "miropt-test-tools", "regex", "rustfix", + "semver", "serde", "serde_json", "tracing", @@ -3301,6 +3302,7 @@ version = "0.0.0" dependencies = [ "itertools", "rustc_ast", + "rustc_data_structures", "rustc_lexer", "rustc_span", "thin-vec", @@ -3621,6 +3623,7 @@ version = "0.0.0" dependencies = [ "annotate-snippets 0.11.4", "derive_setters", + "rustc_abi", "rustc_ast", "rustc_ast_pretty", "rustc_data_structures", @@ -3718,6 +3721,7 @@ name = "rustc_hir_analysis" version = "0.0.0" dependencies = [ "itertools", + "rustc_abi", "rustc_arena", "rustc_ast", "rustc_attr", @@ -3906,6 +3910,7 @@ dependencies = [ name = "rustc_lint" version = "0.0.0" dependencies = [ + "rustc_abi", "rustc_ast", "rustc_ast_pretty", "rustc_attr", @@ -3980,6 +3985,7 @@ dependencies = [ "bitflags 2.6.0", "libloading", "odht", + "rustc_abi", "rustc_ast", "rustc_attr", "rustc_data_structures", @@ -4074,6 +4080,7 @@ version = "0.0.0" dependencies = [ "polonius-engine", "regex", + "rustc_abi", "rustc_ast", "rustc_data_structures", "rustc_errors", @@ -4095,6 +4102,7 @@ version = "0.0.0" dependencies = [ "either", "itertools", + "rustc_abi", "rustc_arena", "rustc_ast", "rustc_attr", @@ -4187,6 +4195,7 @@ dependencies = [ name = "rustc_passes" version = "0.0.0" dependencies = [ + "rustc_abi", "rustc_ast", "rustc_ast_pretty", "rustc_attr", @@ -4213,6 +4222,7 @@ name = "rustc_pattern_analysis" version = "0.0.0" dependencies = [ "rustc-hash 2.0.0", + "rustc_abi", "rustc_apfloat", "rustc_arena", "rustc_data_structures", @@ -4352,6 +4362,7 @@ dependencies = [ "bitflags 2.6.0", "getopts", "libc", + "rustc_abi", "rustc_ast", "rustc_data_structures", "rustc_errors", @@ -4415,6 +4426,7 @@ version = "0.0.0" dependencies = [ "punycode", "rustc-demangle", + "rustc_abi", "rustc_data_structures", "rustc_errors", "rustc_hir", @@ -4496,6 +4508,7 @@ name = "rustc_transmute" version = "0.0.0" dependencies = [ "itertools", + "rustc_abi", "rustc_ast_ir", "rustc_data_structures", "rustc_hir", @@ -4503,7 +4516,6 @@ dependencies = [ "rustc_macros", "rustc_middle", "rustc_span", - "rustc_target", "tracing", ] diff --git a/compiler/rustc_abi/src/layout.rs b/compiler/rustc_abi/src/layout.rs index 0340d1bd6bc..86de39b8f97 100644 --- a/compiler/rustc_abi/src/layout.rs +++ b/compiler/rustc_abi/src/layout.rs @@ -7,7 +7,7 @@ use tracing::debug; use crate::{ Abi, AbiAndPrefAlign, Align, FieldsShape, HasDataLayout, IndexSlice, IndexVec, Integer, - LayoutS, Niche, NonZeroUsize, Primitive, ReprOptions, Scalar, Size, StructKind, TagEncoding, + LayoutData, Niche, NonZeroUsize, Primitive, ReprOptions, Scalar, Size, StructKind, TagEncoding, Variants, WrappingRange, }; @@ -26,9 +26,9 @@ fn absent<'a, FieldIdx, VariantIdx, F>(fields: &IndexSlice<FieldIdx, F>) -> bool where FieldIdx: Idx, VariantIdx: Idx, - F: Deref<Target = &'a LayoutS<FieldIdx, VariantIdx>> + fmt::Debug, + F: Deref<Target = &'a LayoutData<FieldIdx, VariantIdx>> + fmt::Debug, { - let uninhabited = fields.iter().any(|f| f.abi.is_uninhabited()); + let uninhabited = fields.iter().any(|f| f.is_uninhabited()); // We cannot ignore alignment; that might lead us to entirely discard a variant and // produce an enum that is less aligned than it should be! let is_1zst = fields.iter().all(|f| f.is_1zst()); @@ -89,7 +89,7 @@ impl<F> LayoutCalculatorError<F> { } type LayoutCalculatorResult<FieldIdx, VariantIdx, F> = - Result<LayoutS<FieldIdx, VariantIdx>, LayoutCalculatorError<F>>; + Result<LayoutData<FieldIdx, VariantIdx>, LayoutCalculatorError<F>>; #[derive(Clone, Copy, Debug)] pub struct LayoutCalculator<Cx> { @@ -105,7 +105,7 @@ impl<Cx: HasDataLayout> LayoutCalculator<Cx> { &self, a: Scalar, b: Scalar, - ) -> LayoutS<FieldIdx, VariantIdx> { + ) -> LayoutData<FieldIdx, VariantIdx> { let dl = self.cx.data_layout(); let b_align = b.align(dl); let align = a.align(dl).max(b_align).max(dl.aggregate_align); @@ -119,7 +119,7 @@ impl<Cx: HasDataLayout> LayoutCalculator<Cx> { .chain(Niche::from_scalar(dl, Size::ZERO, a)) .max_by_key(|niche| niche.available(dl)); - LayoutS { + LayoutData { variants: Variants::Single { index: VariantIdx::new(0) }, fields: FieldsShape::Arbitrary { offsets: [Size::ZERO, b_offset].into(), @@ -138,7 +138,7 @@ impl<Cx: HasDataLayout> LayoutCalculator<Cx> { 'a, FieldIdx: Idx, VariantIdx: Idx, - F: Deref<Target = &'a LayoutS<FieldIdx, VariantIdx>> + fmt::Debug + Copy, + F: Deref<Target = &'a LayoutData<FieldIdx, VariantIdx>> + fmt::Debug + Copy, >( &self, fields: &IndexSlice<FieldIdx, F>, @@ -211,9 +211,9 @@ impl<Cx: HasDataLayout> LayoutCalculator<Cx> { pub fn layout_of_never_type<FieldIdx: Idx, VariantIdx: Idx>( &self, - ) -> LayoutS<FieldIdx, VariantIdx> { + ) -> LayoutData<FieldIdx, VariantIdx> { let dl = self.cx.data_layout(); - LayoutS { + LayoutData { variants: Variants::Single { index: VariantIdx::new(0) }, fields: FieldsShape::Primitive, abi: Abi::Uninhabited, @@ -229,7 +229,7 @@ impl<Cx: HasDataLayout> LayoutCalculator<Cx> { 'a, FieldIdx: Idx, VariantIdx: Idx, - F: Deref<Target = &'a LayoutS<FieldIdx, VariantIdx>> + fmt::Debug + Copy, + F: Deref<Target = &'a LayoutData<FieldIdx, VariantIdx>> + fmt::Debug + Copy, >( &self, repr: &ReprOptions, @@ -292,7 +292,7 @@ impl<Cx: HasDataLayout> LayoutCalculator<Cx> { 'a, FieldIdx: Idx, VariantIdx: Idx, - F: Deref<Target = &'a LayoutS<FieldIdx, VariantIdx>> + fmt::Debug + Copy, + F: Deref<Target = &'a LayoutData<FieldIdx, VariantIdx>> + fmt::Debug + Copy, >( &self, repr: &ReprOptions, @@ -384,7 +384,7 @@ impl<Cx: HasDataLayout> LayoutCalculator<Cx> { return Err(LayoutCalculatorError::EmptyUnion); }; - Ok(LayoutS { + Ok(LayoutData { variants: Variants::Single { index: only_variant_idx }, fields: FieldsShape::Union(union_field_count), abi, @@ -401,7 +401,7 @@ impl<Cx: HasDataLayout> LayoutCalculator<Cx> { 'a, FieldIdx: Idx, VariantIdx: Idx, - F: Deref<Target = &'a LayoutS<FieldIdx, VariantIdx>> + fmt::Debug + Copy, + F: Deref<Target = &'a LayoutData<FieldIdx, VariantIdx>> + fmt::Debug + Copy, >( &self, repr: &ReprOptions, @@ -501,7 +501,7 @@ impl<Cx: HasDataLayout> LayoutCalculator<Cx> { 'a, FieldIdx: Idx, VariantIdx: Idx, - F: Deref<Target = &'a LayoutS<FieldIdx, VariantIdx>> + fmt::Debug + Copy, + F: Deref<Target = &'a LayoutData<FieldIdx, VariantIdx>> + fmt::Debug + Copy, >( &self, repr: &ReprOptions, @@ -516,8 +516,8 @@ impl<Cx: HasDataLayout> LayoutCalculator<Cx> { // overall LayoutS. Store the overall LayoutS // and the variant LayoutSs here until then. struct TmpLayout<FieldIdx: Idx, VariantIdx: Idx> { - layout: LayoutS<FieldIdx, VariantIdx>, - variants: IndexVec<VariantIdx, LayoutS<FieldIdx, VariantIdx>>, + layout: LayoutData<FieldIdx, VariantIdx>, + variants: IndexVec<VariantIdx, LayoutData<FieldIdx, VariantIdx>>, } let dl = self.cx.data_layout(); @@ -649,7 +649,7 @@ impl<Cx: HasDataLayout> LayoutCalculator<Cx> { Abi::Aggregate { sized: true } }; - let layout = LayoutS { + let layout = LayoutData { variants: Variants::Multiple { tag: niche_scalar, tag_encoding: TagEncoding::Niche { @@ -681,7 +681,7 @@ impl<Cx: HasDataLayout> LayoutCalculator<Cx> { let discr_type = repr.discr_type(); let bits = Integer::from_attr(dl, discr_type).size().bits(); for (i, mut val) in discriminants { - if !repr.c() && variants[i].iter().any(|f| f.abi.is_uninhabited()) { + if !repr.c() && variants[i].iter().any(|f| f.is_uninhabited()) { continue; } if discr_type.is_signed() { @@ -958,7 +958,7 @@ impl<Cx: HasDataLayout> LayoutCalculator<Cx> { let largest_niche = Niche::from_scalar(dl, Size::ZERO, tag); - let tagged_layout = LayoutS { + let tagged_layout = LayoutData { variants: Variants::Multiple { tag, tag_encoding: TagEncoding::Direct, @@ -1013,7 +1013,7 @@ impl<Cx: HasDataLayout> LayoutCalculator<Cx> { 'a, FieldIdx: Idx, VariantIdx: Idx, - F: Deref<Target = &'a LayoutS<FieldIdx, VariantIdx>> + fmt::Debug + Copy, + F: Deref<Target = &'a LayoutData<FieldIdx, VariantIdx>> + fmt::Debug + Copy, >( &self, fields: &IndexSlice<FieldIdx, F>, @@ -1341,7 +1341,7 @@ impl<Cx: HasDataLayout> LayoutCalculator<Cx> { unadjusted_abi_align }; - Ok(LayoutS { + Ok(LayoutData { variants: Variants::Single { index: VariantIdx::new(0) }, fields: FieldsShape::Arbitrary { offsets, memory_index }, abi, @@ -1357,10 +1357,10 @@ impl<Cx: HasDataLayout> LayoutCalculator<Cx> { 'a, FieldIdx: Idx, VariantIdx: Idx, - F: Deref<Target = &'a LayoutS<FieldIdx, VariantIdx>> + fmt::Debug, + F: Deref<Target = &'a LayoutData<FieldIdx, VariantIdx>> + fmt::Debug, >( &self, - layout: &LayoutS<FieldIdx, VariantIdx>, + layout: &LayoutData<FieldIdx, VariantIdx>, fields: &IndexSlice<FieldIdx, F>, ) -> String { let dl = self.cx.data_layout(); diff --git a/compiler/rustc_abi/src/layout/ty.rs b/compiler/rustc_abi/src/layout/ty.rs index c6812c4d4c0..e029e1426b2 100644 --- a/compiler/rustc_abi/src/layout/ty.rs +++ b/compiler/rustc_abi/src/layout/ty.rs @@ -58,7 +58,7 @@ rustc_index::newtype_index! { } #[derive(Copy, Clone, PartialEq, Eq, Hash, HashStable_Generic)] #[rustc_pass_by_value] -pub struct Layout<'a>(pub Interned<'a, LayoutS<FieldIdx, VariantIdx>>); +pub struct Layout<'a>(pub Interned<'a, LayoutData<FieldIdx, VariantIdx>>); impl<'a> fmt::Debug for Layout<'a> { fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { @@ -68,8 +68,8 @@ impl<'a> fmt::Debug for Layout<'a> { } impl<'a> Deref for Layout<'a> { - type Target = &'a LayoutS<FieldIdx, VariantIdx>; - fn deref(&self) -> &&'a LayoutS<FieldIdx, VariantIdx> { + type Target = &'a LayoutData<FieldIdx, VariantIdx>; + fn deref(&self) -> &&'a LayoutData<FieldIdx, VariantIdx> { &self.0.0 } } @@ -142,8 +142,8 @@ impl<'a, Ty: fmt::Display> fmt::Debug for TyAndLayout<'a, Ty> { } impl<'a, Ty> Deref for TyAndLayout<'a, Ty> { - type Target = &'a LayoutS<FieldIdx, VariantIdx>; - fn deref(&self) -> &&'a LayoutS<FieldIdx, VariantIdx> { + type Target = &'a LayoutData<FieldIdx, VariantIdx>; + fn deref(&self) -> &&'a LayoutData<FieldIdx, VariantIdx> { &self.layout.0.0 } } diff --git a/compiler/rustc_abi/src/lib.rs b/compiler/rustc_abi/src/lib.rs index 8e90130da4c..41922aee648 100644 --- a/compiler/rustc_abi/src/lib.rs +++ b/compiler/rustc_abi/src/lib.rs @@ -1485,7 +1485,7 @@ pub enum Variants<FieldIdx: Idx, VariantIdx: Idx> { tag: Scalar, tag_encoding: TagEncoding<VariantIdx>, tag_field: usize, - variants: IndexVec<VariantIdx, LayoutS<FieldIdx, VariantIdx>>, + variants: IndexVec<VariantIdx, LayoutData<FieldIdx, VariantIdx>>, }, } @@ -1603,7 +1603,7 @@ impl Niche { // NOTE: This struct is generic over the FieldIdx and VariantIdx for rust-analyzer usage. #[derive(PartialEq, Eq, Hash, Clone)] #[cfg_attr(feature = "nightly", derive(HashStable_Generic))] -pub struct LayoutS<FieldIdx: Idx, VariantIdx: Idx> { +pub struct LayoutData<FieldIdx: Idx, VariantIdx: Idx> { /// Says where the fields are located within the layout. pub fields: FieldsShape<FieldIdx>, @@ -1643,7 +1643,7 @@ pub struct LayoutS<FieldIdx: Idx, VariantIdx: Idx> { pub unadjusted_abi_align: Align, } -impl<FieldIdx: Idx, VariantIdx: Idx> LayoutS<FieldIdx, VariantIdx> { +impl<FieldIdx: Idx, VariantIdx: Idx> LayoutData<FieldIdx, VariantIdx> { /// Returns `true` if this is an aggregate type (including a ScalarPair!) pub fn is_aggregate(&self) -> bool { match self.abi { @@ -1652,11 +1652,16 @@ impl<FieldIdx: Idx, VariantIdx: Idx> LayoutS<FieldIdx, VariantIdx> { } } + /// Returns `true` if this is an uninhabited type + pub fn is_uninhabited(&self) -> bool { + self.abi.is_uninhabited() + } + pub fn scalar<C: HasDataLayout>(cx: &C, scalar: Scalar) -> Self { let largest_niche = Niche::from_scalar(cx, Size::ZERO, scalar); let size = scalar.size(cx); let align = scalar.align(cx); - LayoutS { + LayoutData { variants: Variants::Single { index: VariantIdx::new(0) }, fields: FieldsShape::Primitive, abi: Abi::Scalar(scalar), @@ -1669,7 +1674,7 @@ impl<FieldIdx: Idx, VariantIdx: Idx> LayoutS<FieldIdx, VariantIdx> { } } -impl<FieldIdx: Idx, VariantIdx: Idx> fmt::Debug for LayoutS<FieldIdx, VariantIdx> +impl<FieldIdx: Idx, VariantIdx: Idx> fmt::Debug for LayoutData<FieldIdx, VariantIdx> where FieldsShape<FieldIdx>: fmt::Debug, Variants<FieldIdx, VariantIdx>: fmt::Debug, @@ -1678,7 +1683,7 @@ where // This is how `Layout` used to print before it become // `Interned<LayoutS>`. We print it like this to avoid having to update // expected output in a lot of tests. - let LayoutS { + let LayoutData { size, align, abi, @@ -1723,7 +1728,7 @@ pub struct PointeeInfo { pub safe: Option<PointerKind>, } -impl<FieldIdx: Idx, VariantIdx: Idx> LayoutS<FieldIdx, VariantIdx> { +impl<FieldIdx: Idx, VariantIdx: Idx> LayoutData<FieldIdx, VariantIdx> { /// Returns `true` if the layout corresponds to an unsized type. #[inline] pub fn is_unsized(&self) -> bool { diff --git a/compiler/rustc_ast/src/token.rs b/compiler/rustc_ast/src/token.rs index 1d6abbef06c..3b9edef0615 100644 --- a/compiler/rustc_ast/src/token.rs +++ b/compiler/rustc_ast/src/token.rs @@ -368,7 +368,7 @@ impl Clone for TokenKind { // a copy. This is faster than the `derive(Clone)` version which has a // separate path for every variant. match self { - Interpolated(nt) => Interpolated(nt.clone()), + Interpolated(nt) => Interpolated(Lrc::clone(nt)), _ => unsafe { std::ptr::read(self) }, } } diff --git a/compiler/rustc_ast_lowering/src/block.rs b/compiler/rustc_ast_lowering/src/block.rs index 9d2b5690c23..20d3ce65fac 100644 --- a/compiler/rustc_ast_lowering/src/block.rs +++ b/compiler/rustc_ast_lowering/src/block.rs @@ -10,17 +10,18 @@ impl<'a, 'hir> LoweringContext<'a, 'hir> { b: &Block, targeted_by_break: bool, ) -> &'hir hir::Block<'hir> { - self.arena.alloc(self.lower_block_noalloc(b, targeted_by_break)) + let hir_id = self.lower_node_id(b.id); + self.arena.alloc(self.lower_block_noalloc(hir_id, b, targeted_by_break)) } pub(super) fn lower_block_noalloc( &mut self, + hir_id: hir::HirId, b: &Block, targeted_by_break: bool, ) -> hir::Block<'hir> { let (stmts, expr) = self.lower_stmts(&b.stmts); let rules = self.lower_block_check_mode(&b.rules); - let hir_id = self.lower_node_id(b.id); hir::Block { hir_id, stmts, expr, rules, span: self.lower_span(b.span), targeted_by_break } } diff --git a/compiler/rustc_ast_lowering/src/delegation.rs b/compiler/rustc_ast_lowering/src/delegation.rs index 3b85f1737bd..70c94f4019a 100644 --- a/compiler/rustc_ast_lowering/src/delegation.rs +++ b/compiler/rustc_ast_lowering/src/delegation.rs @@ -259,10 +259,11 @@ impl<'hir> LoweringContext<'_, 'hir> { self_param_id: pat_node_id, }; self_resolver.visit_block(block); + // Target expr needs to lower `self` path. + this.ident_and_label_to_local_id.insert(pat_node_id, param.pat.hir_id.local_id); this.lower_target_expr(&block) } else { - let pat_hir_id = this.lower_node_id(pat_node_id); - this.generate_arg(pat_hir_id, span) + this.generate_arg(param.pat.hir_id, span) }; args.push(arg); } diff --git a/compiler/rustc_ast_lowering/src/expr.rs b/compiler/rustc_ast_lowering/src/expr.rs index a1a16d0ca26..b7cf2d252dc 100644 --- a/compiler/rustc_ast_lowering/src/expr.rs +++ b/compiler/rustc_ast_lowering/src/expr.rs @@ -3,6 +3,7 @@ use std::assert_matches::assert_matches; use rustc_ast::ptr::P as AstP; use rustc_ast::*; use rustc_data_structures::stack::ensure_sufficient_stack; +use rustc_data_structures::sync::Lrc; use rustc_hir as hir; use rustc_hir::HirId; use rustc_hir::def::{DefKind, Res}; @@ -70,8 +71,8 @@ impl<'hir> LoweringContext<'_, 'hir> { _ => (), } - let hir_id = self.lower_node_id(e.id); - self.lower_attrs(hir_id, &e.attrs); + let expr_hir_id = self.lower_node_id(e.id); + self.lower_attrs(expr_hir_id, &e.attrs); let kind = match &e.kind { ExprKind::Array(exprs) => hir::ExprKind::Array(self.lower_exprs(exprs)), @@ -143,7 +144,7 @@ impl<'hir> LoweringContext<'_, 'hir> { ExprKind::IncludedBytes(bytes) => { let lit = self.arena.alloc(respan( self.lower_span(e.span), - LitKind::ByteStr(bytes.clone(), StrStyle::Cooked), + LitKind::ByteStr(Lrc::clone(bytes), StrStyle::Cooked), )); hir::ExprKind::Lit(lit) } @@ -175,18 +176,25 @@ impl<'hir> LoweringContext<'_, 'hir> { ExprKind::If(cond, then, else_opt) => { self.lower_expr_if(cond, then, else_opt.as_deref()) } - ExprKind::While(cond, body, opt_label) => self.with_loop_scope(e.id, |this| { - let span = this.mark_span_with_reason(DesugaringKind::WhileLoop, e.span, None); - this.lower_expr_while_in_loop_scope(span, cond, body, *opt_label) - }), - ExprKind::Loop(body, opt_label, span) => self.with_loop_scope(e.id, |this| { - hir::ExprKind::Loop( - this.lower_block(body, false), - this.lower_label(*opt_label), - hir::LoopSource::Loop, - this.lower_span(*span), - ) - }), + ExprKind::While(cond, body, opt_label) => { + self.with_loop_scope(expr_hir_id, |this| { + let span = + this.mark_span_with_reason(DesugaringKind::WhileLoop, e.span, None); + let opt_label = this.lower_label(*opt_label, e.id, expr_hir_id); + this.lower_expr_while_in_loop_scope(span, cond, body, opt_label) + }) + } + ExprKind::Loop(body, opt_label, span) => { + self.with_loop_scope(expr_hir_id, |this| { + let opt_label = this.lower_label(*opt_label, e.id, expr_hir_id); + hir::ExprKind::Loop( + this.lower_block(body, false), + opt_label, + hir::LoopSource::Loop, + this.lower_span(*span), + ) + }) + } ExprKind::TryBlock(body) => self.lower_expr_try_block(body), ExprKind::Match(expr, arms, kind) => hir::ExprKind::Match( self.lower_expr(expr), @@ -212,7 +220,7 @@ impl<'hir> LoweringContext<'_, 'hir> { binder, *capture_clause, e.id, - hir_id, + expr_hir_id, *coroutine_kind, fn_decl, body, @@ -223,7 +231,7 @@ impl<'hir> LoweringContext<'_, 'hir> { binder, *capture_clause, e.id, - hir_id, + expr_hir_id, *constness, *movability, fn_decl, @@ -250,8 +258,16 @@ impl<'hir> LoweringContext<'_, 'hir> { ) } ExprKind::Block(blk, opt_label) => { - let opt_label = self.lower_label(*opt_label); - hir::ExprKind::Block(self.lower_block(blk, opt_label.is_some()), opt_label) + // Different from loops, label of block resolves to block id rather than + // expr node id. + let block_hir_id = self.lower_node_id(blk.id); + let opt_label = self.lower_label(*opt_label, blk.id, block_hir_id); + let hir_block = self.arena.alloc(self.lower_block_noalloc( + block_hir_id, + blk, + opt_label.is_some(), + )); + hir::ExprKind::Block(hir_block, opt_label) } ExprKind::Assign(el, er, span) => self.lower_expr_assign(el, er, *span, e.span), ExprKind::AssignOp(op, el, er) => hir::ExprKind::AssignOp( @@ -354,7 +370,7 @@ impl<'hir> LoweringContext<'_, 'hir> { ExprKind::MacCall(_) => panic!("{:?} shouldn't exist here", e.span), }; - hir::Expr { hir_id, kind, span: self.lower_span(e.span) } + hir::Expr { hir_id: expr_hir_id, kind, span: self.lower_span(e.span) } }) } @@ -504,7 +520,6 @@ impl<'hir> LoweringContext<'_, 'hir> { let if_expr = self.expr(span, if_kind); let block = self.block_expr(self.arena.alloc(if_expr)); let span = self.lower_span(span.with_hi(cond.span.hi())); - let opt_label = self.lower_label(opt_label); hir::ExprKind::Loop(block, opt_label, hir::LoopSource::While, span) } @@ -512,8 +527,9 @@ impl<'hir> LoweringContext<'_, 'hir> { /// `try { <stmts>; }` into `{ <stmts>; ::std::ops::Try::from_output(()) }` /// and save the block id to use it as a break target for desugaring of the `?` operator. fn lower_expr_try_block(&mut self, body: &Block) -> hir::ExprKind<'hir> { - self.with_catch_scope(body.id, |this| { - let mut block = this.lower_block_noalloc(body, true); + let body_hir_id = self.lower_node_id(body.id); + self.with_catch_scope(body_hir_id, |this| { + let mut block = this.lower_block_noalloc(body_hir_id, body, true); // Final expression of the block (if present) or `()` with span at the end of block let (try_span, tail_expr) = if let Some(expr) = block.expr.take() { @@ -521,7 +537,7 @@ impl<'hir> LoweringContext<'_, 'hir> { this.mark_span_with_reason( DesugaringKind::TryBlock, expr.span, - Some(this.allow_try_trait.clone()), + Some(Lrc::clone(&this.allow_try_trait)), ), expr, ) @@ -529,7 +545,7 @@ impl<'hir> LoweringContext<'_, 'hir> { let try_span = this.mark_span_with_reason( DesugaringKind::TryBlock, this.tcx.sess.source_map().end_point(body.span), - Some(this.allow_try_trait.clone()), + Some(Lrc::clone(&this.allow_try_trait)), ); (try_span, this.expr_unit(try_span)) @@ -638,7 +654,7 @@ impl<'hir> LoweringContext<'_, 'hir> { let unstable_span = self.mark_span_with_reason( DesugaringKind::Async, self.lower_span(span), - Some(self.allow_gen_future.clone()), + Some(Lrc::clone(&self.allow_gen_future)), ); let resume_ty = self.make_lang_item_qpath(hir::LangItem::ResumeTy, unstable_span, None); @@ -724,7 +740,7 @@ impl<'hir> LoweringContext<'_, 'hir> { let unstable_span = self.mark_span_with_reason( DesugaringKind::Async, span, - Some(self.allow_gen_future.clone()), + Some(Lrc::clone(&self.allow_gen_future)), ); self.lower_attrs(inner_hir_id, &[Attribute { kind: AttrKind::Normal(ptr::P(NormalAttr::from_ident(Ident::new( @@ -800,13 +816,13 @@ impl<'hir> LoweringContext<'_, 'hir> { let features = match await_kind { FutureKind::Future => None, - FutureKind::AsyncIterator => Some(self.allow_for_await.clone()), + FutureKind::AsyncIterator => Some(Lrc::clone(&self.allow_for_await)), }; let span = self.mark_span_with_reason(DesugaringKind::Await, await_kw_span, features); let gen_future_span = self.mark_span_with_reason( DesugaringKind::Await, full_span, - Some(self.allow_gen_future.clone()), + Some(Lrc::clone(&self.allow_gen_future)), ); let expr_hir_id = expr.hir_id; @@ -869,7 +885,7 @@ impl<'hir> LoweringContext<'_, 'hir> { let x_expr = self.expr_ident(gen_future_span, x_ident, x_pat_hid); let ready_field = self.single_pat_field(gen_future_span, x_pat); let ready_pat = self.pat_lang_item_variant(span, hir::LangItem::PollReady, ready_field); - let break_x = self.with_loop_scope(loop_node_id, move |this| { + let break_x = self.with_loop_scope(loop_hir_id, move |this| { let expr_break = hir::ExprKind::Break(this.lower_loop_destination(None), Some(x_expr)); this.arena.alloc(this.expr(gen_future_span, expr_break)) @@ -1101,8 +1117,7 @@ impl<'hir> LoweringContext<'_, 'hir> { hir::CoroutineSource::Closure, ); - let hir_id = this.lower_node_id(coroutine_kind.closure_id()); - this.maybe_forward_track_caller(body.span, closure_hir_id, hir_id); + this.maybe_forward_track_caller(body.span, closure_hir_id, expr.hir_id); (parameters, expr) }); @@ -1465,8 +1480,16 @@ impl<'hir> LoweringContext<'_, 'hir> { ) } - fn lower_label(&self, opt_label: Option<Label>) -> Option<Label> { + // Record labelled expr's HirId so that we can retrieve it in `lower_jump_destination` without + // lowering node id again. + fn lower_label( + &mut self, + opt_label: Option<Label>, + dest_id: NodeId, + dest_hir_id: hir::HirId, + ) -> Option<Label> { let label = opt_label?; + self.ident_and_label_to_local_id.insert(dest_id, dest_hir_id.local_id); Some(Label { ident: self.lower_ident(label.ident) }) } @@ -1474,17 +1497,20 @@ impl<'hir> LoweringContext<'_, 'hir> { let target_id = match destination { Some((id, _)) => { if let Some(loop_id) = self.resolver.get_label_res(id) { - Ok(self.lower_node_id(loop_id)) + let local_id = self.ident_and_label_to_local_id[&loop_id]; + let loop_hir_id = HirId { owner: self.current_hir_id_owner, local_id }; + Ok(loop_hir_id) } else { Err(hir::LoopIdError::UnresolvedLabel) } } - None => self - .loop_scope - .map(|id| Ok(self.lower_node_id(id))) - .unwrap_or(Err(hir::LoopIdError::OutsideLoopScope)), + None => { + self.loop_scope.map(|id| Ok(id)).unwrap_or(Err(hir::LoopIdError::OutsideLoopScope)) + } }; - let label = self.lower_label(destination.map(|(_, label)| label)); + let label = destination + .map(|(_, label)| label) + .map(|label| Label { ident: self.lower_ident(label.ident) }); hir::Destination { label, target_id } } @@ -1499,14 +1525,14 @@ impl<'hir> LoweringContext<'_, 'hir> { } } - fn with_catch_scope<T>(&mut self, catch_id: NodeId, f: impl FnOnce(&mut Self) -> T) -> T { + fn with_catch_scope<T>(&mut self, catch_id: hir::HirId, f: impl FnOnce(&mut Self) -> T) -> T { let old_scope = self.catch_scope.replace(catch_id); let result = f(self); self.catch_scope = old_scope; result } - fn with_loop_scope<T>(&mut self, loop_id: NodeId, f: impl FnOnce(&mut Self) -> T) -> T { + fn with_loop_scope<T>(&mut self, loop_id: hir::HirId, f: impl FnOnce(&mut Self) -> T) -> T { // We're no longer in the base loop's condition; we're in another loop. let was_in_loop_condition = self.is_in_loop_condition; self.is_in_loop_condition = false; @@ -1658,9 +1684,13 @@ impl<'hir> LoweringContext<'_, 'hir> { let head_span = self.mark_span_with_reason(DesugaringKind::ForLoop, head.span, None); let pat_span = self.mark_span_with_reason(DesugaringKind::ForLoop, pat.span, None); + let loop_hir_id = self.lower_node_id(e.id); + let label = self.lower_label(opt_label, e.id, loop_hir_id); + // `None => break` let none_arm = { - let break_expr = self.with_loop_scope(e.id, |this| this.expr_break_alloc(for_span)); + let break_expr = + self.with_loop_scope(loop_hir_id, |this| this.expr_break_alloc(for_span)); let pat = self.pat_none(for_span); self.arm(pat, break_expr) }; @@ -1668,7 +1698,8 @@ impl<'hir> LoweringContext<'_, 'hir> { // Some(<pat>) => <body>, let some_arm = { let some_pat = self.pat_some(pat_span, pat); - let body_block = self.with_loop_scope(e.id, |this| this.lower_block(body, false)); + let body_block = + self.with_loop_scope(loop_hir_id, |this| this.lower_block(body, false)); let body_expr = self.arena.alloc(self.expr_block(body_block)); self.arm(some_pat, body_expr) }; @@ -1722,12 +1753,11 @@ impl<'hir> LoweringContext<'_, 'hir> { // `[opt_ident]: loop { ... }` let kind = hir::ExprKind::Loop( loop_block, - self.lower_label(opt_label), + label, hir::LoopSource::ForLoop, self.lower_span(for_span.with_hi(head.span.hi())), ); - let loop_expr = - self.arena.alloc(hir::Expr { hir_id: self.lower_node_id(e.id), kind, span: for_span }); + let loop_expr = self.arena.alloc(hir::Expr { hir_id: loop_hir_id, kind, span: for_span }); // `mut iter => { ... }` let iter_arm = self.arm(iter_pat, loop_expr); @@ -1812,13 +1842,13 @@ impl<'hir> LoweringContext<'_, 'hir> { let unstable_span = self.mark_span_with_reason( DesugaringKind::QuestionMark, span, - Some(self.allow_try_trait.clone()), + Some(Lrc::clone(&self.allow_try_trait)), ); let try_span = self.tcx.sess.source_map().end_point(span); let try_span = self.mark_span_with_reason( DesugaringKind::QuestionMark, try_span, - Some(self.allow_try_trait.clone()), + Some(Lrc::clone(&self.allow_try_trait)), ); // `Try::branch(<expr>)` @@ -1867,8 +1897,8 @@ impl<'hir> LoweringContext<'_, 'hir> { self.arena.alloc(residual_expr), unstable_span, ); - let ret_expr = if let Some(catch_node) = self.catch_scope { - let target_id = Ok(self.lower_node_id(catch_node)); + let ret_expr = if let Some(catch_id) = self.catch_scope { + let target_id = Ok(catch_id); self.arena.alloc(self.expr( try_span, hir::ExprKind::Break( @@ -1912,7 +1942,7 @@ impl<'hir> LoweringContext<'_, 'hir> { let unstable_span = self.mark_span_with_reason( DesugaringKind::YeetExpr, span, - Some(self.allow_try_trait.clone()), + Some(Lrc::clone(&self.allow_try_trait)), ); let from_yeet_expr = self.wrap_in_try_constructor( @@ -1922,8 +1952,8 @@ impl<'hir> LoweringContext<'_, 'hir> { yeeted_span, ); - if let Some(catch_node) = self.catch_scope { - let target_id = Ok(self.lower_node_id(catch_node)); + if let Some(catch_id) = self.catch_scope { + let target_id = Ok(catch_id); hir::ExprKind::Break(hir::Destination { label: None, target_id }, Some(from_yeet_expr)) } else { hir::ExprKind::Ret(Some(from_yeet_expr)) diff --git a/compiler/rustc_ast_lowering/src/item.rs b/compiler/rustc_ast_lowering/src/item.rs index 97fa90d340e..d7245607501 100644 --- a/compiler/rustc_ast_lowering/src/item.rs +++ b/compiler/rustc_ast_lowering/src/item.rs @@ -154,7 +154,7 @@ impl<'hir> LoweringContext<'_, 'hir> { fn lower_item(&mut self, i: &Item) -> &'hir hir::Item<'hir> { let mut ident = i.ident; let vis_span = self.lower_span(i.vis.span); - let hir_id = self.lower_node_id(i.id); + let hir_id = hir::HirId::make_owner(self.current_hir_id_owner.def_id); let attrs = self.lower_attrs(hir_id, &i.attrs); let kind = self.lower_item_kind(i.span, i.id, hir_id, &mut ident, attrs, vis_span, &i.kind); let item = hir::Item { @@ -604,7 +604,7 @@ impl<'hir> LoweringContext<'_, 'hir> { } fn lower_foreign_item(&mut self, i: &ForeignItem) -> &'hir hir::ForeignItem<'hir> { - let hir_id = self.lower_node_id(i.id); + let hir_id = hir::HirId::make_owner(self.current_hir_id_owner.def_id); let owner_id = hir_id.expect_owner(); self.lower_attrs(hir_id, &i.attrs); let item = hir::ForeignItem { @@ -728,7 +728,7 @@ impl<'hir> LoweringContext<'_, 'hir> { } fn lower_trait_item(&mut self, i: &AssocItem) -> &'hir hir::TraitItem<'hir> { - let hir_id = self.lower_node_id(i.id); + let hir_id = hir::HirId::make_owner(self.current_hir_id_owner.def_id); self.lower_attrs(hir_id, &i.attrs); let trait_item_def_id = hir_id.expect_owner(); @@ -858,7 +858,7 @@ impl<'hir> LoweringContext<'_, 'hir> { // Since `default impl` is not yet implemented, this is always true in impls. let has_value = true; let (defaultness, _) = self.lower_defaultness(i.kind.defaultness(), has_value); - let hir_id = self.lower_node_id(i.id); + let hir_id = hir::HirId::make_owner(self.current_hir_id_owner.def_id); self.lower_attrs(hir_id, &i.attrs); let (generics, kind) = match &i.kind { @@ -1086,7 +1086,7 @@ impl<'hir> LoweringContext<'_, 'hir> { ); // FIXME(async_fn_track_caller): Can this be moved above? - let hir_id = this.lower_node_id(coroutine_kind.closure_id()); + let hir_id = expr.hir_id; this.maybe_forward_track_caller(body.span, fn_id, hir_id); (parameters, expr) diff --git a/compiler/rustc_ast_lowering/src/lib.rs b/compiler/rustc_ast_lowering/src/lib.rs index 34b8137aea8..e1ee3d0af49 100644 --- a/compiler/rustc_ast_lowering/src/lib.rs +++ b/compiler/rustc_ast_lowering/src/lib.rs @@ -40,23 +40,19 @@ #![warn(unreachable_pub)] // tidy-alphabetical-end -use std::collections::hash_map::Entry; - use rustc_ast::node_id::NodeMap; use rustc_ast::ptr::P; use rustc_ast::{self as ast, *}; use rustc_data_structures::captures::Captures; use rustc_data_structures::fingerprint::Fingerprint; -use rustc_data_structures::fx::FxIndexSet; use rustc_data_structures::sorted_map::SortedMap; use rustc_data_structures::stable_hasher::{HashStable, StableHasher}; use rustc_data_structures::sync::Lrc; use rustc_errors::{DiagArgFromDisplay, DiagCtxtHandle, StashKey}; use rustc_hir::def::{DefKind, LifetimeRes, Namespace, PartialRes, PerNS, Res}; -use rustc_hir::def_id::{CRATE_DEF_ID, LOCAL_CRATE, LocalDefId, LocalDefIdMap}; +use rustc_hir::def_id::{CRATE_DEF_ID, LOCAL_CRATE, LocalDefId}; use rustc_hir::{ - self as hir, ConstArg, GenericArg, HirId, ItemLocalMap, LangItem, MissingLifetimeKind, - ParamName, TraitCandidate, + self as hir, ConstArg, GenericArg, HirId, ItemLocalMap, LangItem, ParamName, TraitCandidate, }; use rustc_index::{Idx, IndexSlice, IndexVec}; use rustc_macros::extension; @@ -85,7 +81,6 @@ mod expr; mod format; mod index; mod item; -mod lifetime_collector; mod pat; mod path; @@ -115,8 +110,8 @@ struct LoweringContext<'a, 'hir> { /// outside of an `async fn`. current_item: Option<Span>, - catch_scope: Option<NodeId>, - loop_scope: Option<NodeId>, + catch_scope: Option<HirId>, + loop_scope: Option<HirId>, is_in_loop_condition: bool, is_in_trait_impl: bool, is_in_dyn_type: bool, @@ -140,7 +135,10 @@ struct LoweringContext<'a, 'hir> { impl_trait_defs: Vec<hir::GenericParam<'hir>>, impl_trait_bounds: Vec<hir::WherePredicate<'hir>>, - /// NodeIds that are lowered inside the current HIR owner. + /// NodeIds of pattern identifiers and labelled nodes that are lowered inside the current HIR owner. + ident_and_label_to_local_id: NodeMap<hir::ItemLocalId>, + /// NodeIds that are lowered inside the current HIR owner. Only used for duplicate lowering check. + #[cfg(debug_assertions)] node_id_to_local_id: NodeMap<hir::ItemLocalId>, allow_try_trait: Lrc<[Symbol]>, @@ -148,12 +146,6 @@ struct LoweringContext<'a, 'hir> { allow_async_iterator: Lrc<[Symbol]>, allow_for_await: Lrc<[Symbol]>, allow_async_fn_traits: Lrc<[Symbol]>, - - /// Mapping from generics `def_id`s to TAIT generics `def_id`s. - /// For each captured lifetime (e.g., 'a), we create a new lifetime parameter that is a generic - /// defined on the TAIT, so we have type Foo<'a1> = ... and we establish a mapping in this - /// field from the original parameter 'a to the new parameter 'a1. - generics_def_id_map: Vec<LocalDefIdMap<LocalDefId>>, } impl<'a, 'hir> LoweringContext<'a, 'hir> { @@ -171,6 +163,8 @@ impl<'a, 'hir> LoweringContext<'a, 'hir> { current_hir_id_owner: hir::CRATE_OWNER_ID, current_def_id_parent: CRATE_DEF_ID, item_local_id_counter: hir::ItemLocalId::ZERO, + ident_and_label_to_local_id: Default::default(), + #[cfg(debug_assertions)] node_id_to_local_id: Default::default(), trait_map: Default::default(), @@ -196,7 +190,6 @@ impl<'a, 'hir> LoweringContext<'a, 'hir> { // FIXME(gen_blocks): how does `closure_track_caller`/`async_fn_track_caller` // interact with `gen`/`async gen` blocks allow_async_iterator: [sym::gen_future, sym::async_iterator].into(), - generics_def_id_map: Default::default(), } } @@ -525,54 +518,14 @@ impl<'a, 'hir> LoweringContext<'a, 'hir> { /// Given the id of some node in the AST, finds the `LocalDefId` associated with it by the name /// resolver (if any). - fn orig_opt_local_def_id(&self, node: NodeId) -> Option<LocalDefId> { - self.resolver.node_id_to_def_id.get(&node).copied() - } - - /// Given the id of some node in the AST, finds the `LocalDefId` associated with it by the name - /// resolver (if any), after applying any remapping from `get_remapped_def_id`. - /// - /// For example, in a function like `fn foo<'a>(x: &'a u32)`, - /// invoking with the id from the `ast::Lifetime` node found inside - /// the `&'a u32` type would return the `LocalDefId` of the - /// `'a` parameter declared on `foo`. - /// - /// This function also applies remapping from `get_remapped_def_id`. - /// These are used when synthesizing opaque types from `-> impl Trait` return types and so forth. - /// For example, in a function like `fn foo<'a>() -> impl Debug + 'a`, - /// we would create an opaque type `type FooReturn<'a1> = impl Debug + 'a1`. - /// When lowering the `Debug + 'a` bounds, we add a remapping to map `'a` to `'a1`. fn opt_local_def_id(&self, node: NodeId) -> Option<LocalDefId> { - self.orig_opt_local_def_id(node).map(|local_def_id| self.get_remapped_def_id(local_def_id)) + self.resolver.node_id_to_def_id.get(&node).copied() } fn local_def_id(&self, node: NodeId) -> LocalDefId { self.opt_local_def_id(node).unwrap_or_else(|| panic!("no entry for node id: `{node:?}`")) } - /// Get the previously recorded `to` local def id given the `from` local def id, obtained using - /// `generics_def_id_map` field. - fn get_remapped_def_id(&self, local_def_id: LocalDefId) -> LocalDefId { - // `generics_def_id_map` is a stack of mappings. As we go deeper in impl traits nesting we - // push new mappings, so we first need to get the latest (innermost) mappings, hence `iter().rev()`. - // - // Consider: - // - // `fn test<'a, 'b>() -> impl Trait<&'a u8, Ty = impl Sized + 'b> {}` - // - // We would end with a generics_def_id_map like: - // - // `[[fn#'b -> impl_trait#'b], [fn#'b -> impl_sized#'b]]` - // - // for the opaque type generated on `impl Sized + 'b`, we want the result to be: impl_sized#'b. - // So, if we were trying to find first from the start (outermost) would give the wrong result, impl_trait#'b. - self.generics_def_id_map - .iter() - .rev() - .find_map(|map| map.get(&local_def_id).copied()) - .unwrap_or(local_def_id) - } - /// Freshen the `LoweringContext` and ready it to lower a nested item. /// The lowered item is registered into `self.children`. /// @@ -588,7 +541,11 @@ impl<'a, 'hir> LoweringContext<'a, 'hir> { let current_attrs = std::mem::take(&mut self.attrs); let current_bodies = std::mem::take(&mut self.bodies); - let current_node_ids = std::mem::take(&mut self.node_id_to_local_id); + let current_ident_and_label_to_local_id = + std::mem::take(&mut self.ident_and_label_to_local_id); + + #[cfg(debug_assertions)] + let current_node_id_to_local_id = std::mem::take(&mut self.node_id_to_local_id); let current_trait_map = std::mem::take(&mut self.trait_map); let current_owner = std::mem::replace(&mut self.current_hir_id_owner, hir::OwnerId { def_id }); @@ -602,8 +559,11 @@ impl<'a, 'hir> LoweringContext<'a, 'hir> { // and the caller to refer to some of the subdefinitions' nodes' `LocalDefId`s. // Always allocate the first `HirId` for the owner itself. - let _old = self.node_id_to_local_id.insert(owner, hir::ItemLocalId::ZERO); - debug_assert_eq!(_old, None); + #[cfg(debug_assertions)] + { + let _old = self.node_id_to_local_id.insert(owner, hir::ItemLocalId::ZERO); + debug_assert_eq!(_old, None); + } let item = self.with_def_id_parent(def_id, f); debug_assert_eq!(def_id, item.def_id().def_id); @@ -614,7 +574,12 @@ impl<'a, 'hir> LoweringContext<'a, 'hir> { self.attrs = current_attrs; self.bodies = current_bodies; - self.node_id_to_local_id = current_node_ids; + self.ident_and_label_to_local_id = current_ident_and_label_to_local_id; + + #[cfg(debug_assertions)] + { + self.node_id_to_local_id = current_node_id_to_local_id; + } self.trait_map = current_trait_map; self.current_hir_id_owner = current_owner; self.item_local_id_counter = current_local_counter; @@ -632,27 +597,6 @@ impl<'a, 'hir> LoweringContext<'a, 'hir> { result } - /// Installs the remapping `remap` in scope while `f` is being executed. - /// This causes references to the `LocalDefId` keys to be changed to - /// refer to the values instead. - /// - /// The remapping is used when one piece of AST expands to multiple - /// pieces of HIR. For example, the function `fn foo<'a>(...) -> impl Debug + 'a`, - /// expands to both a function definition (`foo`) and a TAIT for the return value, - /// both of which have a lifetime parameter `'a`. The remapping allows us to - /// rewrite the `'a` in the return value to refer to the - /// `'a` declared on the TAIT, instead of the function. - fn with_remapping<R>( - &mut self, - remap: LocalDefIdMap<LocalDefId>, - f: impl FnOnce(&mut Self) -> R, - ) -> R { - self.generics_def_id_map.push(remap); - let res = f(self); - self.generics_def_id_map.pop(); - res - } - fn make_owner_info(&mut self, node: hir::OwnerNode<'hir>) -> &'hir hir::OwnerInfo<'hir> { let attrs = std::mem::take(&mut self.attrs); let mut bodies = std::mem::take(&mut self.bodies); @@ -680,39 +624,37 @@ impl<'a, 'hir> LoweringContext<'a, 'hir> { self.arena.alloc(hir::OwnerInfo { nodes, parenting, attrs, trait_map }) } - /// This method allocates a new `HirId` for the given `NodeId` and stores it in - /// the `LoweringContext`'s `NodeId => HirId` map. + /// This method allocates a new `HirId` for the given `NodeId`. /// Take care not to call this method if the resulting `HirId` is then not /// actually used in the HIR, as that would trigger an assertion in the /// `HirIdValidator` later on, which makes sure that all `NodeId`s got mapped - /// properly. Calling the method twice with the same `NodeId` is fine though. + /// properly. Calling the method twice with the same `NodeId` is also forbidden. #[instrument(level = "debug", skip(self), ret)] fn lower_node_id(&mut self, ast_node_id: NodeId) -> HirId { assert_ne!(ast_node_id, DUMMY_NODE_ID); - match self.node_id_to_local_id.entry(ast_node_id) { - Entry::Occupied(o) => HirId { owner: self.current_hir_id_owner, local_id: *o.get() }, - Entry::Vacant(v) => { - // Generate a new `HirId`. - let owner = self.current_hir_id_owner; - let local_id = self.item_local_id_counter; - let hir_id = HirId { owner, local_id }; - - v.insert(local_id); - self.item_local_id_counter.increment_by(1); + let owner = self.current_hir_id_owner; + let local_id = self.item_local_id_counter; + assert_ne!(local_id, hir::ItemLocalId::ZERO); + self.item_local_id_counter.increment_by(1); + let hir_id = HirId { owner, local_id }; - assert_ne!(local_id, hir::ItemLocalId::ZERO); - if let Some(def_id) = self.opt_local_def_id(ast_node_id) { - self.children.push((def_id, hir::MaybeOwner::NonOwner(hir_id))); - } + if let Some(def_id) = self.opt_local_def_id(ast_node_id) { + self.children.push((def_id, hir::MaybeOwner::NonOwner(hir_id))); + } - if let Some(traits) = self.resolver.trait_map.remove(&ast_node_id) { - self.trait_map.insert(hir_id.local_id, traits.into_boxed_slice()); - } + if let Some(traits) = self.resolver.trait_map.remove(&ast_node_id) { + self.trait_map.insert(hir_id.local_id, traits.into_boxed_slice()); + } - hir_id - } + // Check whether the same `NodeId` is lowered more than once. + #[cfg(debug_assertions)] + { + let old = self.node_id_to_local_id.insert(ast_node_id, local_id); + assert_eq!(old, None); } + + hir_id } /// Generate a new `HirId` without a backing `NodeId`. @@ -729,7 +671,7 @@ impl<'a, 'hir> LoweringContext<'a, 'hir> { fn lower_res(&mut self, res: Res<NodeId>) -> Res { let res: Result<Res, ()> = res.apply_id(|id| { let owner = self.current_hir_id_owner; - let local_id = self.node_id_to_local_id.get(&id).copied().ok_or(())?; + let local_id = self.ident_and_label_to_local_id.get(&id).copied().ok_or(())?; Ok(HirId { owner, local_id }) }); trace!(?res); @@ -1486,27 +1428,6 @@ impl<'a, 'hir> LoweringContext<'a, 'hir> { // frequently opened issues show. let opaque_ty_span = self.mark_span_with_reason(DesugaringKind::OpaqueTy, span, None); - // Whether this opaque always captures lifetimes in scope. - // Right now, this is all RPITIT and TAITs, and when `lifetime_capture_rules_2024` - // is enabled. We don't check the span of the edition, since this is done - // on a per-opaque basis to account for nested opaques. - let always_capture_in_scope = match origin { - _ if self.tcx.features().lifetime_capture_rules_2024() => true, - hir::OpaqueTyOrigin::TyAlias { .. } => true, - hir::OpaqueTyOrigin::FnReturn { in_trait_or_impl, .. } => in_trait_or_impl.is_some(), - hir::OpaqueTyOrigin::AsyncFn { .. } => { - unreachable!("should be using `lower_coroutine_fn_ret_ty`") - } - }; - let captured_lifetimes_to_duplicate = lifetime_collector::lifetimes_for_opaque( - self.resolver, - always_capture_in_scope, - opaque_ty_node_id, - bounds, - span, - ); - debug!(?captured_lifetimes_to_duplicate); - // Feature gate for RPITIT + use<..> match origin { rustc_hir::OpaqueTyOrigin::FnReturn { in_trait_or_impl: Some(_), .. } => { @@ -1529,22 +1450,15 @@ impl<'a, 'hir> LoweringContext<'a, 'hir> { _ => {} } - self.lower_opaque_inner( - opaque_ty_node_id, - origin, - captured_lifetimes_to_duplicate, - span, - opaque_ty_span, - |this| this.lower_param_bounds(bounds, itctx), - ) + self.lower_opaque_inner(opaque_ty_node_id, origin, opaque_ty_span, |this| { + this.lower_param_bounds(bounds, itctx) + }) } fn lower_opaque_inner( &mut self, opaque_ty_node_id: NodeId, origin: hir::OpaqueTyOrigin, - captured_lifetimes_to_duplicate: FxIndexSet<Lifetime>, - span: Span, opaque_ty_span: Span, lower_item_bounds: impl FnOnce(&mut Self) -> &'hir [hir::GenericBound<'hir>], ) -> hir::TyKind<'hir> { @@ -1552,145 +1466,19 @@ impl<'a, 'hir> LoweringContext<'a, 'hir> { let opaque_ty_hir_id = self.lower_node_id(opaque_ty_node_id); debug!(?opaque_ty_def_id, ?opaque_ty_hir_id); - // Map from captured (old) lifetime to synthetic (new) lifetime. - // Used to resolve lifetimes in the bounds of the opaque. - let mut captured_to_synthesized_mapping = LocalDefIdMap::default(); - // List of (early-bound) synthetic lifetimes that are owned by the opaque. - // This is used to create the `hir::Generics` owned by the opaque. - let mut synthesized_lifetime_definitions = vec![]; - // Pairs of lifetime arg (that resolves to the captured lifetime) - // and the def-id of the (early-bound) synthetic lifetime definition. - // This is used both to create generics for the `TyKind::OpaqueDef` that - // we return, and also as a captured lifetime mapping for RPITITs. - let mut synthesized_lifetime_args = vec![]; - - for lifetime in captured_lifetimes_to_duplicate { - let res = self.resolver.get_lifetime_res(lifetime.id).unwrap_or(LifetimeRes::Error); - let (old_def_id, missing_kind) = match res { - LifetimeRes::Param { param: old_def_id, binder: _ } => (old_def_id, None), - - LifetimeRes::Fresh { param, kind, .. } => { - debug_assert_eq!(lifetime.ident.name, kw::UnderscoreLifetime); - if let Some(old_def_id) = self.orig_opt_local_def_id(param) { - (old_def_id, Some(kind)) - } else { - self.dcx() - .span_delayed_bug(lifetime.ident.span, "no def-id for fresh lifetime"); - continue; - } - } - - // Opaques do not capture `'static` - LifetimeRes::Static { .. } | LifetimeRes::Error => { - continue; - } - - res => { - let bug_msg = format!( - "Unexpected lifetime resolution {:?} for {:?} at {:?}", - res, lifetime.ident, lifetime.ident.span - ); - span_bug!(lifetime.ident.span, "{}", bug_msg); - } - }; - - if captured_to_synthesized_mapping.get(&old_def_id).is_none() { - // Create a new lifetime parameter local to the opaque. - let duplicated_lifetime_node_id = self.next_node_id(); - let duplicated_lifetime_def_id = self.create_def( - opaque_ty_def_id, - duplicated_lifetime_node_id, - lifetime.ident.name, - DefKind::LifetimeParam, - self.lower_span(lifetime.ident.span), - ); - captured_to_synthesized_mapping.insert(old_def_id, duplicated_lifetime_def_id); - // FIXME: Instead of doing this, we could move this whole loop - // into the `with_hir_id_owner`, then just directly construct - // the `hir::GenericParam` here. - synthesized_lifetime_definitions.push(( - duplicated_lifetime_node_id, - duplicated_lifetime_def_id, - self.lower_ident(lifetime.ident), - missing_kind, - )); - - // Now make an arg that we can use for the generic params of the opaque tykind. - let id = self.next_node_id(); - let lifetime_arg = self.new_named_lifetime_with_res(id, lifetime.ident, res); - let duplicated_lifetime_def_id = self.local_def_id(duplicated_lifetime_node_id); - synthesized_lifetime_args.push((lifetime_arg, duplicated_lifetime_def_id)) - } - } - let opaque_ty_def = self.with_def_id_parent(opaque_ty_def_id, |this| { - // Install the remapping from old to new (if any). This makes sure that - // any lifetimes that would have resolved to the def-id of captured - // lifetimes are remapped to the new *synthetic* lifetimes of the opaque. - let bounds = this - .with_remapping(captured_to_synthesized_mapping, |this| lower_item_bounds(this)); - - let generic_params = - this.arena.alloc_from_iter(synthesized_lifetime_definitions.iter().map( - |&(new_node_id, new_def_id, ident, missing_kind)| { - let hir_id = this.lower_node_id(new_node_id); - let (name, kind) = if ident.name == kw::UnderscoreLifetime { - ( - hir::ParamName::Fresh, - hir::LifetimeParamKind::Elided( - missing_kind.unwrap_or(MissingLifetimeKind::Underscore), - ), - ) - } else { - (hir::ParamName::Plain(ident), hir::LifetimeParamKind::Explicit) - }; - - hir::GenericParam { - hir_id, - def_id: new_def_id, - name, - span: ident.span, - pure_wrt_drop: false, - kind: hir::GenericParamKind::Lifetime { kind }, - colon_span: None, - source: hir::GenericParamSource::Generics, - } - }, - )); - debug!("lower_async_fn_ret_ty: generic_params={:#?}", generic_params); - - let lifetime_mapping = self.arena.alloc_slice(&synthesized_lifetime_args); - - trace!("registering opaque type with id {:#?}", opaque_ty_def_id); + let bounds = lower_item_bounds(this); let opaque_ty_def = hir::OpaqueTy { hir_id: opaque_ty_hir_id, def_id: opaque_ty_def_id, - generics: this.arena.alloc(hir::Generics { - params: generic_params, - predicates: &[], - has_where_clause_predicates: false, - where_clause_span: this.lower_span(span), - span: this.lower_span(span), - }), bounds, origin, - lifetime_mapping, span: this.lower_span(opaque_ty_span), }; this.arena.alloc(opaque_ty_def) }); - let generic_args = self.arena.alloc_from_iter( - synthesized_lifetime_args - .iter() - .map(|(lifetime, _)| hir::GenericArg::Lifetime(*lifetime)), - ); - - // Create the `Foo<...>` reference itself. Note that the `type - // Foo = impl Trait` is, internally, created as a child of the - // async fn, so the *type parameters* are inherited. It's - // only the lifetime parameters that we must supply. - hir::TyKind::OpaqueDef(opaque_ty_def, generic_args) + hir::TyKind::OpaqueDef(opaque_ty_def) } fn lower_precise_capturing_args( @@ -1865,20 +1653,13 @@ impl<'a, 'hir> LoweringContext<'a, 'hir> { CoroutineKind::Async { return_impl_trait_id, .. } => (return_impl_trait_id, None), CoroutineKind::Gen { return_impl_trait_id, .. } => (return_impl_trait_id, None), CoroutineKind::AsyncGen { return_impl_trait_id, .. } => { - (return_impl_trait_id, Some(self.allow_async_iterator.clone())) + (return_impl_trait_id, Some(Lrc::clone(&self.allow_async_iterator))) } }; let opaque_ty_span = self.mark_span_with_reason(DesugaringKind::Async, span, allowed_features); - let captured_lifetimes = self - .resolver - .extra_lifetime_params(opaque_ty_node_id) - .into_iter() - .map(|(ident, id, _)| Lifetime { id, ident }) - .collect(); - let in_trait_or_impl = match fn_kind { FnDeclKind::Trait => Some(hir::RpitContext::Trait), FnDeclKind::Impl => Some(hir::RpitContext::TraitImpl), @@ -1889,8 +1670,6 @@ impl<'a, 'hir> LoweringContext<'a, 'hir> { let opaque_ty_ref = self.lower_opaque_inner( opaque_ty_node_id, hir::OpaqueTyOrigin::AsyncFn { parent: fn_def_id, in_trait_or_impl }, - captured_lifetimes, - span, opaque_ty_span, |this| { let bound = this.lower_coroutine_fn_output_type_to_bound( @@ -1987,10 +1766,7 @@ impl<'a, 'hir> LoweringContext<'a, 'hir> { res: LifetimeRes, ) -> &'hir hir::Lifetime { let res = match res { - LifetimeRes::Param { param, .. } => { - let param = self.get_remapped_def_id(param); - hir::LifetimeName::Param(param) - } + LifetimeRes::Param { param, .. } => hir::LifetimeName::Param(param), LifetimeRes::Fresh { param, .. } => { let param = self.local_def_id(param); hir::LifetimeName::Param(param) diff --git a/compiler/rustc_ast_lowering/src/lifetime_collector.rs b/compiler/rustc_ast_lowering/src/lifetime_collector.rs deleted file mode 100644 index 8d47c856bdd..00000000000 --- a/compiler/rustc_ast_lowering/src/lifetime_collector.rs +++ /dev/null @@ -1,151 +0,0 @@ -use rustc_ast::visit::{self, BoundKind, LifetimeCtxt, Visitor}; -use rustc_ast::{ - GenericBound, GenericBounds, Lifetime, NodeId, PathSegment, PolyTraitRef, Ty, TyKind, -}; -use rustc_data_structures::fx::FxIndexSet; -use rustc_hir::def::{DefKind, LifetimeRes, Res}; -use rustc_middle::span_bug; -use rustc_middle::ty::ResolverAstLowering; -use rustc_span::Span; -use rustc_span::symbol::{Ident, kw}; - -use super::ResolverAstLoweringExt; - -struct LifetimeCollectVisitor<'ast> { - resolver: &'ast mut ResolverAstLowering, - always_capture_in_scope: bool, - current_binders: Vec<NodeId>, - collected_lifetimes: FxIndexSet<Lifetime>, -} - -impl<'ast> LifetimeCollectVisitor<'ast> { - fn new(resolver: &'ast mut ResolverAstLowering, always_capture_in_scope: bool) -> Self { - Self { - resolver, - always_capture_in_scope, - current_binders: Vec::new(), - collected_lifetimes: FxIndexSet::default(), - } - } - - fn visit_opaque(&mut self, opaque_ty_node_id: NodeId, bounds: &'ast GenericBounds, span: Span) { - // If we're edition 2024 or within a TAIT or RPITIT, *and* there is no - // `use<>` statement to override the default capture behavior, then - // capture all of the in-scope lifetimes. - if (self.always_capture_in_scope || span.at_least_rust_2024()) - && bounds.iter().all(|bound| !matches!(bound, GenericBound::Use(..))) - { - for (ident, id, _) in self.resolver.extra_lifetime_params(opaque_ty_node_id) { - self.record_lifetime_use(Lifetime { id, ident }); - } - } - - // We also recurse on the bounds to make sure we capture all the lifetimes - // mentioned in the bounds. These may disagree with the `use<>` list, in which - // case we will error on these later. We will also recurse to visit any - // nested opaques, which may *implicitly* capture lifetimes. - for bound in bounds { - self.visit_param_bound(bound, BoundKind::Bound); - } - } - - fn record_lifetime_use(&mut self, lifetime: Lifetime) { - match self.resolver.get_lifetime_res(lifetime.id).unwrap_or(LifetimeRes::Error) { - LifetimeRes::Param { binder, .. } | LifetimeRes::Fresh { binder, .. } => { - if !self.current_binders.contains(&binder) { - self.collected_lifetimes.insert(lifetime); - } - } - LifetimeRes::Static { .. } | LifetimeRes::Error => { - self.collected_lifetimes.insert(lifetime); - } - LifetimeRes::Infer => {} - res => { - let bug_msg = format!( - "Unexpected lifetime resolution {:?} for {:?} at {:?}", - res, lifetime.ident, lifetime.ident.span - ); - span_bug!(lifetime.ident.span, "{}", bug_msg); - } - } - } - - /// This collect lifetimes that are elided, for nodes like `Foo<T>` where there are no explicit - /// lifetime nodes. Is equivalent to having "pseudo" nodes introduced for each of the node ids - /// in the list start..end. - fn record_elided_anchor(&mut self, node_id: NodeId, span: Span) { - if let Some(LifetimeRes::ElidedAnchor { start, end }) = - self.resolver.get_lifetime_res(node_id) - { - for i in start..end { - let lifetime = Lifetime { id: i, ident: Ident::new(kw::UnderscoreLifetime, span) }; - self.record_lifetime_use(lifetime); - } - } - } -} - -impl<'ast> Visitor<'ast> for LifetimeCollectVisitor<'ast> { - fn visit_lifetime(&mut self, lifetime: &'ast Lifetime, _: LifetimeCtxt) { - self.record_lifetime_use(*lifetime); - } - - fn visit_path_segment(&mut self, path_segment: &'ast PathSegment) { - self.record_elided_anchor(path_segment.id, path_segment.ident.span); - visit::walk_path_segment(self, path_segment); - } - - fn visit_poly_trait_ref(&mut self, t: &'ast PolyTraitRef) { - self.current_binders.push(t.trait_ref.ref_id); - - visit::walk_poly_trait_ref(self, t); - - self.current_binders.pop(); - } - - fn visit_ty(&mut self, t: &'ast Ty) { - match &t.kind { - TyKind::Path(None, _) => { - // We can sometimes encounter bare trait objects - // which are represented in AST as paths. - if let Some(partial_res) = self.resolver.get_partial_res(t.id) - && let Some(Res::Def(DefKind::Trait | DefKind::TraitAlias, _)) = - partial_res.full_res() - { - self.current_binders.push(t.id); - visit::walk_ty(self, t); - self.current_binders.pop(); - } else { - visit::walk_ty(self, t); - } - } - TyKind::BareFn(_) => { - self.current_binders.push(t.id); - visit::walk_ty(self, t); - self.current_binders.pop(); - } - TyKind::Ref(None, _) | TyKind::PinnedRef(None, _) => { - self.record_elided_anchor(t.id, t.span); - visit::walk_ty(self, t); - } - TyKind::ImplTrait(opaque_ty_node_id, bounds) => { - self.visit_opaque(*opaque_ty_node_id, bounds, t.span) - } - _ => { - visit::walk_ty(self, t); - } - } - } -} - -pub(crate) fn lifetimes_for_opaque( - resolver: &mut ResolverAstLowering, - always_capture_in_scope: bool, - opaque_ty_node_id: NodeId, - bounds: &GenericBounds, - span: Span, -) -> FxIndexSet<Lifetime> { - let mut visitor = LifetimeCollectVisitor::new(resolver, always_capture_in_scope); - visitor.visit_opaque(opaque_ty_node_id, bounds, span); - visitor.collected_lifetimes -} diff --git a/compiler/rustc_ast_lowering/src/pat.rs b/compiler/rustc_ast_lowering/src/pat.rs index 760f84564f1..ace7bfb5c73 100644 --- a/compiler/rustc_ast_lowering/src/pat.rs +++ b/compiler/rustc_ast_lowering/src/pat.rs @@ -21,13 +21,20 @@ impl<'a, 'hir> LoweringContext<'a, 'hir> { fn lower_pat_mut(&mut self, mut pattern: &Pat) -> hir::Pat<'hir> { ensure_sufficient_stack(|| { // loop here to avoid recursion + let pat_hir_id = self.lower_node_id(pattern.id); let node = loop { match &pattern.kind { PatKind::Wild => break hir::PatKind::Wild, PatKind::Never => break hir::PatKind::Never, PatKind::Ident(binding_mode, ident, sub) => { let lower_sub = |this: &mut Self| sub.as_ref().map(|s| this.lower_pat(s)); - break self.lower_pat_ident(pattern, *binding_mode, *ident, lower_sub); + break self.lower_pat_ident( + pattern, + *binding_mode, + *ident, + pat_hir_id, + lower_sub, + ); } PatKind::Lit(e) => { break hir::PatKind::Lit(self.lower_expr_within_pat(e, false)); @@ -119,7 +126,7 @@ impl<'a, 'hir> LoweringContext<'a, 'hir> { } }; - self.pat_with_node_id_of(pattern, node) + self.pat_with_node_id_of(pattern, node, pat_hir_id) }) } @@ -187,10 +194,12 @@ impl<'a, 'hir> LoweringContext<'a, 'hir> { let mut prev_rest_span = None; // Lowers `$bm $ident @ ..` to `$bm $ident @ _`. - let lower_rest_sub = |this: &mut Self, pat, &ann, &ident, sub| { - let lower_sub = |this: &mut Self| Some(this.pat_wild_with_node_id_of(sub)); - let node = this.lower_pat_ident(pat, ann, ident, lower_sub); - this.pat_with_node_id_of(pat, node) + let lower_rest_sub = |this: &mut Self, pat: &Pat, &ann, &ident, sub: &Pat| { + let sub_hir_id = this.lower_node_id(sub.id); + let lower_sub = |this: &mut Self| Some(this.pat_wild_with_node_id_of(sub, sub_hir_id)); + let pat_hir_id = this.lower_node_id(pat.id); + let node = this.lower_pat_ident(pat, ann, ident, pat_hir_id, lower_sub); + this.pat_with_node_id_of(pat, node, pat_hir_id) }; let mut iter = pats.iter(); @@ -200,7 +209,8 @@ impl<'a, 'hir> LoweringContext<'a, 'hir> { // Found a sub-slice pattern `..`. Record, lower it to `_`, and stop here. PatKind::Rest => { prev_rest_span = Some(pat.span); - slice = Some(self.pat_wild_with_node_id_of(pat)); + let hir_id = self.lower_node_id(pat.id); + slice = Some(self.pat_wild_with_node_id_of(pat, hir_id)); break; } // Found a sub-slice pattern `$binding_mode $ident @ ..`. @@ -248,19 +258,35 @@ impl<'a, 'hir> LoweringContext<'a, 'hir> { p: &Pat, annotation: BindingMode, ident: Ident, + hir_id: hir::HirId, lower_sub: impl FnOnce(&mut Self) -> Option<&'hir hir::Pat<'hir>>, ) -> hir::PatKind<'hir> { match self.resolver.get_partial_res(p.id).map(|d| d.expect_full_res()) { // `None` can occur in body-less function signatures res @ (None | Some(Res::Local(_))) => { - let canonical_id = match res { - Some(Res::Local(id)) => id, - _ => p.id, + let binding_id = match res { + Some(Res::Local(id)) => { + // In `Or` patterns like `VariantA(s) | VariantB(s, _)`, multiple identifier patterns + // will be resolved to the same `Res::Local`. Thus they just share a single + // `HirId`. + if id == p.id { + self.ident_and_label_to_local_id.insert(id, hir_id.local_id); + hir_id + } else { + hir::HirId { + owner: self.current_hir_id_owner, + local_id: self.ident_and_label_to_local_id[&id], + } + } + } + _ => { + self.ident_and_label_to_local_id.insert(p.id, hir_id.local_id); + hir_id + } }; - hir::PatKind::Binding( annotation, - self.lower_node_id(canonical_id), + binding_id, self.lower_ident(ident), lower_sub(self), ) @@ -280,18 +306,18 @@ impl<'a, 'hir> LoweringContext<'a, 'hir> { } } - fn pat_wild_with_node_id_of(&mut self, p: &Pat) -> &'hir hir::Pat<'hir> { - self.arena.alloc(self.pat_with_node_id_of(p, hir::PatKind::Wild)) + fn pat_wild_with_node_id_of(&mut self, p: &Pat, hir_id: hir::HirId) -> &'hir hir::Pat<'hir> { + self.arena.alloc(self.pat_with_node_id_of(p, hir::PatKind::Wild, hir_id)) } - /// Construct a `Pat` with the `HirId` of `p.id` lowered. - fn pat_with_node_id_of(&mut self, p: &Pat, kind: hir::PatKind<'hir>) -> hir::Pat<'hir> { - hir::Pat { - hir_id: self.lower_node_id(p.id), - kind, - span: self.lower_span(p.span), - default_binding_modes: true, - } + /// Construct a `Pat` with the `HirId` of `p.id` already lowered. + fn pat_with_node_id_of( + &mut self, + p: &Pat, + kind: hir::PatKind<'hir>, + hir_id: hir::HirId, + ) -> hir::Pat<'hir> { + hir::Pat { hir_id, kind, span: self.lower_span(p.span), default_binding_modes: true } } /// Emit a friendly error for extra `..` patterns in a tuple/tuple struct/slice pattern. diff --git a/compiler/rustc_ast_lowering/src/path.rs b/compiler/rustc_ast_lowering/src/path.rs index 258655de486..133793e26ea 100644 --- a/compiler/rustc_ast_lowering/src/path.rs +++ b/compiler/rustc_ast_lowering/src/path.rs @@ -34,7 +34,10 @@ impl<'a, 'hir> LoweringContext<'a, 'hir> { modifiers: Option<ast::TraitBoundModifiers>, ) -> hir::QPath<'hir> { let qself_position = qself.as_ref().map(|q| q.position); - let qself = qself.as_ref().map(|q| self.lower_ty(&q.ty, itctx)); + let qself = qself + .as_ref() + // Reject cases like `<impl Trait>::Assoc` and `<impl Trait as Trait>::Assoc`. + .map(|q| self.lower_ty(&q.ty, ImplTraitContext::Disallowed(ImplTraitPosition::Path))); let partial_res = self.resolver.get_partial_res(id).unwrap_or_else(|| PartialRes::new(Res::Err)); @@ -70,11 +73,21 @@ impl<'a, 'hir> LoweringContext<'a, 'hir> { let bound_modifier_allowed_features = if let Res::Def(DefKind::Trait, async_def_id) = res && self.tcx.async_fn_trait_kind_from_def_id(async_def_id).is_some() { - Some(self.allow_async_fn_traits.clone()) + Some(Lrc::clone(&self.allow_async_fn_traits)) } else { None }; + // Only permit `impl Trait` in the final segment. E.g., we permit `Option<impl Trait>`, + // `option::Option<T>::Xyz<impl Trait>` and reject `option::Option<impl Trait>::Xyz`. + let itctx = |i| { + if i + 1 == p.segments.len() { + itctx + } else { + ImplTraitContext::Disallowed(ImplTraitPosition::Path) + } + }; + let path_span_lo = p.span.shrink_to_lo(); let proj_start = p.segments.len() - unresolved_segments; let path = self.arena.alloc(hir::Path { @@ -121,7 +134,7 @@ impl<'a, 'hir> LoweringContext<'a, 'hir> { segment, param_mode, generic_args_mode, - itctx, + itctx(i), bound_modifier_allowed_features.clone(), ) }, @@ -185,7 +198,7 @@ impl<'a, 'hir> LoweringContext<'a, 'hir> { segment, param_mode, generic_args_mode, - itctx, + itctx(i), None, )); let qpath = hir::QPath::TypeRelative(ty, hir_segment); diff --git a/compiler/rustc_ast_passes/messages.ftl b/compiler/rustc_ast_passes/messages.ftl index 92acaaa5f36..d81fd53938b 100644 --- a/compiler/rustc_ast_passes/messages.ftl +++ b/compiler/rustc_ast_passes/messages.ftl @@ -146,8 +146,6 @@ ast_passes_generic_before_constraints = generic arguments must come before the f ast_passes_generic_default_trailing = generic parameters with a default must be trailing -ast_passes_impl_trait_path = `impl Trait` is not allowed in path parameters - ast_passes_incompatible_features = `{$f1}` and `{$f2}` are incompatible, using them at the same time is not allowed .help = remove one of these features diff --git a/compiler/rustc_ast_passes/src/ast_validation.rs b/compiler/rustc_ast_passes/src/ast_validation.rs index 1d149e91b85..0a4f86d4822 100644 --- a/compiler/rustc_ast_passes/src/ast_validation.rs +++ b/compiler/rustc_ast_passes/src/ast_validation.rs @@ -80,10 +80,6 @@ struct AstValidator<'a> { disallow_tilde_const: Option<TildeConstReason>, - /// Used to ban `impl Trait` in path projections like `<impl Iterator>::Item` - /// or `Foo::Bar<impl Trait>` - is_impl_trait_banned: bool, - /// Used to ban explicit safety on foreign items when the extern block is not marked as unsafe. extern_mod_safety: Option<Safety>, @@ -123,12 +119,6 @@ impl<'a> AstValidator<'a> { self.extern_mod_safety = old; } - fn with_banned_impl_trait(&mut self, f: impl FnOnce(&mut Self)) { - let old = mem::replace(&mut self.is_impl_trait_banned, true); - f(self); - self.is_impl_trait_banned = old; - } - fn with_tilde_const( &mut self, disallowed: Option<TildeConstReason>, @@ -213,37 +203,6 @@ impl<'a> AstValidator<'a> { .with_tilde_const(Some(TildeConstReason::TraitObject), |this| { visit::walk_ty(this, t) }), - TyKind::Path(qself, path) => { - // We allow these: - // - `Option<impl Trait>` - // - `option::Option<impl Trait>` - // - `option::Option<T>::Foo<impl Trait>` - // - // But not these: - // - `<impl Trait>::Foo` - // - `option::Option<impl Trait>::Foo`. - // - // To implement this, we disallow `impl Trait` from `qself` - // (for cases like `<impl Trait>::Foo>`) - // but we allow `impl Trait` in `GenericArgs` - // iff there are no more PathSegments. - if let Some(qself) = qself { - // `impl Trait` in `qself` is always illegal - self.with_banned_impl_trait(|this| this.visit_ty(&qself.ty)); - } - - // Note that there should be a call to visit_path here, - // so if any logic is added to process `Path`s a call to it should be - // added both in visit_path and here. This code mirrors visit::walk_path. - for (i, segment) in path.segments.iter().enumerate() { - // Allow `impl Trait` iff we're on the final path segment - if i == path.segments.len() - 1 { - self.visit_path_segment(segment); - } else { - self.with_banned_impl_trait(|this| this.visit_path_segment(segment)); - } - } - } _ => visit::walk_ty(self, t), } } @@ -737,10 +696,6 @@ impl<'a> AstValidator<'a> { } } TyKind::ImplTrait(_, bounds) => { - if self.is_impl_trait_banned { - self.dcx().emit_err(errors::ImplTraitPath { span: ty.span }); - } - if let Some(outer_impl_trait_sp) = self.outer_impl_trait { self.dcx().emit_err(errors::NestedImplTrait { span: ty.span, @@ -1729,7 +1684,6 @@ pub fn check_crate( has_proc_macro_decls: false, outer_impl_trait: None, disallow_tilde_const: Some(TildeConstReason::Item), - is_impl_trait_banned: false, extern_mod_safety: None, lint_buffer: lints, }; diff --git a/compiler/rustc_ast_passes/src/errors.rs b/compiler/rustc_ast_passes/src/errors.rs index 4ca1acde1e2..8c3ac9864ed 100644 --- a/compiler/rustc_ast_passes/src/errors.rs +++ b/compiler/rustc_ast_passes/src/errors.rs @@ -419,13 +419,6 @@ pub(crate) struct TraitObjectBound { } #[derive(Diagnostic)] -#[diag(ast_passes_impl_trait_path, code = E0667)] -pub(crate) struct ImplTraitPath { - #[primary_span] - pub span: Span, -} - -#[derive(Diagnostic)] #[diag(ast_passes_nested_impl_trait, code = E0666)] pub(crate) struct NestedImplTrait { #[primary_span] diff --git a/compiler/rustc_ast_pretty/Cargo.toml b/compiler/rustc_ast_pretty/Cargo.toml index 9ae5c9b3cec..f290fedcd8b 100644 --- a/compiler/rustc_ast_pretty/Cargo.toml +++ b/compiler/rustc_ast_pretty/Cargo.toml @@ -7,6 +7,7 @@ edition = "2021" # tidy-alphabetical-start itertools = "0.12" rustc_ast = { path = "../rustc_ast" } +rustc_data_structures = { path = "../rustc_data_structures" } rustc_lexer = { path = "../rustc_lexer" } rustc_span = { path = "../rustc_span" } thin-vec = "0.2.12" diff --git a/compiler/rustc_ast_pretty/src/pprust/state.rs b/compiler/rustc_ast_pretty/src/pprust/state.rs index 1e18f0779f0..de9f5187be7 100644 --- a/compiler/rustc_ast_pretty/src/pprust/state.rs +++ b/compiler/rustc_ast_pretty/src/pprust/state.rs @@ -21,6 +21,7 @@ use rustc_ast::{ GenericBound, InlineAsmOperand, InlineAsmOptions, InlineAsmRegOrRegClass, InlineAsmTemplatePiece, PatKind, RangeEnd, RangeSyntax, Safety, SelfKind, Term, attr, }; +use rustc_data_structures::sync::Lrc; use rustc_span::edition::Edition; use rustc_span::source_map::{SourceMap, Spanned}; use rustc_span::symbol::{Ident, IdentPrinter, Symbol, kw, sym}; @@ -105,7 +106,7 @@ fn split_block_comment_into_lines(text: &str, col: CharPos) -> Vec<String> { fn gather_comments(sm: &SourceMap, path: FileName, src: String) -> Vec<Comment> { let sm = SourceMap::new(sm.path_mapping().clone()); let source_file = sm.new_source_file(path, src); - let text = (*source_file.src.as_ref().unwrap()).clone(); + let text = Lrc::clone(&(*source_file.src.as_ref().unwrap())); let text: &str = text.as_str(); let start_bpos = source_file.start_pos; diff --git a/compiler/rustc_borrowck/src/diagnostics/region_name.rs b/compiler/rustc_borrowck/src/diagnostics/region_name.rs index b4b8373ac97..6ca7251295d 100644 --- a/compiler/rustc_borrowck/src/diagnostics/region_name.rs +++ b/compiler/rustc_borrowck/src/diagnostics/region_name.rs @@ -830,7 +830,7 @@ impl<'tcx> MirBorrowckCtxt<'_, '_, 'tcx> { /// /// [`OpaqueDef`]: hir::TyKind::OpaqueDef fn get_future_inner_return_ty(&self, hir_ty: &'tcx hir::Ty<'tcx>) -> &'tcx hir::Ty<'tcx> { - let hir::TyKind::OpaqueDef(opaque_ty, _) = hir_ty.kind else { + let hir::TyKind::OpaqueDef(opaque_ty) = hir_ty.kind else { span_bug!( hir_ty.span, "lowered return type of async fn is not OpaqueDef: {:?}", diff --git a/compiler/rustc_borrowck/src/lib.rs b/compiler/rustc_borrowck/src/lib.rs index 698fdafc936..efcee2899c6 100644 --- a/compiler/rustc_borrowck/src/lib.rs +++ b/compiler/rustc_borrowck/src/lib.rs @@ -34,7 +34,7 @@ use rustc_infer::infer::{ use rustc_middle::mir::tcx::PlaceTy; use rustc_middle::mir::*; use rustc_middle::query::Providers; -use rustc_middle::ty::{self, ParamEnv, RegionVid, TyCtxt}; +use rustc_middle::ty::{self, ParamEnv, RegionVid, TyCtxt, TypingMode}; use rustc_middle::{bug, span_bug}; use rustc_mir_dataflow::Analysis; use rustc_mir_dataflow::impls::{ @@ -193,9 +193,7 @@ fn do_mir_borrowck<'tcx>( .map(|(idx, body)| (idx, MoveData::gather_moves(body, tcx, |_| true))); let mut flow_inits = MaybeInitializedPlaces::new(tcx, body, &move_data) - .into_engine(tcx, body) - .pass_name("borrowck") - .iterate_to_fixpoint() + .iterate_to_fixpoint(tcx, body, Some("borrowck")) .into_results_cursor(body); let locals_are_invalidated_at_exit = tcx.hir().body_owner_kind(def).is_fn_or_closure(); @@ -243,18 +241,21 @@ fn do_mir_borrowck<'tcx>( // usage significantly on some benchmarks. drop(flow_inits); - let flow_borrows = Borrows::new(tcx, body, ®ioncx, &borrow_set) - .into_engine(tcx, body) - .pass_name("borrowck") - .iterate_to_fixpoint(); - let flow_uninits = MaybeUninitializedPlaces::new(tcx, body, &move_data) - .into_engine(tcx, body) - .pass_name("borrowck") - .iterate_to_fixpoint(); - let flow_ever_inits = EverInitializedPlaces::new(body, &move_data) - .into_engine(tcx, body) - .pass_name("borrowck") - .iterate_to_fixpoint(); + let flow_borrows = Borrows::new(tcx, body, ®ioncx, &borrow_set).iterate_to_fixpoint( + tcx, + body, + Some("borrowck"), + ); + let flow_uninits = MaybeUninitializedPlaces::new(tcx, body, &move_data).iterate_to_fixpoint( + tcx, + body, + Some("borrowck"), + ); + let flow_ever_inits = EverInitializedPlaces::new(body, &move_data).iterate_to_fixpoint( + tcx, + body, + Some("borrowck"), + ); let movable_coroutine = // The first argument is the coroutine type passed by value @@ -440,7 +441,7 @@ pub struct BorrowckInferCtxt<'tcx> { impl<'tcx> BorrowckInferCtxt<'tcx> { pub(crate) fn new(tcx: TyCtxt<'tcx>, def_id: LocalDefId) -> Self { - let infcx = tcx.infer_ctxt().with_opaque_type_inference(def_id).build(); + let infcx = tcx.infer_ctxt().build(TypingMode::analysis_in_body(tcx, def_id)); BorrowckInferCtxt { infcx, reg_var_to_origin: RefCell::new(Default::default()) } } diff --git a/compiler/rustc_borrowck/src/nll.rs b/compiler/rustc_borrowck/src/nll.rs index 3674053409b..f76603d5679 100644 --- a/compiler/rustc_borrowck/src/nll.rs +++ b/compiler/rustc_borrowck/src/nll.rs @@ -107,13 +107,13 @@ pub(crate) fn compute_regions<'a, 'tcx>( param_env, body, promoted, - universal_regions.clone(), + Rc::clone(&universal_regions), location_table, borrow_set, &mut all_facts, flow_inits, move_data, - elements.clone(), + Rc::clone(&elements), upvars, ); diff --git a/compiler/rustc_borrowck/src/region_infer/mod.rs b/compiler/rustc_borrowck/src/region_infer/mod.rs index e85f529bf0e..d5c2796932e 100644 --- a/compiler/rustc_borrowck/src/region_infer/mod.rs +++ b/compiler/rustc_borrowck/src/region_infer/mod.rs @@ -733,7 +733,7 @@ impl<'tcx> RegionInferenceContext<'tcx> { } // Now take member constraints into account. - let member_constraints = self.member_constraints.clone(); + let member_constraints = Rc::clone(&self.member_constraints); for m_c_i in member_constraints.indices(scc_a) { self.apply_member_constraint(scc_a, m_c_i, member_constraints.choice_regions(m_c_i)); } @@ -1679,7 +1679,7 @@ impl<'tcx> RegionInferenceContext<'tcx> { infcx: &InferCtxt<'tcx>, errors_buffer: &mut RegionErrors<'tcx>, ) { - let member_constraints = self.member_constraints.clone(); + let member_constraints = Rc::clone(&self.member_constraints); for m_c_i in member_constraints.all_indices() { debug!(?m_c_i); let m_c = &member_constraints[m_c_i]; diff --git a/compiler/rustc_borrowck/src/region_infer/opaque_types.rs b/compiler/rustc_borrowck/src/region_infer/opaque_types.rs index abce98265b3..741dac9e763 100644 --- a/compiler/rustc_borrowck/src/region_infer/opaque_types.rs +++ b/compiler/rustc_borrowck/src/region_infer/opaque_types.rs @@ -9,6 +9,7 @@ use rustc_macros::extension; use rustc_middle::ty::visit::TypeVisitableExt; use rustc_middle::ty::{ self, GenericArgKind, GenericArgs, OpaqueHiddenType, OpaqueTypeKey, Ty, TyCtxt, TypeFoldable, + TypingMode, }; use rustc_span::Span; use rustc_trait_selection::error_reporting::InferCtxtErrorExt; @@ -340,14 +341,13 @@ fn check_opaque_type_well_formed<'tcx>( parent_def_id = tcx.local_parent(parent_def_id); } - // FIXME(-Znext-solver): We probably should use `&[]` instead of - // and prepopulate this `InferCtxt` with known opaque values, rather than - // allowing opaque types to be defined and checking them after the fact. + // FIXME(#132279): This should eventually use the already defined hidden types + // instead. Alternatively we'll entirely remove this function given we also check + // the opaque in `check_opaque_meets_bounds` later. let infcx = tcx .infer_ctxt() .with_next_trait_solver(next_trait_solver) - .with_opaque_type_inference(parent_def_id) - .build(); + .build(TypingMode::analysis_in_body(tcx, parent_def_id)); let ocx = ObligationCtxt::new_with_diagnostics(&infcx); let identity_args = GenericArgs::identity_for_item(tcx, def_id); @@ -517,7 +517,9 @@ impl<'tcx> LazyOpaqueTyEnv<'tcx> { }, ); - let infcx = tcx.infer_ctxt().build(); + // FIXME(#132279): It feels wrong to use `non_body_analysis` here given that we're + // in a body here. + let infcx = tcx.infer_ctxt().build(TypingMode::non_body_analysis()); let ocx = ObligationCtxt::new(&infcx); let wf_tys = ocx.assumed_wf_types(param_env, parent).unwrap_or_else(|_| { diff --git a/compiler/rustc_borrowck/src/type_check/mod.rs b/compiler/rustc_borrowck/src/type_check/mod.rs index a544d88e832..26919bfd488 100644 --- a/compiler/rustc_borrowck/src/type_check/mod.rs +++ b/compiler/rustc_borrowck/src/type_check/mod.rs @@ -134,7 +134,7 @@ pub(crate) fn type_check<'a, 'tcx>( let mut constraints = MirTypeckRegionConstraints { placeholder_indices: PlaceholderIndices::default(), placeholder_index_to_region: IndexVec::default(), - liveness_constraints: LivenessValues::with_specific_points(elements.clone()), + liveness_constraints: LivenessValues::with_specific_points(Rc::clone(&elements)), outlives_constraints: OutlivesConstraintSet::default(), member_constraints: MemberConstraintSet::default(), type_tests: Vec::default(), @@ -150,7 +150,7 @@ pub(crate) fn type_check<'a, 'tcx>( infcx, param_env, implicit_region_bound, - universal_regions.clone(), + Rc::clone(&universal_regions), &mut constraints, ); diff --git a/compiler/rustc_builtin_macros/src/deriving/smart_ptr.rs b/compiler/rustc_builtin_macros/src/deriving/coerce_pointee.rs index 731945f5cbf..53e938ee216 100644 --- a/compiler/rustc_builtin_macros/src/deriving/smart_ptr.rs +++ b/compiler/rustc_builtin_macros/src/deriving/coerce_pointee.rs @@ -19,7 +19,7 @@ macro_rules! path { ($span:expr, $($part:ident)::*) => { vec![$(Ident::new(sym::$part, $span),)*] } } -pub(crate) fn expand_deriving_smart_ptr( +pub(crate) fn expand_deriving_coerce_pointee( cx: &ExtCtxt<'_>, span: Span, _mitem: &MetaItem, @@ -41,7 +41,7 @@ pub(crate) fn expand_deriving_smart_ptr( cx.dcx() .struct_span_err( span, - "`SmartPointer` can only be derived on `struct`s with `#[repr(transparent)]`", + "`CoercePointee` can only be derived on `struct`s with `#[repr(transparent)]`", ) .emit(); return; @@ -54,7 +54,7 @@ pub(crate) fn expand_deriving_smart_ptr( cx.dcx() .struct_span_err( span, - "`SmartPointer` can only be derived on `struct`s with at least one field", + "`CoercePointee` can only be derived on `struct`s with at least one field", ) .emit(); return; @@ -64,7 +64,7 @@ pub(crate) fn expand_deriving_smart_ptr( cx.dcx() .struct_span_err( span, - "`SmartPointer` can only be derived on `struct`s with `#[repr(transparent)]`", + "`CoercePointee` can only be derived on `struct`s with `#[repr(transparent)]`", ) .emit(); return; @@ -94,10 +94,10 @@ pub(crate) fn expand_deriving_smart_ptr( .collect(); let pointee_param_idx = if type_params.is_empty() { - // `#[derive(SmartPointer)]` requires at least one generic type on the target `struct` + // `#[derive(CoercePointee)]` requires at least one generic type on the target `struct` cx.dcx().struct_span_err( span, - "`SmartPointer` can only be derived on `struct`s that are generic over at least one type", + "`CoercePointee` can only be derived on `struct`s that are generic over at least one type", ).emit(); return; } else if type_params.len() == 1 { @@ -113,7 +113,7 @@ pub(crate) fn expand_deriving_smart_ptr( (None, _) => { cx.dcx().struct_span_err( span, - "exactly one generic type parameter must be marked as #[pointee] to derive SmartPointer traits", + "exactly one generic type parameter must be marked as #[pointee] to derive CoercePointee traits", ).emit(); return; } @@ -121,7 +121,7 @@ pub(crate) fn expand_deriving_smart_ptr( cx.dcx() .struct_span_err( vec![one, another], - "only one type parameter can be marked as `#[pointee]` when deriving SmartPointer traits", + "only one type parameter can be marked as `#[pointee]` when deriving CoercePointee traits", ) .emit(); return; @@ -185,7 +185,7 @@ pub(crate) fn expand_deriving_smart_ptr( .struct_span_err( pointee_ty_ident.span, format!( - "`derive(SmartPointer)` requires {} to be marked `?Sized`", + "`derive(CoercePointee)` requires {} to be marked `?Sized`", pointee_ty_ident.name ), ) @@ -195,7 +195,7 @@ pub(crate) fn expand_deriving_smart_ptr( let arg = GenericArg::Type(s_ty.clone()); let unsize = cx.path_all(span, true, path!(span, core::marker::Unsize), vec![arg]); pointee.bounds.push(cx.trait_bound(unsize, false)); - // Drop `#[pointee]` attribute since it should not be recognized outside `derive(SmartPointer)` + // Drop `#[pointee]` attribute since it should not be recognized outside `derive(CoercePointee)` pointee.attrs.retain(|attr| !attr.has_name(sym::pointee)); } diff --git a/compiler/rustc_builtin_macros/src/deriving/mod.rs b/compiler/rustc_builtin_macros/src/deriving/mod.rs index e884c0ec718..681fbd1651d 100644 --- a/compiler/rustc_builtin_macros/src/deriving/mod.rs +++ b/compiler/rustc_builtin_macros/src/deriving/mod.rs @@ -22,12 +22,12 @@ macro path_std($($x:tt)*) { pub(crate) mod bounds; pub(crate) mod clone; +pub(crate) mod coerce_pointee; pub(crate) mod debug; pub(crate) mod decodable; pub(crate) mod default; pub(crate) mod encodable; pub(crate) mod hash; -pub(crate) mod smart_ptr; #[path = "cmp/eq.rs"] pub(crate) mod eq; diff --git a/compiler/rustc_builtin_macros/src/lib.rs b/compiler/rustc_builtin_macros/src/lib.rs index 377d7f542cf..9eee92164cf 100644 --- a/compiler/rustc_builtin_macros/src/lib.rs +++ b/compiler/rustc_builtin_macros/src/lib.rs @@ -133,7 +133,7 @@ pub fn register_builtin_macros(resolver: &mut dyn ResolverExpand) { PartialOrd: partial_ord::expand_deriving_partial_ord, RustcDecodable: decodable::expand_deriving_rustc_decodable, RustcEncodable: encodable::expand_deriving_rustc_encodable, - SmartPointer: smart_ptr::expand_deriving_smart_ptr, + CoercePointee: coerce_pointee::expand_deriving_coerce_pointee, } let client = proc_macro::bridge::client::Client::expand1(proc_macro::quote); diff --git a/compiler/rustc_codegen_cranelift/src/abi/comments.rs b/compiler/rustc_codegen_cranelift/src/abi/comments.rs index a318cae1722..daea789ee3e 100644 --- a/compiler/rustc_codegen_cranelift/src/abi/comments.rs +++ b/compiler/rustc_codegen_cranelift/src/abi/comments.rs @@ -79,7 +79,7 @@ pub(super) fn add_local_place_comments<'tcx>( return; } let TyAndLayout { ty, layout } = place.layout(); - let rustc_target::abi::LayoutS { size, align, .. } = layout.0.0; + let rustc_abi::LayoutData { size, align, .. } = layout.0.0; let (kind, extra) = place.debug_comment(); diff --git a/compiler/rustc_codegen_llvm/src/abi.rs b/compiler/rustc_codegen_llvm/src/abi.rs index 2fe5ed32daa..8a1ee48c43c 100644 --- a/compiler/rustc_codegen_llvm/src/abi.rs +++ b/compiler/rustc_codegen_llvm/src/abi.rs @@ -415,7 +415,7 @@ impl<'ll, 'tcx> FnAbiLlvmExt<'ll, 'tcx> for FnAbi<'tcx, Ty<'tcx>> { instance: Option<ty::Instance<'tcx>>, ) { let mut func_attrs = SmallVec::<[_; 3]>::new(); - if self.ret.layout.abi.is_uninhabited() { + if self.ret.layout.is_uninhabited() { func_attrs.push(llvm::AttributeKind::NoReturn.create_attr(cx.llcx)); } if !self.can_unwind { @@ -532,7 +532,7 @@ impl<'ll, 'tcx> FnAbiLlvmExt<'ll, 'tcx> for FnAbi<'tcx, Ty<'tcx>> { fn apply_attrs_callsite(&self, bx: &mut Builder<'_, 'll, 'tcx>, callsite: &'ll Value) { let mut func_attrs = SmallVec::<[_; 2]>::new(); - if self.ret.layout.abi.is_uninhabited() { + if self.ret.layout.is_uninhabited() { func_attrs.push(llvm::AttributeKind::NoReturn.create_attr(bx.cx.llcx)); } if !self.can_unwind { diff --git a/compiler/rustc_codegen_llvm/src/allocator.rs b/compiler/rustc_codegen_llvm/src/allocator.rs index 89f5305840b..149ded28356 100644 --- a/compiler/rustc_codegen_llvm/src/allocator.rs +++ b/compiler/rustc_codegen_llvm/src/allocator.rs @@ -7,6 +7,7 @@ use rustc_middle::bug; use rustc_middle::ty::TyCtxt; use rustc_session::config::{DebugInfo, OomStrategy}; +use crate::common::AsCCharPtr; use crate::llvm::{self, Context, False, Module, True, Type}; use crate::{ModuleLlvm, attributes, debuginfo}; @@ -76,21 +77,15 @@ pub(crate) unsafe fn codegen( unsafe { // __rust_alloc_error_handler_should_panic let name = OomStrategy::SYMBOL; - let ll_g = llvm::LLVMRustGetOrInsertGlobal(llmod, name.as_ptr().cast(), name.len(), i8); - llvm::LLVMRustSetVisibility( - ll_g, - llvm::Visibility::from_generic(tcx.sess.default_visibility()), - ); + let ll_g = llvm::LLVMRustGetOrInsertGlobal(llmod, name.as_c_char_ptr(), name.len(), i8); + llvm::set_visibility(ll_g, llvm::Visibility::from_generic(tcx.sess.default_visibility())); let val = tcx.sess.opts.unstable_opts.oom.should_panic(); let llval = llvm::LLVMConstInt(i8, val as u64, False); llvm::LLVMSetInitializer(ll_g, llval); let name = NO_ALLOC_SHIM_IS_UNSTABLE; - let ll_g = llvm::LLVMRustGetOrInsertGlobal(llmod, name.as_ptr().cast(), name.len(), i8); - llvm::LLVMRustSetVisibility( - ll_g, - llvm::Visibility::from_generic(tcx.sess.default_visibility()), - ); + let ll_g = llvm::LLVMRustGetOrInsertGlobal(llmod, name.as_c_char_ptr(), name.len(), i8); + llvm::set_visibility(ll_g, llvm::Visibility::from_generic(tcx.sess.default_visibility())); let llval = llvm::LLVMConstInt(i8, 0, False); llvm::LLVMSetInitializer(ll_g, llval); } @@ -121,7 +116,7 @@ fn create_wrapper_function( ); let llfn = llvm::LLVMRustGetOrInsertFunction( llmod, - from_name.as_ptr().cast(), + from_name.as_c_char_ptr(), from_name.len(), ty, ); @@ -134,10 +129,7 @@ fn create_wrapper_function( None }; - llvm::LLVMRustSetVisibility( - llfn, - llvm::Visibility::from_generic(tcx.sess.default_visibility()), - ); + llvm::set_visibility(llfn, llvm::Visibility::from_generic(tcx.sess.default_visibility())); if tcx.sess.must_emit_unwind_tables() { let uwtable = @@ -146,12 +138,12 @@ fn create_wrapper_function( } let callee = - llvm::LLVMRustGetOrInsertFunction(llmod, to_name.as_ptr().cast(), to_name.len(), ty); + llvm::LLVMRustGetOrInsertFunction(llmod, to_name.as_c_char_ptr(), to_name.len(), ty); if let Some(no_return) = no_return { // -> ! DIFlagNoReturn attributes::apply_to_llfn(callee, llvm::AttributePlace::Function, &[no_return]); } - llvm::LLVMRustSetVisibility(callee, llvm::Visibility::Hidden); + llvm::set_visibility(callee, llvm::Visibility::Hidden); let llbb = llvm::LLVMAppendBasicBlockInContext(llcx, llfn, c"entry".as_ptr()); @@ -162,7 +154,7 @@ fn create_wrapper_function( .enumerate() .map(|(i, _)| llvm::LLVMGetParam(llfn, i as c_uint)) .collect::<Vec<_>>(); - let ret = llvm::LLVMRustBuildCall( + let ret = llvm::LLVMBuildCallWithOperandBundles( llbuilder, ty, callee, @@ -170,6 +162,7 @@ fn create_wrapper_function( args.len() as c_uint, [].as_ptr(), 0 as c_uint, + c"".as_ptr(), ); llvm::LLVMSetTailCall(ret, True); if output.is_some() { diff --git a/compiler/rustc_codegen_llvm/src/asm.rs b/compiler/rustc_codegen_llvm/src/asm.rs index d1d7d0cf4ce..3c30822a2e2 100644 --- a/compiler/rustc_codegen_llvm/src/asm.rs +++ b/compiler/rustc_codegen_llvm/src/asm.rs @@ -15,7 +15,7 @@ use smallvec::SmallVec; use tracing::debug; use crate::builder::Builder; -use crate::common::Funclet; +use crate::common::{AsCCharPtr, Funclet}; use crate::context::CodegenCx; use crate::type_::Type; use crate::type_of::LayoutLlvmExt; @@ -420,7 +420,7 @@ impl<'tcx> AsmCodegenMethods<'tcx> for CodegenCx<'_, 'tcx> { unsafe { llvm::LLVMAppendModuleInlineAsm( self.llmod, - template_str.as_ptr().cast(), + template_str.as_c_char_ptr(), template_str.len(), ); } @@ -458,14 +458,14 @@ pub(crate) fn inline_asm_call<'ll>( let fty = bx.cx.type_func(&argtys, output); unsafe { // Ask LLVM to verify that the constraints are well-formed. - let constraints_ok = llvm::LLVMRustInlineAsmVerify(fty, cons.as_ptr().cast(), cons.len()); + let constraints_ok = llvm::LLVMRustInlineAsmVerify(fty, cons.as_c_char_ptr(), cons.len()); debug!("constraint verification result: {:?}", constraints_ok); if constraints_ok { let v = llvm::LLVMRustInlineAsm( fty, - asm.as_ptr().cast(), + asm.as_c_char_ptr(), asm.len(), - cons.as_ptr().cast(), + cons.as_c_char_ptr(), cons.len(), volatile, alignstack, diff --git a/compiler/rustc_codegen_llvm/src/back/lto.rs b/compiler/rustc_codegen_llvm/src/back/lto.rs index 1f7a923dd2c..48beb9be2b2 100644 --- a/compiler/rustc_codegen_llvm/src/back/lto.rs +++ b/compiler/rustc_codegen_llvm/src/back/lto.rs @@ -165,13 +165,14 @@ fn get_bitcode_slice_from_object_data<'a>( // We drop the "__LLVM," prefix here because on Apple platforms there's a notion of "segment // name" which in the public API for sections gets treated as part of the section name, but // internally in MachOObjectFile.cpp gets treated separately. - let section_name = bitcode_section_name(cgcx).trim_start_matches("__LLVM,"); + let section_name = bitcode_section_name(cgcx).to_str().unwrap().trim_start_matches("__LLVM,"); let mut len = 0; let data = unsafe { llvm::LLVMRustGetSliceFromObjectDataByName( obj.as_ptr(), obj.len(), section_name.as_ptr(), + section_name.len(), &mut len, ) }; @@ -502,9 +503,9 @@ fn thin_lto( // upstream... let data = llvm::LLVMRustCreateThinLTOData( thin_modules.as_ptr(), - thin_modules.len() as u32, + thin_modules.len(), symbols_below_threshold.as_ptr(), - symbols_below_threshold.len() as u32, + symbols_below_threshold.len(), ) .ok_or_else(|| write::llvm_err(dcx, LlvmError::PrepareThinLtoContext))?; @@ -569,7 +570,7 @@ fn thin_lto( info!(" - {}: re-compiled", module_name); opt_jobs.push(LtoModuleCodegen::Thin(ThinModule { - shared: shared.clone(), + shared: Arc::clone(&shared), idx: module_index, })); } @@ -601,23 +602,9 @@ pub(crate) fn run_pass_manager( // This code is based off the code found in llvm's LTO code generator: // llvm/lib/LTO/LTOCodeGenerator.cpp debug!("running the pass manager"); - unsafe { - if !llvm::LLVMRustHasModuleFlag( - module.module_llvm.llmod(), - "LTOPostLink".as_ptr().cast(), - 11, - ) { - llvm::LLVMRustAddModuleFlagU32( - module.module_llvm.llmod(), - llvm::LLVMModFlagBehavior::Error, - c"LTOPostLink".as_ptr(), - 1, - ); - } - let opt_stage = if thin { llvm::OptStage::ThinLTO } else { llvm::OptStage::FatLTO }; - let opt_level = config.opt_level.unwrap_or(config::OptLevel::No); - write::llvm_optimize(cgcx, dcx, module, config, opt_level, opt_stage)?; - } + let opt_stage = if thin { llvm::OptStage::ThinLTO } else { llvm::OptStage::FatLTO }; + let opt_level = config.opt_level.unwrap_or(config::OptLevel::No); + unsafe { write::llvm_optimize(cgcx, dcx, module, config, opt_level, opt_stage) }?; debug!("lto done"); Ok(()) } diff --git a/compiler/rustc_codegen_llvm/src/back/write.rs b/compiler/rustc_codegen_llvm/src/back/write.rs index afdd2b581b8..bfa9e8b82a0 100644 --- a/compiler/rustc_codegen_llvm/src/back/write.rs +++ b/compiler/rustc_codegen_llvm/src/back/write.rs @@ -1,4 +1,4 @@ -use std::ffi::CString; +use std::ffi::{CStr, CString}; use std::io::{self, Write}; use std::path::{Path, PathBuf}; use std::sync::Arc; @@ -34,6 +34,7 @@ use crate::back::owned_target_machine::OwnedTargetMachine; use crate::back::profiling::{ LlvmSelfProfiler, selfprofile_after_pass_callback, selfprofile_before_pass_callback, }; +use crate::common::AsCCharPtr; use crate::errors::{ CopyBitcode, FromLlvmDiag, FromLlvmOptimizationDiag, LlvmError, UnknownCompression, WithLlvmError, WriteBytecode, @@ -596,9 +597,9 @@ pub(crate) unsafe fn llvm_optimize( llvm_selfprofiler, selfprofile_before_pass_callback, selfprofile_after_pass_callback, - extra_passes.as_ptr().cast(), + extra_passes.as_c_char_ptr(), extra_passes.len(), - llvm_plugins.as_ptr().cast(), + llvm_plugins.as_c_char_ptr(), llvm_plugins.len(), ) }; @@ -957,14 +958,13 @@ fn target_is_aix(cgcx: &CodegenContext<LlvmCodegenBackend>) -> bool { cgcx.opts.target_triple.triple().contains("-aix") } -//FIXME use c string literals here too -pub(crate) fn bitcode_section_name(cgcx: &CodegenContext<LlvmCodegenBackend>) -> &'static str { +pub(crate) fn bitcode_section_name(cgcx: &CodegenContext<LlvmCodegenBackend>) -> &'static CStr { if target_is_apple(cgcx) { - "__LLVM,__bitcode\0" + c"__LLVM,__bitcode" } else if target_is_aix(cgcx) { - ".ipa\0" + c".ipa" } else { - ".llvmbc\0" + c".llvmbc" } } @@ -1041,9 +1041,8 @@ unsafe fn embed_bitcode( ); llvm::LLVMSetInitializer(llglobal, llconst); - let section = bitcode_section_name(cgcx); - llvm::LLVMSetSection(llglobal, section.as_ptr().cast()); - llvm::LLVMRustSetLinkage(llglobal, llvm::Linkage::PrivateLinkage); + llvm::set_section(llglobal, bitcode_section_name(cgcx)); + llvm::set_linkage(llglobal, llvm::Linkage::PrivateLinkage); llvm::LLVMSetGlobalConstant(llglobal, llvm::True); let llconst = common::bytes_in_context(llcx, cmdline.as_bytes()); @@ -1060,15 +1059,15 @@ unsafe fn embed_bitcode( } else { c".llvmcmd" }; - llvm::LLVMSetSection(llglobal, section.as_ptr()); - llvm::LLVMRustSetLinkage(llglobal, llvm::Linkage::PrivateLinkage); + llvm::set_section(llglobal, section); + llvm::set_linkage(llglobal, llvm::Linkage::PrivateLinkage); } else { // We need custom section flags, so emit module-level inline assembly. let section_flags = if cgcx.is_pe_coff { "n" } else { "e" }; let asm = create_section_with_flags_asm(".llvmbc", section_flags, bitcode); - llvm::LLVMAppendModuleInlineAsm(llmod, asm.as_ptr().cast(), asm.len()); + llvm::LLVMAppendModuleInlineAsm(llmod, asm.as_c_char_ptr(), asm.len()); let asm = create_section_with_flags_asm(".llvmcmd", section_flags, cmdline.as_bytes()); - llvm::LLVMAppendModuleInlineAsm(llmod, asm.as_ptr().cast(), asm.len()); + llvm::LLVMAppendModuleInlineAsm(llmod, asm.as_c_char_ptr(), asm.len()); } } } @@ -1096,7 +1095,7 @@ fn create_msvc_imps( let ptr_ty = Type::ptr_llcx(llcx); let globals = base::iter_globals(llmod) .filter(|&val| { - llvm::LLVMRustGetLinkage(val) == llvm::Linkage::ExternalLinkage + llvm::get_linkage(val) == llvm::Linkage::ExternalLinkage && llvm::LLVMIsDeclaration(val) == 0 }) .filter_map(|val| { @@ -1115,7 +1114,7 @@ fn create_msvc_imps( for (imp_name, val) in globals { let imp = llvm::LLVMAddGlobal(llmod, ptr_ty, imp_name.as_ptr()); llvm::LLVMSetInitializer(imp, val); - llvm::LLVMRustSetLinkage(imp, llvm::Linkage::ExternalLinkage); + llvm::set_linkage(imp, llvm::Linkage::ExternalLinkage); } } diff --git a/compiler/rustc_codegen_llvm/src/base.rs b/compiler/rustc_codegen_llvm/src/base.rs index 0ba8d82406a..32793894794 100644 --- a/compiler/rustc_codegen_llvm/src/base.rs +++ b/compiler/rustc_codegen_llvm/src/base.rs @@ -145,10 +145,8 @@ pub(crate) fn compile_codegen_unit( pub(crate) fn set_link_section(llval: &Value, attrs: &CodegenFnAttrs) { let Some(sect) = attrs.link_section else { return }; - unsafe { - let buf = SmallCStr::new(sect.as_str()); - llvm::LLVMSetSection(llval, buf.as_ptr()); - } + let buf = SmallCStr::new(sect.as_str()); + llvm::set_section(llval, &buf); } pub(crate) fn linkage_to_llvm(linkage: Linkage) -> llvm::Linkage { diff --git a/compiler/rustc_codegen_llvm/src/builder.rs b/compiler/rustc_codegen_llvm/src/builder.rs index 8702532c36e..f8eb3e0c982 100644 --- a/compiler/rustc_codegen_llvm/src/builder.rs +++ b/compiler/rustc_codegen_llvm/src/builder.rs @@ -239,7 +239,6 @@ impl<'a, 'll, 'tcx> BuilderMethods<'a, 'tcx> for Builder<'a, 'll, 'tcx> { let args = self.check_call("invoke", llty, llfn, args); let funclet_bundle = funclet.map(|funclet| funclet.bundle()); - let funclet_bundle = funclet_bundle.as_ref().map(|b| &*b.raw); let mut bundles: SmallVec<[_; 2]> = SmallVec::new(); if let Some(funclet_bundle) = funclet_bundle { bundles.push(funclet_bundle); @@ -250,13 +249,12 @@ impl<'a, 'll, 'tcx> BuilderMethods<'a, 'tcx> for Builder<'a, 'll, 'tcx> { // Emit KCFI operand bundle let kcfi_bundle = self.kcfi_operand_bundle(fn_attrs, fn_abi, instance, llfn); - let kcfi_bundle = kcfi_bundle.as_ref().map(|b| &*b.raw); - if let Some(kcfi_bundle) = kcfi_bundle { + if let Some(kcfi_bundle) = kcfi_bundle.as_deref() { bundles.push(kcfi_bundle); } let invoke = unsafe { - llvm::LLVMRustBuildInvoke( + llvm::LLVMBuildInvokeWithOperandBundles( self.llbuilder, llty, llfn, @@ -1179,7 +1177,6 @@ impl<'a, 'll, 'tcx> BuilderMethods<'a, 'tcx> for Builder<'a, 'll, 'tcx> { let args = self.check_call("call", llty, llfn, args); let funclet_bundle = funclet.map(|funclet| funclet.bundle()); - let funclet_bundle = funclet_bundle.as_ref().map(|b| &*b.raw); let mut bundles: SmallVec<[_; 2]> = SmallVec::new(); if let Some(funclet_bundle) = funclet_bundle { bundles.push(funclet_bundle); @@ -1190,13 +1187,12 @@ impl<'a, 'll, 'tcx> BuilderMethods<'a, 'tcx> for Builder<'a, 'll, 'tcx> { // Emit KCFI operand bundle let kcfi_bundle = self.kcfi_operand_bundle(fn_attrs, fn_abi, instance, llfn); - let kcfi_bundle = kcfi_bundle.as_ref().map(|b| &*b.raw); - if let Some(kcfi_bundle) = kcfi_bundle { + if let Some(kcfi_bundle) = kcfi_bundle.as_deref() { bundles.push(kcfi_bundle); } let call = unsafe { - llvm::LLVMRustBuildCall( + llvm::LLVMBuildCallWithOperandBundles( self.llbuilder, llty, llfn, @@ -1204,6 +1200,7 @@ impl<'a, 'll, 'tcx> BuilderMethods<'a, 'tcx> for Builder<'a, 'll, 'tcx> { args.len() as c_uint, bundles.as_ptr(), bundles.len() as c_uint, + c"".as_ptr(), ) }; if let Some(fn_abi) = fn_abi { @@ -1509,7 +1506,6 @@ impl<'a, 'll, 'tcx> Builder<'a, 'll, 'tcx> { let args = self.check_call("callbr", llty, llfn, args); let funclet_bundle = funclet.map(|funclet| funclet.bundle()); - let funclet_bundle = funclet_bundle.as_ref().map(|b| &*b.raw); let mut bundles: SmallVec<[_; 2]> = SmallVec::new(); if let Some(funclet_bundle) = funclet_bundle { bundles.push(funclet_bundle); @@ -1520,13 +1516,12 @@ impl<'a, 'll, 'tcx> Builder<'a, 'll, 'tcx> { // Emit KCFI operand bundle let kcfi_bundle = self.kcfi_operand_bundle(fn_attrs, fn_abi, instance, llfn); - let kcfi_bundle = kcfi_bundle.as_ref().map(|b| &*b.raw); - if let Some(kcfi_bundle) = kcfi_bundle { + if let Some(kcfi_bundle) = kcfi_bundle.as_deref() { bundles.push(kcfi_bundle); } let callbr = unsafe { - llvm::LLVMRustBuildCallBr( + llvm::LLVMBuildCallBr( self.llbuilder, llty, llfn, @@ -1601,7 +1596,7 @@ impl<'a, 'll, 'tcx> Builder<'a, 'll, 'tcx> { fn_abi: Option<&FnAbi<'tcx, Ty<'tcx>>>, instance: Option<Instance<'tcx>>, llfn: &'ll Value, - ) -> Option<llvm::OperandBundleDef<'ll>> { + ) -> Option<llvm::OperandBundleOwned<'ll>> { let is_indirect_call = unsafe { llvm::LLVMRustIsNonGVFunctionPointerTy(llfn) }; let kcfi_bundle = if self.tcx.sess.is_sanitizer_kcfi_enabled() && let Some(fn_abi) = fn_abi @@ -1627,7 +1622,7 @@ impl<'a, 'll, 'tcx> Builder<'a, 'll, 'tcx> { kcfi::typeid_for_fnabi(self.tcx, fn_abi, options) }; - Some(llvm::OperandBundleDef::new("kcfi", &[self.const_u32(kcfi_typeid)])) + Some(llvm::OperandBundleOwned::new("kcfi", &[self.const_u32(kcfi_typeid)])) } else { None }; diff --git a/compiler/rustc_codegen_llvm/src/callee.rs b/compiler/rustc_codegen_llvm/src/callee.rs index a51ef8d7b85..25037b97375 100644 --- a/compiler/rustc_codegen_llvm/src/callee.rs +++ b/compiler/rustc_codegen_llvm/src/callee.rs @@ -95,9 +95,9 @@ pub(crate) fn get_fn<'ll, 'tcx>(cx: &CodegenCx<'ll, 'tcx>, instance: Instance<'t // whether we are sharing generics or not. The important thing here is // that the visibility we apply to the declaration is the same one that // has been applied to the definition (wherever that definition may be). - unsafe { - llvm::LLVMRustSetLinkage(llfn, llvm::Linkage::ExternalLinkage); + llvm::set_linkage(llfn, llvm::Linkage::ExternalLinkage); + unsafe { let is_generic = instance.args.non_erasable_generics().next().is_some(); let is_hidden = if is_generic { @@ -135,7 +135,7 @@ pub(crate) fn get_fn<'ll, 'tcx>(cx: &CodegenCx<'ll, 'tcx>, instance: Instance<'t || !cx.tcx.is_reachable_non_generic(instance_def_id)) }; if is_hidden { - llvm::LLVMRustSetVisibility(llfn, llvm::Visibility::Hidden); + llvm::set_visibility(llfn, llvm::Visibility::Hidden); } // MinGW: For backward compatibility we rely on the linker to decide whether it diff --git a/compiler/rustc_codegen_llvm/src/common.rs b/compiler/rustc_codegen_llvm/src/common.rs index 0ced37b53a8..8852dec7d9f 100644 --- a/compiler/rustc_codegen_llvm/src/common.rs +++ b/compiler/rustc_codegen_llvm/src/common.rs @@ -17,7 +17,7 @@ use tracing::debug; use crate::consts::const_alloc_to_llvm; pub(crate) use crate::context::CodegenCx; -use crate::llvm::{self, BasicBlock, Bool, ConstantInt, False, Metadata, OperandBundleDef, True}; +use crate::llvm::{self, BasicBlock, Bool, ConstantInt, False, Metadata, True}; use crate::type_::Type; use crate::value::Value; @@ -63,19 +63,19 @@ use crate::value::Value; /// the `OperandBundleDef` value created for MSVC landing pads. pub(crate) struct Funclet<'ll> { cleanuppad: &'ll Value, - operand: OperandBundleDef<'ll>, + operand: llvm::OperandBundleOwned<'ll>, } impl<'ll> Funclet<'ll> { pub(crate) fn new(cleanuppad: &'ll Value) -> Self { - Funclet { cleanuppad, operand: OperandBundleDef::new("funclet", &[cleanuppad]) } + Funclet { cleanuppad, operand: llvm::OperandBundleOwned::new("funclet", &[cleanuppad]) } } pub(crate) fn cleanuppad(&self) -> &'ll Value { self.cleanuppad } - pub(crate) fn bundle(&self) -> &OperandBundleDef<'ll> { + pub(crate) fn bundle(&self) -> &llvm::OperandBundle<'ll> { &self.operand } } @@ -219,8 +219,8 @@ impl<'ll, 'tcx> ConstCodegenMethods<'tcx> for CodegenCx<'ll, 'tcx> { llvm::LLVMSetInitializer(g, sc); llvm::LLVMSetGlobalConstant(g, True); llvm::LLVMSetUnnamedAddress(g, llvm::UnnamedAddr::Global); - llvm::LLVMRustSetLinkage(g, llvm::Linkage::InternalLinkage); } + llvm::set_linkage(g, llvm::Linkage::InternalLinkage); (s.to_owned(), g) }) .1; @@ -392,3 +392,21 @@ pub(crate) fn get_dllimport<'tcx>( tcx.native_library(id) .and_then(|lib| lib.dll_imports.iter().find(|di| di.name.as_str() == name)) } + +/// Extension trait for explicit casts to `*const c_char`. +pub(crate) trait AsCCharPtr { + /// Equivalent to `self.as_ptr().cast()`, but only casts to `*const c_char`. + fn as_c_char_ptr(&self) -> *const c_char; +} + +impl AsCCharPtr for str { + fn as_c_char_ptr(&self) -> *const c_char { + self.as_ptr().cast() + } +} + +impl AsCCharPtr for [u8] { + fn as_c_char_ptr(&self) -> *const c_char { + self.as_ptr().cast() + } +} diff --git a/compiler/rustc_codegen_llvm/src/consts.rs b/compiler/rustc_codegen_llvm/src/consts.rs index 33a85adeb87..21d996ef460 100644 --- a/compiler/rustc_codegen_llvm/src/consts.rs +++ b/compiler/rustc_codegen_llvm/src/consts.rs @@ -19,7 +19,7 @@ use rustc_target::abi::{ }; use tracing::{debug, instrument, trace}; -use crate::common::CodegenCx; +use crate::common::{AsCCharPtr, CodegenCx}; use crate::errors::{ InvalidMinimumAlignmentNotPowerOfTwo, InvalidMinimumAlignmentTooLarge, SymbolAlreadyDefined, }; @@ -172,29 +172,27 @@ fn check_and_apply_linkage<'ll, 'tcx>( if let Some(linkage) = attrs.import_linkage { debug!("get_static: sym={} linkage={:?}", sym, linkage); - unsafe { - // Declare a symbol `foo` with the desired linkage. - let g1 = cx.declare_global(sym, cx.type_i8()); - llvm::LLVMRustSetLinkage(g1, base::linkage_to_llvm(linkage)); - - // Declare an internal global `extern_with_linkage_foo` which - // is initialized with the address of `foo`. If `foo` is - // discarded during linking (for example, if `foo` has weak - // linkage and there are no definitions), then - // `extern_with_linkage_foo` will instead be initialized to - // zero. - let mut real_name = "_rust_extern_with_linkage_".to_string(); - real_name.push_str(sym); - let g2 = cx.define_global(&real_name, llty).unwrap_or_else(|| { - cx.sess().dcx().emit_fatal(SymbolAlreadyDefined { - span: cx.tcx.def_span(def_id), - symbol_name: sym, - }) - }); - llvm::LLVMRustSetLinkage(g2, llvm::Linkage::InternalLinkage); - llvm::LLVMSetInitializer(g2, g1); - g2 - } + // Declare a symbol `foo` with the desired linkage. + let g1 = cx.declare_global(sym, cx.type_i8()); + llvm::set_linkage(g1, base::linkage_to_llvm(linkage)); + + // Declare an internal global `extern_with_linkage_foo` which + // is initialized with the address of `foo`. If `foo` is + // discarded during linking (for example, if `foo` has weak + // linkage and there are no definitions), then + // `extern_with_linkage_foo` will instead be initialized to + // zero. + let mut real_name = "_rust_extern_with_linkage_".to_string(); + real_name.push_str(sym); + let g2 = cx.define_global(&real_name, llty).unwrap_or_else(|| { + cx.sess().dcx().emit_fatal(SymbolAlreadyDefined { + span: cx.tcx.def_span(def_id), + symbol_name: sym, + }) + }); + llvm::set_linkage(g2, llvm::Linkage::InternalLinkage); + unsafe { llvm::LLVMSetInitializer(g2, g1) }; + g2 } else if cx.tcx.sess.target.arch == "x86" && let Some(dllimport) = crate::common::get_dllimport(cx.tcx, def_id, sym) { @@ -224,23 +222,21 @@ impl<'ll> CodegenCx<'ll, '_> { align: Align, kind: Option<&str>, ) -> &'ll Value { - unsafe { - let gv = match kind { - Some(kind) if !self.tcx.sess.fewer_names() => { - let name = self.generate_local_symbol_name(kind); - let gv = self.define_global(&name, self.val_ty(cv)).unwrap_or_else(|| { - bug!("symbol `{}` is already defined", name); - }); - llvm::LLVMRustSetLinkage(gv, llvm::Linkage::PrivateLinkage); - gv - } - _ => self.define_private_global(self.val_ty(cv)), - }; - llvm::LLVMSetInitializer(gv, cv); - set_global_alignment(self, gv, align); - llvm::SetUnnamedAddress(gv, llvm::UnnamedAddr::Global); - gv - } + let gv = match kind { + Some(kind) if !self.tcx.sess.fewer_names() => { + let name = self.generate_local_symbol_name(kind); + let gv = self.define_global(&name, self.val_ty(cv)).unwrap_or_else(|| { + bug!("symbol `{}` is already defined", name); + }); + llvm::set_linkage(gv, llvm::Linkage::PrivateLinkage); + gv + } + _ => self.define_private_global(self.val_ty(cv)), + }; + unsafe { llvm::LLVMSetInitializer(gv, cv) }; + set_global_alignment(self, gv, align); + llvm::SetUnnamedAddress(gv, llvm::UnnamedAddr::Global); + gv } #[instrument(level = "debug", skip(self))] @@ -292,9 +288,7 @@ impl<'ll> CodegenCx<'ll, '_> { let g = self.declare_global(sym, llty); if !self.tcx.is_reachable_non_generic(def_id) { - unsafe { - llvm::LLVMRustSetVisibility(g, llvm::Visibility::Hidden); - } + llvm::set_visibility(g, llvm::Visibility::Hidden); } g @@ -312,7 +306,7 @@ impl<'ll> CodegenCx<'ll, '_> { llvm::set_thread_local_mode(g, self.tls_model); } - let dso_local = unsafe { self.should_assume_dso_local(g, true) }; + let dso_local = self.should_assume_dso_local(g, true); if dso_local { unsafe { llvm::LLVMRustSetDSOLocal(g, true); @@ -401,18 +395,18 @@ impl<'ll> CodegenCx<'ll, '_> { let name = llvm::get_value_name(g).to_vec(); llvm::set_value_name(g, b""); - let linkage = llvm::LLVMRustGetLinkage(g); - let visibility = llvm::LLVMRustGetVisibility(g); + let linkage = llvm::get_linkage(g); + let visibility = llvm::get_visibility(g); let new_g = llvm::LLVMRustGetOrInsertGlobal( self.llmod, - name.as_ptr().cast(), + name.as_c_char_ptr(), name.len(), val_llty, ); - llvm::LLVMRustSetLinkage(new_g, linkage); - llvm::LLVMRustSetVisibility(new_g, visibility); + llvm::set_linkage(new_g, linkage); + llvm::set_visibility(new_g, visibility); // The old global has had its name removed but is returned by // get_static since it is in the instance cache. Provide an @@ -457,7 +451,7 @@ impl<'ll> CodegenCx<'ll, '_> { if let Some(section) = attrs.link_section { let section = llvm::LLVMMDStringInContext2( self.llcx, - section.as_str().as_ptr().cast(), + section.as_str().as_c_char_ptr(), section.as_str().len(), ); assert!(alloc.provenance().ptrs().is_empty()); @@ -468,7 +462,7 @@ impl<'ll> CodegenCx<'ll, '_> { let bytes = alloc.inspect_with_uninit_and_ptr_outside_interpreter(0..alloc.len()); let alloc = - llvm::LLVMMDStringInContext2(self.llcx, bytes.as_ptr().cast(), bytes.len()); + llvm::LLVMMDStringInContext2(self.llcx, bytes.as_c_char_ptr(), bytes.len()); let data = [section, alloc]; let meta = llvm::LLVMMDNodeInContext2(self.llcx, data.as_ptr(), data.len()); let val = llvm::LLVMMetadataAsValue(self.llcx, meta); diff --git a/compiler/rustc_codegen_llvm/src/context.rs b/compiler/rustc_codegen_llvm/src/context.rs index 3fc153c6cd4..9778ff4918c 100644 --- a/compiler/rustc_codegen_llvm/src/context.rs +++ b/compiler/rustc_codegen_llvm/src/context.rs @@ -29,6 +29,7 @@ use smallvec::SmallVec; use crate::back::write::to_llvm_code_model; use crate::callee::get_fn; +use crate::common::AsCCharPtr; use crate::debuginfo::metadata::apply_vcall_visibility_metadata; use crate::llvm::{Metadata, MetadataType}; use crate::type_::Type; @@ -209,133 +210,111 @@ pub(crate) unsafe fn create_module<'ll>( // If skipping the PLT is enabled, we need to add some module metadata // to ensure intrinsic calls don't use it. if !sess.needs_plt() { - let avoid_plt = c"RtLibUseGOT".as_ptr(); - unsafe { - llvm::LLVMRustAddModuleFlagU32(llmod, llvm::LLVMModFlagBehavior::Warning, avoid_plt, 1); - } + llvm::add_module_flag_u32(llmod, llvm::ModuleFlagMergeBehavior::Warning, "RtLibUseGOT", 1); } // Enable canonical jump tables if CFI is enabled. (See https://reviews.llvm.org/D65629.) if sess.is_sanitizer_cfi_canonical_jump_tables_enabled() && sess.is_sanitizer_cfi_enabled() { - let canonical_jump_tables = c"CFI Canonical Jump Tables".as_ptr(); - unsafe { - llvm::LLVMRustAddModuleFlagU32( - llmod, - llvm::LLVMModFlagBehavior::Override, - canonical_jump_tables, - 1, - ); - } + llvm::add_module_flag_u32( + llmod, + llvm::ModuleFlagMergeBehavior::Override, + "CFI Canonical Jump Tables", + 1, + ); } // If we're normalizing integers with CFI, ensure LLVM generated functions do the same. // See https://github.com/llvm/llvm-project/pull/104826 if sess.is_sanitizer_cfi_normalize_integers_enabled() { - let cfi_normalize_integers = c"cfi-normalize-integers".as_ptr().cast(); - unsafe { - llvm::LLVMRustAddModuleFlagU32( - llmod, - llvm::LLVMModFlagBehavior::Override, - cfi_normalize_integers, - 1, - ); - } + llvm::add_module_flag_u32( + llmod, + llvm::ModuleFlagMergeBehavior::Override, + "cfi-normalize-integers", + 1, + ); } // Enable LTO unit splitting if specified or if CFI is enabled. (See // https://reviews.llvm.org/D53891.) if sess.is_split_lto_unit_enabled() || sess.is_sanitizer_cfi_enabled() { - let enable_split_lto_unit = c"EnableSplitLTOUnit".as_ptr(); - unsafe { - llvm::LLVMRustAddModuleFlagU32( - llmod, - llvm::LLVMModFlagBehavior::Override, - enable_split_lto_unit, - 1, - ); - } + llvm::add_module_flag_u32( + llmod, + llvm::ModuleFlagMergeBehavior::Override, + "EnableSplitLTOUnit", + 1, + ); } // Add "kcfi" module flag if KCFI is enabled. (See https://reviews.llvm.org/D119296.) if sess.is_sanitizer_kcfi_enabled() { - let kcfi = c"kcfi".as_ptr(); - unsafe { - llvm::LLVMRustAddModuleFlagU32(llmod, llvm::LLVMModFlagBehavior::Override, kcfi, 1); - } + llvm::add_module_flag_u32(llmod, llvm::ModuleFlagMergeBehavior::Override, "kcfi", 1); // Add "kcfi-offset" module flag with -Z patchable-function-entry (See // https://reviews.llvm.org/D141172). let pfe = PatchableFunctionEntry::from_config(sess.opts.unstable_opts.patchable_function_entry); if pfe.prefix() > 0 { - let kcfi_offset = c"kcfi-offset".as_ptr().cast(); - unsafe { - llvm::LLVMRustAddModuleFlagU32( - llmod, - llvm::LLVMModFlagBehavior::Override, - kcfi_offset, - pfe.prefix().into(), - ); - } + llvm::add_module_flag_u32( + llmod, + llvm::ModuleFlagMergeBehavior::Override, + "kcfi-offset", + pfe.prefix().into(), + ); } } // Control Flow Guard is currently only supported by the MSVC linker on Windows. if sess.target.is_like_msvc { - unsafe { - match sess.opts.cg.control_flow_guard { - CFGuard::Disabled => {} - CFGuard::NoChecks => { - // Set `cfguard=1` module flag to emit metadata only. - llvm::LLVMRustAddModuleFlagU32( - llmod, - llvm::LLVMModFlagBehavior::Warning, - c"cfguard".as_ptr() as *const _, - 1, - ) - } - CFGuard::Checks => { - // Set `cfguard=2` module flag to emit metadata and checks. - llvm::LLVMRustAddModuleFlagU32( - llmod, - llvm::LLVMModFlagBehavior::Warning, - c"cfguard".as_ptr() as *const _, - 2, - ) - } + match sess.opts.cg.control_flow_guard { + CFGuard::Disabled => {} + CFGuard::NoChecks => { + // Set `cfguard=1` module flag to emit metadata only. + llvm::add_module_flag_u32( + llmod, + llvm::ModuleFlagMergeBehavior::Warning, + "cfguard", + 1, + ); + } + CFGuard::Checks => { + // Set `cfguard=2` module flag to emit metadata and checks. + llvm::add_module_flag_u32( + llmod, + llvm::ModuleFlagMergeBehavior::Warning, + "cfguard", + 2, + ); } } } if let Some(BranchProtection { bti, pac_ret }) = sess.opts.unstable_opts.branch_protection { if sess.target.arch == "aarch64" { - unsafe { - llvm::LLVMRustAddModuleFlagU32( - llmod, - llvm::LLVMModFlagBehavior::Min, - c"branch-target-enforcement".as_ptr(), - bti.into(), - ); - llvm::LLVMRustAddModuleFlagU32( - llmod, - llvm::LLVMModFlagBehavior::Min, - c"sign-return-address".as_ptr(), - pac_ret.is_some().into(), - ); - let pac_opts = pac_ret.unwrap_or(PacRet { leaf: false, key: PAuthKey::A }); - llvm::LLVMRustAddModuleFlagU32( - llmod, - llvm::LLVMModFlagBehavior::Min, - c"sign-return-address-all".as_ptr(), - pac_opts.leaf.into(), - ); - llvm::LLVMRustAddModuleFlagU32( - llmod, - llvm::LLVMModFlagBehavior::Min, - c"sign-return-address-with-bkey".as_ptr(), - u32::from(pac_opts.key == PAuthKey::B), - ); - } + llvm::add_module_flag_u32( + llmod, + llvm::ModuleFlagMergeBehavior::Min, + "branch-target-enforcement", + bti.into(), + ); + llvm::add_module_flag_u32( + llmod, + llvm::ModuleFlagMergeBehavior::Min, + "sign-return-address", + pac_ret.is_some().into(), + ); + let pac_opts = pac_ret.unwrap_or(PacRet { leaf: false, key: PAuthKey::A }); + llvm::add_module_flag_u32( + llmod, + llvm::ModuleFlagMergeBehavior::Min, + "sign-return-address-all", + pac_opts.leaf.into(), + ); + llvm::add_module_flag_u32( + llmod, + llvm::ModuleFlagMergeBehavior::Min, + "sign-return-address-with-bkey", + u32::from(pac_opts.key == PAuthKey::B), + ); } else { bug!( "branch-protection used on non-AArch64 target; \ @@ -346,59 +325,46 @@ pub(crate) unsafe fn create_module<'ll>( // Pass on the control-flow protection flags to LLVM (equivalent to `-fcf-protection` in Clang). if let CFProtection::Branch | CFProtection::Full = sess.opts.unstable_opts.cf_protection { - unsafe { - llvm::LLVMRustAddModuleFlagU32( - llmod, - llvm::LLVMModFlagBehavior::Override, - c"cf-protection-branch".as_ptr(), - 1, - ); - } + llvm::add_module_flag_u32( + llmod, + llvm::ModuleFlagMergeBehavior::Override, + "cf-protection-branch", + 1, + ); } if let CFProtection::Return | CFProtection::Full = sess.opts.unstable_opts.cf_protection { - unsafe { - llvm::LLVMRustAddModuleFlagU32( - llmod, - llvm::LLVMModFlagBehavior::Override, - c"cf-protection-return".as_ptr(), - 1, - ); - } + llvm::add_module_flag_u32( + llmod, + llvm::ModuleFlagMergeBehavior::Override, + "cf-protection-return", + 1, + ); } if sess.opts.unstable_opts.virtual_function_elimination { - unsafe { - llvm::LLVMRustAddModuleFlagU32( - llmod, - llvm::LLVMModFlagBehavior::Error, - c"Virtual Function Elim".as_ptr(), - 1, - ); - } + llvm::add_module_flag_u32( + llmod, + llvm::ModuleFlagMergeBehavior::Error, + "Virtual Function Elim", + 1, + ); } // Set module flag to enable Windows EHCont Guard (/guard:ehcont). if sess.opts.unstable_opts.ehcont_guard { - unsafe { - llvm::LLVMRustAddModuleFlagU32( - llmod, - llvm::LLVMModFlagBehavior::Warning, - c"ehcontguard".as_ptr() as *const _, - 1, - ) - } + llvm::add_module_flag_u32(llmod, llvm::ModuleFlagMergeBehavior::Warning, "ehcontguard", 1); } match sess.opts.unstable_opts.function_return { FunctionReturn::Keep => {} - FunctionReturn::ThunkExtern => unsafe { - llvm::LLVMRustAddModuleFlagU32( + FunctionReturn::ThunkExtern => { + llvm::add_module_flag_u32( llmod, - llvm::LLVMModFlagBehavior::Override, - c"function_return_thunk_extern".as_ptr(), + llvm::ModuleFlagMergeBehavior::Override, + "function_return_thunk_extern", 1, - ) - }, + ); + } } match (sess.opts.unstable_opts.small_data_threshold, sess.target.small_data_threshold_support()) @@ -406,15 +372,12 @@ pub(crate) unsafe fn create_module<'ll>( // Set up the small-data optimization limit for architectures that use // an LLVM module flag to control this. (Some(threshold), SmallDataThresholdSupport::LlvmModuleFlag(flag)) => { - let flag = SmallCStr::new(flag.as_ref()); - unsafe { - llvm::LLVMRustAddModuleFlagU32( - llmod, - llvm::LLVMModFlagBehavior::Error, - flag.as_c_str().as_ptr(), - threshold as u32, - ) - } + llvm::add_module_flag_u32( + llmod, + llvm::ModuleFlagMergeBehavior::Error, + &flag, + threshold as u32, + ); } _ => (), }; @@ -429,7 +392,7 @@ pub(crate) unsafe fn create_module<'ll>( let name_metadata = unsafe { llvm::LLVMMDStringInContext2( llcx, - rustc_producer.as_ptr().cast(), + rustc_producer.as_c_char_ptr(), rustc_producer.as_bytes().len(), ) }; @@ -448,33 +411,29 @@ pub(crate) unsafe fn create_module<'ll>( // If llvm_abiname is empty, emit nothing. let llvm_abiname = &sess.target.options.llvm_abiname; if matches!(sess.target.arch.as_ref(), "riscv32" | "riscv64") && !llvm_abiname.is_empty() { - unsafe { - llvm::LLVMRustAddModuleFlagString( - llmod, - llvm::LLVMModFlagBehavior::Error, - c"target-abi".as_ptr(), - llvm_abiname.as_ptr().cast(), - llvm_abiname.len(), - ); - } + llvm::add_module_flag_str( + llmod, + llvm::ModuleFlagMergeBehavior::Error, + "target-abi", + llvm_abiname, + ); } // Add module flags specified via -Z llvm_module_flag - for (key, value, behavior) in &sess.opts.unstable_opts.llvm_module_flag { - let key = format!("{key}\0"); - let behavior = match behavior.as_str() { - "error" => llvm::LLVMModFlagBehavior::Error, - "warning" => llvm::LLVMModFlagBehavior::Warning, - "require" => llvm::LLVMModFlagBehavior::Require, - "override" => llvm::LLVMModFlagBehavior::Override, - "append" => llvm::LLVMModFlagBehavior::Append, - "appendunique" => llvm::LLVMModFlagBehavior::AppendUnique, - "max" => llvm::LLVMModFlagBehavior::Max, - "min" => llvm::LLVMModFlagBehavior::Min, + for (key, value, merge_behavior) in &sess.opts.unstable_opts.llvm_module_flag { + let merge_behavior = match merge_behavior.as_str() { + "error" => llvm::ModuleFlagMergeBehavior::Error, + "warning" => llvm::ModuleFlagMergeBehavior::Warning, + "require" => llvm::ModuleFlagMergeBehavior::Require, + "override" => llvm::ModuleFlagMergeBehavior::Override, + "append" => llvm::ModuleFlagMergeBehavior::Append, + "appendunique" => llvm::ModuleFlagMergeBehavior::AppendUnique, + "max" => llvm::ModuleFlagMergeBehavior::Max, + "min" => llvm::ModuleFlagMergeBehavior::Min, // We already checked this during option parsing _ => unreachable!(), }; - unsafe { llvm::LLVMRustAddModuleFlagU32(llmod, behavior, key.as_ptr().cast(), *value) } + llvm::add_module_flag_u32(llmod, merge_behavior, key, *value); } llmod @@ -605,8 +564,8 @@ impl<'ll, 'tcx> CodegenCx<'ll, 'tcx> { unsafe { let g = llvm::LLVMAddGlobal(self.llmod, self.val_ty(array), name.as_ptr()); llvm::LLVMSetInitializer(g, array); - llvm::LLVMRustSetLinkage(g, llvm::Linkage::AppendingLinkage); - llvm::LLVMSetSection(g, c"llvm.metadata".as_ptr()); + llvm::set_linkage(g, llvm::Linkage::AppendingLinkage); + llvm::set_section(g, c"llvm.metadata"); } } } diff --git a/compiler/rustc_codegen_llvm/src/coverageinfo/mod.rs b/compiler/rustc_codegen_llvm/src/coverageinfo/mod.rs index c6b2a623ea6..a298ed86276 100644 --- a/compiler/rustc_codegen_llvm/src/coverageinfo/mod.rs +++ b/compiler/rustc_codegen_llvm/src/coverageinfo/mod.rs @@ -14,7 +14,7 @@ use rustc_target::abi::Size; use tracing::{debug, instrument}; use crate::builder::Builder; -use crate::common::CodegenCx; +use crate::common::{AsCCharPtr, CodegenCx}; use crate::coverageinfo::map_data::FunctionCoverageCollector; use crate::llvm; @@ -236,7 +236,7 @@ fn create_pgo_func_name_var<'ll, 'tcx>( unsafe { llvm::LLVMRustCoverageCreatePGOFuncNameVar( llfn, - mangled_fn_name.as_ptr().cast(), + mangled_fn_name.as_c_char_ptr(), mangled_fn_name.len(), ) } @@ -248,7 +248,7 @@ pub(crate) fn write_filenames_section_to_buffer<'a>( ) { let (pointers, lengths) = filenames .into_iter() - .map(|s: &str| (s.as_ptr().cast(), s.len())) + .map(|s: &str| (s.as_c_char_ptr(), s.len())) .unzip::<_, _, Vec<_>, Vec<_>>(); unsafe { @@ -291,7 +291,7 @@ pub(crate) fn write_mapping_to_buffer( } pub(crate) fn hash_bytes(bytes: &[u8]) -> u64 { - unsafe { llvm::LLVMRustCoverageHashByteArray(bytes.as_ptr().cast(), bytes.len()) } + unsafe { llvm::LLVMRustCoverageHashByteArray(bytes.as_c_char_ptr(), bytes.len()) } } pub(crate) fn mapping_version() -> u32 { diff --git a/compiler/rustc_codegen_llvm/src/debuginfo/gdb.rs b/compiler/rustc_codegen_llvm/src/debuginfo/gdb.rs index f93d3e40b20..aef8642f199 100644 --- a/compiler/rustc_codegen_llvm/src/debuginfo/gdb.rs +++ b/compiler/rustc_codegen_llvm/src/debuginfo/gdb.rs @@ -72,11 +72,11 @@ pub(crate) fn get_or_insert_gdb_debug_scripts_section_global<'ll>( let section_var = cx .define_global(section_var_name, llvm_type) .unwrap_or_else(|| bug!("symbol `{}` is already defined", section_var_name)); - llvm::LLVMSetSection(section_var, c".debug_gdb_scripts".as_ptr()); + llvm::set_section(section_var, c".debug_gdb_scripts"); llvm::LLVMSetInitializer(section_var, cx.const_bytes(section_contents)); llvm::LLVMSetGlobalConstant(section_var, llvm::True); llvm::LLVMSetUnnamedAddress(section_var, llvm::UnnamedAddr::Global); - llvm::LLVMRustSetLinkage(section_var, llvm::Linkage::LinkOnceODRLinkage); + llvm::set_linkage(section_var, llvm::Linkage::LinkOnceODRLinkage); // This should make sure that the whole section is not larger than // the string it contains. Otherwise we get a warning from GDB. llvm::LLVMSetAlignment(section_var, 1); diff --git a/compiler/rustc_codegen_llvm/src/debuginfo/metadata.rs b/compiler/rustc_codegen_llvm/src/debuginfo/metadata.rs index 15d441a986d..9064cfaeb29 100644 --- a/compiler/rustc_codegen_llvm/src/debuginfo/metadata.rs +++ b/compiler/rustc_codegen_llvm/src/debuginfo/metadata.rs @@ -32,7 +32,7 @@ use super::type_names::{compute_debuginfo_type_name, compute_debuginfo_vtable_na use super::utils::{ DIB, create_DIArray, debug_context, get_namespace_for_item, is_node_local_to_unit, }; -use crate::common::CodegenCx; +use crate::common::{AsCCharPtr, CodegenCx}; use crate::debuginfo::metadata::type_map::build_type_with_children; use crate::debuginfo::utils::{WidePtrKind, wide_pointer_kind}; use crate::llvm::debuginfo::{ @@ -190,7 +190,7 @@ fn build_pointer_or_reference_di_node<'ll, 'tcx>( data_layout.pointer_size.bits(), data_layout.pointer_align.abi.bits() as u32, 0, // Ignore DWARF address space. - ptr_type_debuginfo_name.as_ptr().cast(), + ptr_type_debuginfo_name.as_c_char_ptr(), ptr_type_debuginfo_name.len(), ) }; @@ -348,7 +348,7 @@ fn build_subroutine_type_di_node<'ll, 'tcx>( size, align, 0, // Ignore DWARF address space. - name.as_ptr().cast(), + name.as_c_char_ptr(), name.len(), ) }; @@ -518,7 +518,7 @@ fn recursion_marker_type_di_node<'ll, 'tcx>(cx: &CodegenCx<'ll, 'tcx>) -> &'ll D let name = "<recur_type>"; llvm::LLVMRustDIBuilderCreateBasicType( DIB(cx), - name.as_ptr().cast(), + name.as_c_char_ptr(), name.len(), cx.tcx.data_layout.pointer_size.bits(), DW_ATE_unsigned, @@ -640,14 +640,14 @@ pub(crate) fn file_metadata<'ll>(cx: &CodegenCx<'ll, '_>, source_file: &SourceFi unsafe { llvm::LLVMRustDIBuilderCreateFile( DIB(cx), - file_name.as_ptr().cast(), + file_name.as_c_char_ptr(), file_name.len(), - directory.as_ptr().cast(), + directory.as_c_char_ptr(), directory.len(), hash_kind, - hash_value.as_ptr().cast(), + hash_value.as_c_char_ptr(), hash_value.len(), - source.map_or(ptr::null(), |x| x.as_ptr().cast()), + source.map_or(ptr::null(), |x| x.as_c_char_ptr()), source.map_or(0, |x| x.len()), ) } @@ -662,12 +662,12 @@ fn unknown_file_metadata<'ll>(cx: &CodegenCx<'ll, '_>) -> &'ll DIFile { llvm::LLVMRustDIBuilderCreateFile( DIB(cx), - file_name.as_ptr().cast(), + file_name.as_c_char_ptr(), file_name.len(), - directory.as_ptr().cast(), + directory.as_c_char_ptr(), directory.len(), llvm::ChecksumKind::None, - hash_value.as_ptr().cast(), + hash_value.as_c_char_ptr(), hash_value.len(), ptr::null(), 0, @@ -788,7 +788,7 @@ fn build_basic_type_di_node<'ll, 'tcx>( let ty_di_node = unsafe { llvm::LLVMRustDIBuilderCreateBasicType( DIB(cx), - name.as_ptr().cast(), + name.as_c_char_ptr(), name.len(), cx.size_of(t).bits(), encoding, @@ -810,7 +810,7 @@ fn build_basic_type_di_node<'ll, 'tcx>( llvm::LLVMRustDIBuilderCreateTypedef( DIB(cx), ty_di_node, - typedef_name.as_ptr().cast(), + typedef_name.as_c_char_ptr(), typedef_name.len(), unknown_file_metadata(cx), 0, @@ -861,7 +861,7 @@ fn build_param_type_di_node<'ll, 'tcx>( di_node: unsafe { llvm::LLVMRustDIBuilderCreateBasicType( DIB(cx), - name.as_ptr().cast(), + name.as_c_char_ptr(), name.len(), Size::ZERO.bits(), DW_ATE_unsigned, @@ -948,9 +948,9 @@ pub(crate) fn build_compile_unit_di_node<'ll, 'tcx>( unsafe { let compile_unit_file = llvm::LLVMRustDIBuilderCreateFile( debug_context.builder, - name_in_debuginfo.as_ptr().cast(), + name_in_debuginfo.as_c_char_ptr(), name_in_debuginfo.len(), - work_dir.as_ptr().cast(), + work_dir.as_c_char_ptr(), work_dir.len(), llvm::ChecksumKind::None, ptr::null(), @@ -963,7 +963,7 @@ pub(crate) fn build_compile_unit_di_node<'ll, 'tcx>( debug_context.builder, DW_LANG_RUST, compile_unit_file, - producer.as_ptr().cast(), + producer.as_c_char_ptr(), producer.len(), tcx.sess.opts.optimize != config::OptLevel::No, c"".as_ptr(), @@ -971,7 +971,7 @@ pub(crate) fn build_compile_unit_di_node<'ll, 'tcx>( // NB: this doesn't actually have any perceptible effect, it seems. LLVM will instead // put the path supplied to `MCSplitDwarfFile` into the debug info of the final // output(s). - split_name.as_ptr().cast(), + split_name.as_c_char_ptr(), split_name.len(), kind, 0, @@ -1022,7 +1022,7 @@ fn build_field_di_node<'ll, 'tcx>( llvm::LLVMRustDIBuilderCreateMemberType( DIB(cx), owner, - name.as_ptr().cast(), + name.as_c_char_ptr(), name.len(), unknown_file_metadata(cx), UNKNOWN_LINE_NUMBER, @@ -1306,7 +1306,7 @@ fn build_generic_type_param_di_nodes<'ll, 'tcx>( llvm::LLVMRustDIBuilderCreateTemplateTypeParameter( DIB(cx), None, - name.as_ptr().cast(), + name.as_c_char_ptr(), name.len(), actual_type_di_node, ) @@ -1382,9 +1382,9 @@ pub(crate) fn build_global_var_di_node<'ll>( llvm::LLVMRustDIBuilderCreateStaticVariable( DIB(cx), Some(var_scope), - var_name.as_ptr().cast(), + var_name.as_c_char_ptr(), var_name.len(), - linkage_name.as_ptr().cast(), + linkage_name.as_c_char_ptr(), linkage_name.len(), file_metadata, line_number, @@ -1602,9 +1602,9 @@ pub(crate) fn create_vtable_di_node<'ll, 'tcx>( llvm::LLVMRustDIBuilderCreateStaticVariable( DIB(cx), NO_SCOPE_METADATA, - vtable_name.as_ptr().cast(), + vtable_name.as_c_char_ptr(), vtable_name.len(), - linkage_name.as_ptr().cast(), + linkage_name.as_c_char_ptr(), linkage_name.len(), unknown_file_metadata(cx), UNKNOWN_LINE_NUMBER, diff --git a/compiler/rustc_codegen_llvm/src/debuginfo/metadata/enums/cpp_like.rs b/compiler/rustc_codegen_llvm/src/debuginfo/metadata/enums/cpp_like.rs index 966788cf32f..5385d3a9212 100644 --- a/compiler/rustc_codegen_llvm/src/debuginfo/metadata/enums/cpp_like.rs +++ b/compiler/rustc_codegen_llvm/src/debuginfo/metadata/enums/cpp_like.rs @@ -11,7 +11,7 @@ use rustc_middle::ty::{self, AdtDef, CoroutineArgs, CoroutineArgsExt, Ty}; use rustc_target::abi::{Align, Endian, Size, TagEncoding, VariantIdx, Variants}; use smallvec::smallvec; -use crate::common::CodegenCx; +use crate::common::{AsCCharPtr, CodegenCx}; use crate::debuginfo::metadata::enums::DiscrResult; use crate::debuginfo::metadata::type_map::{self, Stub, UniqueTypeId}; use crate::debuginfo::metadata::{ @@ -359,7 +359,7 @@ fn build_single_variant_union_fields<'ll, 'tcx>( llvm::LLVMRustDIBuilderCreateStaticMemberType( DIB(cx), enum_type_di_node, - TAG_FIELD_NAME.as_ptr().cast(), + TAG_FIELD_NAME.as_c_char_ptr(), TAG_FIELD_NAME.len(), unknown_file_metadata(cx), UNKNOWN_LINE_NUMBER, @@ -537,7 +537,7 @@ fn build_variant_struct_wrapper_type_di_node<'ll, 'tcx>( llvm::LLVMRustDIBuilderCreateStaticMemberType( DIB(cx), wrapper_struct_type_di_node, - name.as_ptr().cast(), + name.as_c_char_ptr(), name.len(), unknown_file_metadata(cx), UNKNOWN_LINE_NUMBER, @@ -785,7 +785,7 @@ fn build_union_fields_for_direct_tag_enum_or_coroutine<'ll, 'tcx>( llvm::LLVMRustDIBuilderCreateMemberType( DIB(cx), enum_type_di_node, - field_name.as_ptr().cast(), + field_name.as_c_char_ptr(), field_name.len(), file_di_node, line_number, diff --git a/compiler/rustc_codegen_llvm/src/debuginfo/metadata/enums/mod.rs b/compiler/rustc_codegen_llvm/src/debuginfo/metadata/enums/mod.rs index fe1634146ff..4c848027b55 100644 --- a/compiler/rustc_codegen_llvm/src/debuginfo/metadata/enums/mod.rs +++ b/compiler/rustc_codegen_llvm/src/debuginfo/metadata/enums/mod.rs @@ -13,7 +13,7 @@ use rustc_target::abi::{FieldIdx, TagEncoding, VariantIdx, Variants}; use super::type_map::{DINodeCreationResult, UniqueTypeId}; use super::{SmallVec, size_and_align_of}; -use crate::common::CodegenCx; +use crate::common::{AsCCharPtr, CodegenCx}; use crate::debuginfo::metadata::type_map::{self, Stub}; use crate::debuginfo::metadata::{ UNKNOWN_LINE_NUMBER, build_field_di_node, build_generic_type_param_di_nodes, type_di_node, @@ -106,7 +106,7 @@ fn build_enumeration_type_di_node<'ll, 'tcx>( let value = [value as u64, (value >> 64) as u64]; Some(llvm::LLVMRustDIBuilderCreateEnumerator( DIB(cx), - name.as_ptr().cast(), + name.as_c_char_ptr(), name.len(), value.as_ptr(), size.bits() as libc::c_uint, @@ -119,7 +119,7 @@ fn build_enumeration_type_di_node<'ll, 'tcx>( llvm::LLVMRustDIBuilderCreateEnumerationType( DIB(cx), containing_scope, - type_name.as_ptr().cast(), + type_name.as_c_char_ptr(), type_name.len(), unknown_file_metadata(cx), UNKNOWN_LINE_NUMBER, diff --git a/compiler/rustc_codegen_llvm/src/debuginfo/metadata/enums/native.rs b/compiler/rustc_codegen_llvm/src/debuginfo/metadata/enums/native.rs index 5e7dbdd921a..b7400c5aeb2 100644 --- a/compiler/rustc_codegen_llvm/src/debuginfo/metadata/enums/native.rs +++ b/compiler/rustc_codegen_llvm/src/debuginfo/metadata/enums/native.rs @@ -10,7 +10,7 @@ use rustc_middle::ty::{self}; use rustc_target::abi::{Size, TagEncoding, VariantIdx, Variants}; use smallvec::smallvec; -use crate::common::CodegenCx; +use crate::common::{AsCCharPtr, CodegenCx}; use crate::debuginfo::metadata::type_map::{self, Stub, StubInfo, UniqueTypeId}; use crate::debuginfo::metadata::{ DINodeCreationResult, NO_GENERICS, SmallVec, UNKNOWN_LINE_NUMBER, file_metadata, @@ -244,7 +244,7 @@ fn build_enum_variant_part_di_node<'ll, 'tcx>( llvm::LLVMRustDIBuilderCreateVariantPart( DIB(cx), enum_type_di_node, - variant_part_name.as_ptr().cast(), + variant_part_name.as_c_char_ptr(), variant_part_name.len(), unknown_file_metadata(cx), UNKNOWN_LINE_NUMBER, @@ -253,7 +253,7 @@ fn build_enum_variant_part_di_node<'ll, 'tcx>( DIFlags::FlagZero, tag_member_di_node, create_DIArray(DIB(cx), &[]), - variant_part_unique_type_id_str.as_ptr().cast(), + variant_part_unique_type_id_str.as_c_char_ptr(), variant_part_unique_type_id_str.len(), ) }, @@ -327,7 +327,7 @@ fn build_discr_member_di_node<'ll, 'tcx>( Some(llvm::LLVMRustDIBuilderCreateMemberType( DIB(cx), containing_scope, - tag_name.as_ptr().cast(), + tag_name.as_c_char_ptr(), tag_name.len(), unknown_file_metadata(cx), UNKNOWN_LINE_NUMBER, @@ -399,7 +399,7 @@ fn build_enum_variant_member_di_node<'ll, 'tcx>( llvm::LLVMRustDIBuilderCreateVariantMemberType( DIB(cx), variant_part_di_node, - variant_member_info.variant_name.as_ptr().cast(), + variant_member_info.variant_name.as_c_char_ptr(), variant_member_info.variant_name.len(), file_di_node, line_number, diff --git a/compiler/rustc_codegen_llvm/src/debuginfo/metadata/type_map.rs b/compiler/rustc_codegen_llvm/src/debuginfo/metadata/type_map.rs index 714e3c0b145..d050dc9b406 100644 --- a/compiler/rustc_codegen_llvm/src/debuginfo/metadata/type_map.rs +++ b/compiler/rustc_codegen_llvm/src/debuginfo/metadata/type_map.rs @@ -9,7 +9,7 @@ use rustc_middle::ty::{ParamEnv, PolyExistentialTraitRef, Ty, TyCtxt}; use rustc_target::abi::{Align, Size, VariantIdx}; use super::{SmallVec, UNKNOWN_LINE_NUMBER, unknown_file_metadata}; -use crate::common::CodegenCx; +use crate::common::{AsCCharPtr, CodegenCx}; use crate::debuginfo::utils::{DIB, create_DIArray, debug_context}; use crate::llvm::debuginfo::{DIFlags, DIScope, DIType}; use crate::llvm::{self}; @@ -191,7 +191,7 @@ pub(super) fn stub<'ll, 'tcx>( llvm::LLVMRustDIBuilderCreateStructType( DIB(cx), containing_scope, - name.as_ptr().cast(), + name.as_c_char_ptr(), name.len(), unknown_file_metadata(cx), UNKNOWN_LINE_NUMBER, @@ -202,7 +202,7 @@ pub(super) fn stub<'ll, 'tcx>( empty_array, 0, vtable_holder, - unique_type_id_str.as_ptr().cast(), + unique_type_id_str.as_c_char_ptr(), unique_type_id_str.len(), ) } @@ -211,7 +211,7 @@ pub(super) fn stub<'ll, 'tcx>( llvm::LLVMRustDIBuilderCreateUnionType( DIB(cx), containing_scope, - name.as_ptr().cast(), + name.as_c_char_ptr(), name.len(), unknown_file_metadata(cx), UNKNOWN_LINE_NUMBER, @@ -220,7 +220,7 @@ pub(super) fn stub<'ll, 'tcx>( flags, Some(empty_array), 0, - unique_type_id_str.as_ptr().cast(), + unique_type_id_str.as_c_char_ptr(), unique_type_id_str.len(), ) }, diff --git a/compiler/rustc_codegen_llvm/src/debuginfo/mod.rs b/compiler/rustc_codegen_llvm/src/debuginfo/mod.rs index 3de4ca77e7d..72e723aa849 100644 --- a/compiler/rustc_codegen_llvm/src/debuginfo/mod.rs +++ b/compiler/rustc_codegen_llvm/src/debuginfo/mod.rs @@ -31,7 +31,7 @@ use self::namespace::mangled_name_of_instance; use self::utils::{DIB, create_DIArray, is_node_local_to_unit}; use crate::abi::FnAbi; use crate::builder::Builder; -use crate::common::CodegenCx; +use crate::common::{AsCCharPtr, CodegenCx}; use crate::llvm; use crate::llvm::debuginfo::{ DIArray, DIBuilder, DIFile, DIFlags, DILexicalBlock, DILocation, DISPFlags, DIScope, DIType, @@ -91,45 +91,39 @@ impl<'ll, 'tcx> CodegenUnitDebugContext<'ll, 'tcx> { } pub(crate) fn finalize(&self, sess: &Session) { - unsafe { - llvm::LLVMRustDIBuilderFinalize(self.builder); - - if !sess.target.is_like_msvc { - // Debuginfo generation in LLVM by default uses a higher - // version of dwarf than macOS currently understands. We can - // instruct LLVM to emit an older version of dwarf, however, - // for macOS to understand. For more info see #11352 - // This can be overridden using --llvm-opts -dwarf-version,N. - // Android has the same issue (#22398) - let dwarf_version = sess - .opts - .unstable_opts - .dwarf_version - .unwrap_or(sess.target.default_dwarf_version); - llvm::LLVMRustAddModuleFlagU32( - self.llmod, - llvm::LLVMModFlagBehavior::Warning, - c"Dwarf Version".as_ptr(), - dwarf_version, - ); - } else { - // Indicate that we want CodeView debug information on MSVC - llvm::LLVMRustAddModuleFlagU32( - self.llmod, - llvm::LLVMModFlagBehavior::Warning, - c"CodeView".as_ptr(), - 1, - ) - } - - // Prevent bitcode readers from deleting the debug info. - llvm::LLVMRustAddModuleFlagU32( + unsafe { llvm::LLVMRustDIBuilderFinalize(self.builder) }; + if !sess.target.is_like_msvc { + // Debuginfo generation in LLVM by default uses a higher + // version of dwarf than macOS currently understands. We can + // instruct LLVM to emit an older version of dwarf, however, + // for macOS to understand. For more info see #11352 + // This can be overridden using --llvm-opts -dwarf-version,N. + // Android has the same issue (#22398) + let dwarf_version = + sess.opts.unstable_opts.dwarf_version.unwrap_or(sess.target.default_dwarf_version); + llvm::add_module_flag_u32( self.llmod, - llvm::LLVMModFlagBehavior::Warning, - c"Debug Info Version".as_ptr(), - llvm::LLVMRustDebugMetadataVersion(), + llvm::ModuleFlagMergeBehavior::Warning, + "Dwarf Version", + dwarf_version, + ); + } else { + // Indicate that we want CodeView debug information on MSVC + llvm::add_module_flag_u32( + self.llmod, + llvm::ModuleFlagMergeBehavior::Warning, + "CodeView", + 1, ); } + + // Prevent bitcode readers from deleting the debug info. + llvm::add_module_flag_u32( + self.llmod, + llvm::ModuleFlagMergeBehavior::Warning, + "Debug Info Version", + unsafe { llvm::LLVMRustDebugMetadataVersion() }, + ); } } @@ -364,7 +358,7 @@ impl<'ll, 'tcx> DebugInfoCodegenMethods<'tcx> for CodegenCx<'ll, 'tcx> { let mut flags = DIFlags::FlagPrototyped; - if fn_abi.ret.layout.abi.is_uninhabited() { + if fn_abi.ret.layout.is_uninhabited() { flags |= DIFlags::FlagNoReturn; } @@ -389,9 +383,9 @@ impl<'ll, 'tcx> DebugInfoCodegenMethods<'tcx> for CodegenCx<'ll, 'tcx> { llvm::LLVMRustDIBuilderCreateMethod( DIB(self), containing_scope, - name.as_ptr().cast(), + name.as_c_char_ptr(), name.len(), - linkage_name.as_ptr().cast(), + linkage_name.as_c_char_ptr(), linkage_name.len(), file_metadata, loc.line, @@ -406,9 +400,9 @@ impl<'ll, 'tcx> DebugInfoCodegenMethods<'tcx> for CodegenCx<'ll, 'tcx> { llvm::LLVMRustDIBuilderCreateFunction( DIB(self), containing_scope, - name.as_ptr().cast(), + name.as_c_char_ptr(), name.len(), - linkage_name.as_ptr().cast(), + linkage_name.as_c_char_ptr(), linkage_name.len(), file_metadata, loc.line, @@ -494,7 +488,7 @@ impl<'ll, 'tcx> DebugInfoCodegenMethods<'tcx> for CodegenCx<'ll, 'tcx> { Some(llvm::LLVMRustDIBuilderCreateTemplateTypeParameter( DIB(cx), None, - name.as_ptr().cast(), + name.as_c_char_ptr(), name.len(), actual_type_metadata, )) @@ -635,7 +629,7 @@ impl<'ll, 'tcx> DebugInfoCodegenMethods<'tcx> for CodegenCx<'ll, 'tcx> { DIB(self), dwarf_tag, scope_metadata, - name.as_ptr().cast(), + name.as_c_char_ptr(), name.len(), file_metadata, loc.line, diff --git a/compiler/rustc_codegen_llvm/src/debuginfo/namespace.rs b/compiler/rustc_codegen_llvm/src/debuginfo/namespace.rs index 3578755aae0..33d9bc23890 100644 --- a/compiler/rustc_codegen_llvm/src/debuginfo/namespace.rs +++ b/compiler/rustc_codegen_llvm/src/debuginfo/namespace.rs @@ -5,7 +5,7 @@ use rustc_hir::def_id::DefId; use rustc_middle::ty::{self, Instance}; use super::utils::{DIB, debug_context}; -use crate::common::CodegenCx; +use crate::common::{AsCCharPtr, CodegenCx}; use crate::llvm; use crate::llvm::debuginfo::DIScope; @@ -36,7 +36,7 @@ pub(crate) fn item_namespace<'ll>(cx: &CodegenCx<'ll, '_>, def_id: DefId) -> &'l llvm::LLVMRustDIBuilderCreateNameSpace( DIB(cx), parent_scope, - namespace_name_string.as_ptr().cast(), + namespace_name_string.as_c_char_ptr(), namespace_name_string.len(), false, // ExportSymbols (only relevant for C++ anonymous namespaces) ) diff --git a/compiler/rustc_codegen_llvm/src/declare.rs b/compiler/rustc_codegen_llvm/src/declare.rs index 33258cb46fa..d338c848754 100644 --- a/compiler/rustc_codegen_llvm/src/declare.rs +++ b/compiler/rustc_codegen_llvm/src/declare.rs @@ -20,6 +20,7 @@ use smallvec::SmallVec; use tracing::debug; use crate::abi::{FnAbi, FnAbiLlvmExt}; +use crate::common::AsCCharPtr; use crate::context::CodegenCx; use crate::llvm::AttributePlace::Function; use crate::llvm::Visibility; @@ -41,7 +42,7 @@ fn declare_raw_fn<'ll>( ) -> &'ll Value { debug!("declare_raw_fn(name={:?}, ty={:?})", name, ty); let llfn = unsafe { - llvm::LLVMRustGetOrInsertFunction(cx.llmod, name.as_ptr().cast(), name.len(), ty) + llvm::LLVMRustGetOrInsertFunction(cx.llmod, name.as_c_char_ptr(), name.len(), ty) }; llvm::SetFunctionCallConv(llfn, callconv); @@ -68,7 +69,7 @@ impl<'ll, 'tcx> CodegenCx<'ll, 'tcx> { /// return its Value instead. pub(crate) fn declare_global(&self, name: &str, ty: &'ll Type) -> &'ll Value { debug!("declare_global(name={:?})", name); - unsafe { llvm::LLVMRustGetOrInsertGlobal(self.llmod, name.as_ptr().cast(), name.len(), ty) } + unsafe { llvm::LLVMRustGetOrInsertGlobal(self.llmod, name.as_c_char_ptr(), name.len(), ty) } } /// Declare a C ABI function. @@ -209,7 +210,7 @@ impl<'ll, 'tcx> CodegenCx<'ll, 'tcx> { /// Gets declared value by name. pub(crate) fn get_declared_value(&self, name: &str) -> Option<&'ll Value> { debug!("get_declared_value(name={:?})", name); - unsafe { llvm::LLVMRustGetNamedValue(self.llmod, name.as_ptr().cast(), name.len()) } + unsafe { llvm::LLVMRustGetNamedValue(self.llmod, name.as_c_char_ptr(), name.len()) } } /// Gets defined or externally defined (AvailableExternally linkage) value by diff --git a/compiler/rustc_codegen_llvm/src/intrinsic.rs b/compiler/rustc_codegen_llvm/src/intrinsic.rs index c9a17c9852d..d04b5257619 100644 --- a/compiler/rustc_codegen_llvm/src/intrinsic.rs +++ b/compiler/rustc_codegen_llvm/src/intrinsic.rs @@ -785,13 +785,12 @@ fn codegen_msvc_try<'ll>( let type_info = bx.const_struct(&[type_info_vtable, bx.const_null(bx.type_ptr()), type_name], false); let tydesc = bx.declare_global("__rust_panic_type_info", bx.val_ty(type_info)); - unsafe { - llvm::LLVMRustSetLinkage(tydesc, llvm::Linkage::LinkOnceODRLinkage); - if bx.cx.tcx.sess.target.supports_comdat() { - llvm::SetUniqueComdat(bx.llmod, tydesc); - } - llvm::LLVMSetInitializer(tydesc, type_info); + + llvm::set_linkage(tydesc, llvm::Linkage::LinkOnceODRLinkage); + if bx.cx.tcx.sess.target.supports_comdat() { + llvm::SetUniqueComdat(bx.llmod, tydesc); } + unsafe { llvm::LLVMSetInitializer(tydesc, type_info) }; // The flag value of 8 indicates that we are catching the exception by // reference instead of by value. We can't use catch by value because @@ -1064,7 +1063,7 @@ fn gen_fn<'ll, 'tcx>( cx.set_frame_pointer_type(llfn); cx.apply_target_cpu_attr(llfn); // FIXME(eddyb) find a nicer way to do this. - unsafe { llvm::LLVMRustSetLinkage(llfn, llvm::Linkage::InternalLinkage) }; + llvm::set_linkage(llfn, llvm::Linkage::InternalLinkage); let llbb = Builder::append_block(cx, llfn, "entry-block"); let bx = Builder::build(cx, llbb); codegen(bx); diff --git a/compiler/rustc_codegen_llvm/src/llvm/ffi.rs b/compiler/rustc_codegen_llvm/src/llvm/ffi.rs index 10e55a4f7f6..8fc586d2c8f 100644 --- a/compiler/rustc_codegen_llvm/src/llvm/ffi.rs +++ b/compiler/rustc_codegen_llvm/src/llvm/ffi.rs @@ -1,9 +1,12 @@ #![allow(non_camel_case_types)] #![allow(non_upper_case_globals)] +use std::fmt::Debug; use std::marker::PhantomData; +use std::ptr; use libc::{c_char, c_int, c_uint, c_ulonglong, c_void, size_t}; +use rustc_macros::TryFromU32; use rustc_target::spec::SymbolVisibility; use super::RustString; @@ -19,6 +22,30 @@ pub type Bool = c_uint; pub const True: Bool = 1 as Bool; pub const False: Bool = 0 as Bool; +/// Wrapper for a raw enum value returned from LLVM's C APIs. +/// +/// For C enums returned by LLVM, it's risky to use a Rust enum as the return +/// type, because it would be UB if a later version of LLVM adds a new enum +/// value and returns it. Instead, return this raw wrapper, then convert to the +/// Rust-side enum explicitly. +#[repr(transparent)] +pub struct RawEnum<T> { + value: u32, + /// We don't own or consume a `T`, but we can produce one. + _rust_side_type: PhantomData<fn() -> T>, +} + +impl<T: TryFrom<u32>> RawEnum<T> { + #[track_caller] + pub(crate) fn to_rust(self) -> T + where + T::Error: Debug, + { + // If this fails, the Rust-side enum is out of sync with LLVM's enum. + T::try_from(self.value).expect("enum value returned by LLVM should be known") + } +} + #[derive(Copy, Clone, PartialEq)] #[repr(C)] #[allow(dead_code)] // Variants constructed by C++. @@ -59,7 +86,7 @@ pub enum LLVMMachineType { ARM = 0x01c0, } -/// LLVM's Module::ModFlagBehavior, defined in llvm/include/llvm/IR/Module.h. +/// Must match the layout of `LLVMRustModuleFlagMergeBehavior`. /// /// When merging modules (e.g. during LTO), their metadata flags are combined. Conflicts are /// resolved according to the merge behaviors specified here. Flags differing only in merge @@ -67,9 +94,13 @@ pub enum LLVMMachineType { /// /// In order for Rust-C LTO to work, we must specify behaviors compatible with Clang. Notably, /// 'Error' and 'Warning' cannot be mixed for a given flag. +/// +/// There is a stable LLVM-C version of this enum (`LLVMModuleFlagBehavior`), +/// but as of LLVM 19 it does not support all of the enum values in the unstable +/// C++ API. #[derive(Copy, Clone, PartialEq)] #[repr(C)] -pub enum LLVMModFlagBehavior { +pub enum ModuleFlagMergeBehavior { Error = 1, Warning = 2, Require = 3, @@ -108,26 +139,36 @@ pub enum CallConv { AvrInterrupt = 85, } -/// LLVMRustLinkage -#[derive(Copy, Clone, PartialEq)] +/// Must match the layout of `LLVMLinkage`. +#[derive(Copy, Clone, PartialEq, TryFromU32)] #[repr(C)] pub enum Linkage { ExternalLinkage = 0, AvailableExternallyLinkage = 1, LinkOnceAnyLinkage = 2, LinkOnceODRLinkage = 3, - WeakAnyLinkage = 4, - WeakODRLinkage = 5, - AppendingLinkage = 6, - InternalLinkage = 7, - PrivateLinkage = 8, - ExternalWeakLinkage = 9, - CommonLinkage = 10, + #[deprecated = "marked obsolete by LLVM"] + LinkOnceODRAutoHideLinkage = 4, + WeakAnyLinkage = 5, + WeakODRLinkage = 6, + AppendingLinkage = 7, + InternalLinkage = 8, + PrivateLinkage = 9, + #[deprecated = "marked obsolete by LLVM"] + DLLImportLinkage = 10, + #[deprecated = "marked obsolete by LLVM"] + DLLExportLinkage = 11, + ExternalWeakLinkage = 12, + #[deprecated = "marked obsolete by LLVM"] + GhostLinkage = 13, + CommonLinkage = 14, + LinkerPrivateLinkage = 15, + LinkerPrivateWeakLinkage = 16, } -// LLVMRustVisibility +/// Must match the layout of `LLVMVisibility`. #[repr(C)] -#[derive(Copy, Clone, PartialEq)] +#[derive(Copy, Clone, PartialEq, TryFromU32)] pub enum Visibility { Default = 0, Hidden = 1, @@ -668,8 +709,9 @@ unsafe extern "C" { } #[repr(C)] pub struct RustArchiveMember<'a>(InvariantOpaque<'a>); +/// Opaque pointee of `LLVMOperandBundleRef`. #[repr(C)] -pub struct OperandBundleDef<'a>(InvariantOpaque<'a>); +pub(crate) struct OperandBundle<'a>(InvariantOpaque<'a>); #[repr(C)] pub struct Linker<'a>(InvariantOpaque<'a>); @@ -945,7 +987,11 @@ unsafe extern "C" { // Operations on global variables, functions, and aliases (globals) pub fn LLVMIsDeclaration(Global: &Value) -> Bool; + pub fn LLVMGetLinkage(Global: &Value) -> RawEnum<Linkage>; + pub fn LLVMSetLinkage(Global: &Value, RustLinkage: Linkage); pub fn LLVMSetSection(Global: &Value, Section: *const c_char); + pub fn LLVMGetVisibility(Global: &Value) -> RawEnum<Visibility>; + pub fn LLVMSetVisibility(Global: &Value, Viz: Visibility); pub fn LLVMGetAlignment(Global: &Value) -> c_uint; pub fn LLVMSetAlignment(Global: &Value, Bytes: c_uint); pub fn LLVMSetDLLStorageClass(V: &Value, C: DLLStorageClass); @@ -1494,6 +1540,50 @@ unsafe extern "C" { pub fn LLVMGetOrInsertComdat(M: &Module, Name: *const c_char) -> &Comdat; pub fn LLVMSetComdat(V: &Value, C: &Comdat); + + pub(crate) fn LLVMCreateOperandBundle( + Tag: *const c_char, + TagLen: size_t, + Args: *const &'_ Value, + NumArgs: c_uint, + ) -> *mut OperandBundle<'_>; + pub(crate) fn LLVMDisposeOperandBundle(Bundle: ptr::NonNull<OperandBundle<'_>>); + + pub(crate) fn LLVMBuildCallWithOperandBundles<'a>( + B: &Builder<'a>, + Ty: &'a Type, + Fn: &'a Value, + Args: *const &'a Value, + NumArgs: c_uint, + Bundles: *const &OperandBundle<'a>, + NumBundles: c_uint, + Name: *const c_char, + ) -> &'a Value; + pub(crate) fn LLVMBuildInvokeWithOperandBundles<'a>( + B: &Builder<'a>, + Ty: &'a Type, + Fn: &'a Value, + Args: *const &'a Value, + NumArgs: c_uint, + Then: &'a BasicBlock, + Catch: &'a BasicBlock, + Bundles: *const &OperandBundle<'a>, + NumBundles: c_uint, + Name: *const c_char, + ) -> &'a Value; + pub(crate) fn LLVMBuildCallBr<'a>( + B: &Builder<'a>, + Ty: &'a Type, + Fn: &'a Value, + DefaultDest: &'a BasicBlock, + IndirectDests: *const &'a BasicBlock, + NumIndirectDests: c_uint, + Args: *const &'a Value, + NumArgs: c_uint, + Bundles: *const &OperandBundle<'a>, + NumBundles: c_uint, + Name: *const c_char, + ) -> &'a Value; } #[link(name = "llvm-wrapper", kind = "static")] @@ -1521,10 +1611,6 @@ unsafe extern "C" { ) -> bool; // Operations on global variables, functions, and aliases (globals) - pub fn LLVMRustGetLinkage(Global: &Value) -> Linkage; - pub fn LLVMRustSetLinkage(Global: &Value, RustLinkage: Linkage); - pub fn LLVMRustGetVisibility(Global: &Value) -> Visibility; - pub fn LLVMRustSetVisibility(Global: &Value, Viz: Visibility); pub fn LLVMRustSetDSOLocal(Global: &Value, is_dso_local: bool); // Operations on global variables @@ -1583,47 +1669,11 @@ unsafe extern "C" { AttrsLen: size_t, ); - pub fn LLVMRustBuildInvoke<'a>( - B: &Builder<'a>, - Ty: &'a Type, - Fn: &'a Value, - Args: *const &'a Value, - NumArgs: c_uint, - Then: &'a BasicBlock, - Catch: &'a BasicBlock, - OpBundles: *const &OperandBundleDef<'a>, - NumOpBundles: c_uint, - Name: *const c_char, - ) -> &'a Value; - - pub fn LLVMRustBuildCallBr<'a>( - B: &Builder<'a>, - Ty: &'a Type, - Fn: &'a Value, - DefaultDest: &'a BasicBlock, - IndirectDests: *const &'a BasicBlock, - NumIndirectDests: c_uint, - Args: *const &'a Value, - NumArgs: c_uint, - OpBundles: *const &OperandBundleDef<'a>, - NumOpBundles: c_uint, - Name: *const c_char, - ) -> &'a Value; - pub fn LLVMRustSetFastMath(Instr: &Value); pub fn LLVMRustSetAlgebraicMath(Instr: &Value); pub fn LLVMRustSetAllowReassoc(Instr: &Value); // Miscellaneous instructions - pub fn LLVMRustBuildCall<'a>( - B: &Builder<'a>, - Ty: &'a Type, - Fn: &'a Value, - Args: *const &'a Value, - NumArgs: c_uint, - OpBundles: *const &OperandBundleDef<'a>, - NumOpBundles: c_uint, - ) -> &'a Value; pub fn LLVMRustBuildMemCpy<'a>( B: &Builder<'a>, Dst: &'a Value, @@ -1793,21 +1843,21 @@ unsafe extern "C" { /// "compatible" means depends on the merge behaviors involved. pub fn LLVMRustAddModuleFlagU32( M: &Module, - merge_behavior: LLVMModFlagBehavior, - name: *const c_char, - value: u32, + MergeBehavior: ModuleFlagMergeBehavior, + Name: *const c_char, + NameLen: size_t, + Value: u32, ); pub fn LLVMRustAddModuleFlagString( M: &Module, - merge_behavior: LLVMModFlagBehavior, - name: *const c_char, - value: *const c_char, - value_len: size_t, + MergeBehavior: ModuleFlagMergeBehavior, + Name: *const c_char, + NameLen: size_t, + Value: *const c_char, + ValueLen: size_t, ); - pub fn LLVMRustHasModuleFlag(M: &Module, name: *const c_char, len: size_t) -> bool; - pub fn LLVMRustDIBuilderCreate(M: &Module) -> &mut DIBuilder<'_>; pub fn LLVMRustDIBuilderDispose<'a>(Builder: &'a mut DIBuilder<'a>); @@ -2317,13 +2367,6 @@ unsafe extern "C" { pub fn LLVMRustSetDataLayoutFromTargetMachine<'a>(M: &'a Module, TM: &'a TargetMachine); - pub fn LLVMRustBuildOperandBundleDef( - Name: *const c_char, - Inputs: *const &'_ Value, - NumInputs: c_uint, - ) -> &mut OperandBundleDef<'_>; - pub fn LLVMRustFreeOperandBundleDef<'a>(Bundle: &'a mut OperandBundleDef<'a>); - pub fn LLVMRustPositionBuilderAtStart<'a>(B: &Builder<'a>, BB: &'a BasicBlock); pub fn LLVMRustSetModulePICLevel(M: &Module); @@ -2349,9 +2392,9 @@ unsafe extern "C" { pub fn LLVMRustThinLTOBufferThinLinkDataLen(M: &ThinLTOBuffer) -> size_t; pub fn LLVMRustCreateThinLTOData( Modules: *const ThinLTOModule, - NumModules: c_uint, + NumModules: size_t, PreservedSymbols: *const *const c_char, - PreservedSymbolsLen: c_uint, + PreservedSymbolsLen: size_t, ) -> Option<&'static mut ThinLTOData>; pub fn LLVMRustPrepareThinLTORename( Data: &ThinLTOData, @@ -2376,6 +2419,7 @@ unsafe extern "C" { data: *const u8, len: usize, name: *const u8, + name_len: usize, out_len: &mut usize, ) -> *const u8; diff --git a/compiler/rustc_codegen_llvm/src/llvm/mod.rs b/compiler/rustc_codegen_llvm/src/llvm/mod.rs index e837022044e..00a5cd3b859 100644 --- a/compiler/rustc_codegen_llvm/src/llvm/mod.rs +++ b/compiler/rustc_codegen_llvm/src/llvm/mod.rs @@ -2,11 +2,12 @@ use std::cell::RefCell; use std::ffi::{CStr, CString}; +use std::ops::Deref; +use std::ptr; use std::str::FromStr; use std::string::FromUtf8Error; use libc::c_uint; -use rustc_data_structures::small_c_str::SmallCStr; use rustc_llvm::RustString; use rustc_target::abi::{Align, Size, WrappingRange}; @@ -17,13 +18,13 @@ pub use self::IntPredicate::*; pub use self::Linkage::*; pub use self::MetadataType::*; pub use self::RealPredicate::*; +pub use self::ffi::*; +use crate::common::AsCCharPtr; pub mod archive_ro; pub mod diagnostic; mod ffi; -pub use self::ffi::*; - impl LLVMRustResult { pub fn into_result(self) -> Result<(), ()> { match self { @@ -53,9 +54,9 @@ pub fn CreateAttrStringValue<'ll>(llcx: &'ll Context, attr: &str, value: &str) - unsafe { LLVMCreateStringAttribute( llcx, - attr.as_ptr().cast(), + attr.as_c_char_ptr(), attr.len().try_into().unwrap(), - value.as_ptr().cast(), + value.as_c_char_ptr(), value.len().try_into().unwrap(), ) } @@ -65,7 +66,7 @@ pub fn CreateAttrString<'ll>(llcx: &'ll Context, attr: &str) -> &'ll Attribute { unsafe { LLVMCreateStringAttribute( llcx, - attr.as_ptr().cast(), + attr.as_c_char_ptr(), attr.len().try_into().unwrap(), std::ptr::null(), 0, @@ -232,15 +233,23 @@ pub fn set_global_constant(llglobal: &Value, is_constant: bool) { } } +pub fn get_linkage(llglobal: &Value) -> Linkage { + unsafe { LLVMGetLinkage(llglobal) }.to_rust() +} + pub fn set_linkage(llglobal: &Value, linkage: Linkage) { unsafe { - LLVMRustSetLinkage(llglobal, linkage); + LLVMSetLinkage(llglobal, linkage); } } +pub fn get_visibility(llglobal: &Value) -> Visibility { + unsafe { LLVMGetVisibility(llglobal) }.to_rust() +} + pub fn set_visibility(llglobal: &Value, visibility: Visibility) { unsafe { - LLVMRustSetVisibility(llglobal, visibility); + LLVMSetVisibility(llglobal, visibility); } } @@ -286,7 +295,7 @@ pub fn get_value_name(value: &Value) -> &[u8] { /// Safe wrapper for `LLVMSetValueName2` from a byte slice pub fn set_value_name(value: &Value, name: &[u8]) { unsafe { - let data = name.as_ptr().cast(); + let data = name.as_c_char_ptr(); LLVMSetValueName2(value, data, name.len()); } } @@ -323,24 +332,68 @@ pub fn last_error() -> Option<String> { } } -pub struct OperandBundleDef<'a> { - pub raw: &'a mut ffi::OperandBundleDef<'a>, +/// Owns an [`OperandBundle`], and will dispose of it when dropped. +pub(crate) struct OperandBundleOwned<'a> { + raw: ptr::NonNull<OperandBundle<'a>>, } -impl<'a> OperandBundleDef<'a> { - pub fn new(name: &str, vals: &[&'a Value]) -> Self { - let name = SmallCStr::new(name); - let def = unsafe { - LLVMRustBuildOperandBundleDef(name.as_ptr(), vals.as_ptr(), vals.len() as c_uint) +impl<'a> OperandBundleOwned<'a> { + pub(crate) fn new(name: &str, vals: &[&'a Value]) -> Self { + let raw = unsafe { + LLVMCreateOperandBundle( + name.as_c_char_ptr(), + name.len(), + vals.as_ptr(), + vals.len() as c_uint, + ) }; - OperandBundleDef { raw: def } + OperandBundleOwned { raw: ptr::NonNull::new(raw).unwrap() } } } -impl Drop for OperandBundleDef<'_> { +impl Drop for OperandBundleOwned<'_> { fn drop(&mut self) { unsafe { - LLVMRustFreeOperandBundleDef(&mut *(self.raw as *mut _)); + LLVMDisposeOperandBundle(self.raw); } } } + +impl<'a> Deref for OperandBundleOwned<'a> { + type Target = OperandBundle<'a>; + + fn deref(&self) -> &Self::Target { + // SAFETY: The returned reference is opaque and can only used for FFI. + // It is valid for as long as `&self` is. + unsafe { self.raw.as_ref() } + } +} + +pub(crate) fn add_module_flag_u32( + module: &Module, + merge_behavior: ModuleFlagMergeBehavior, + key: &str, + value: u32, +) { + unsafe { + LLVMRustAddModuleFlagU32(module, merge_behavior, key.as_c_char_ptr(), key.len(), value); + } +} + +pub(crate) fn add_module_flag_str( + module: &Module, + merge_behavior: ModuleFlagMergeBehavior, + key: &str, + value: &str, +) { + unsafe { + LLVMRustAddModuleFlagString( + module, + merge_behavior, + key.as_c_char_ptr(), + key.len(), + value.as_c_char_ptr(), + value.len(), + ); + } +} diff --git a/compiler/rustc_codegen_llvm/src/llvm_util.rs b/compiler/rustc_codegen_llvm/src/llvm_util.rs index 57936215ff1..9adb1299b3d 100644 --- a/compiler/rustc_codegen_llvm/src/llvm_util.rs +++ b/compiler/rustc_codegen_llvm/src/llvm_util.rs @@ -248,6 +248,7 @@ pub(crate) fn to_llvm_features<'a>(sess: &Session, s: &'a str) -> Option<LLVMFea ("aarch64", "pmuv3") => Some(LLVMFeature::new("perfmon")), ("aarch64", "paca") => Some(LLVMFeature::new("pauth")), ("aarch64", "pacg") => Some(LLVMFeature::new("pauth")), + ("aarch64", "pauth-lr") if get_version().0 < 19 => None, // Before LLVM 20 those two features were packaged together as b16b16 ("aarch64", "sve-b16b16") if get_version().0 < 20 => Some(LLVMFeature::new("b16b16")), ("aarch64", "sme-b16b16") if get_version().0 < 20 => Some(LLVMFeature::new("b16b16")), @@ -697,12 +698,9 @@ fn backend_feature_name<'a>(sess: &Session, s: &'a str) -> Option<&'a str> { let feature = s .strip_prefix(&['+', '-'][..]) .unwrap_or_else(|| sess.dcx().emit_fatal(InvalidTargetFeaturePrefix { feature: s })); - if s.is_empty() { - return None; - } // Rustc-specific feature requests like `+crt-static` or `-crt-static` // are not passed down to LLVM. - if RUSTC_SPECIFIC_FEATURES.contains(&feature) { + if s.is_empty() || RUSTC_SPECIFIC_FEATURES.contains(&feature) { return None; } Some(feature) diff --git a/compiler/rustc_codegen_llvm/src/mono_item.rs b/compiler/rustc_codegen_llvm/src/mono_item.rs index bf6ef219873..ea8857b4739 100644 --- a/compiler/rustc_codegen_llvm/src/mono_item.rs +++ b/compiler/rustc_codegen_llvm/src/mono_item.rs @@ -39,9 +39,9 @@ impl<'tcx> PreDefineCodegenMethods<'tcx> for CodegenCx<'_, 'tcx> { .emit_fatal(SymbolAlreadyDefined { span: self.tcx.def_span(def_id), symbol_name }) }); + llvm::set_linkage(g, base::linkage_to_llvm(linkage)); + llvm::set_visibility(g, base::visibility_to_llvm(visibility)); unsafe { - llvm::LLVMRustSetLinkage(g, base::linkage_to_llvm(linkage)); - llvm::LLVMRustSetVisibility(g, base::visibility_to_llvm(visibility)); if self.should_assume_dso_local(g, false) { llvm::LLVMRustSetDSOLocal(g, true); } @@ -61,7 +61,7 @@ impl<'tcx> PreDefineCodegenMethods<'tcx> for CodegenCx<'_, 'tcx> { let fn_abi = self.fn_abi_of_instance(instance, ty::List::empty()); let lldecl = self.declare_fn(symbol_name, fn_abi, Some(instance)); - unsafe { llvm::LLVMRustSetLinkage(lldecl, base::linkage_to_llvm(linkage)) }; + llvm::set_linkage(lldecl, base::linkage_to_llvm(linkage)); let attrs = self.tcx.codegen_fn_attrs(instance.def_id()); base::set_link_section(lldecl, attrs); if (linkage == Linkage::LinkOnceODR || linkage == Linkage::WeakODR) @@ -78,21 +78,15 @@ impl<'tcx> PreDefineCodegenMethods<'tcx> for CodegenCx<'_, 'tcx> { && linkage != Linkage::Private && self.tcx.is_compiler_builtins(LOCAL_CRATE) { - unsafe { - llvm::LLVMRustSetVisibility(lldecl, llvm::Visibility::Hidden); - } + llvm::set_visibility(lldecl, llvm::Visibility::Hidden); } else { - unsafe { - llvm::LLVMRustSetVisibility(lldecl, base::visibility_to_llvm(visibility)); - } + llvm::set_visibility(lldecl, base::visibility_to_llvm(visibility)); } debug!("predefine_fn: instance = {:?}", instance); - unsafe { - if self.should_assume_dso_local(lldecl, false) { - llvm::LLVMRustSetDSOLocal(lldecl, true); - } + if self.should_assume_dso_local(lldecl, false) { + unsafe { llvm::LLVMRustSetDSOLocal(lldecl, true) }; } self.instances.borrow_mut().insert(instance, lldecl); @@ -102,13 +96,13 @@ impl<'tcx> PreDefineCodegenMethods<'tcx> for CodegenCx<'_, 'tcx> { impl CodegenCx<'_, '_> { /// Whether a definition or declaration can be assumed to be local to a group of /// libraries that form a single DSO or executable. - pub(crate) unsafe fn should_assume_dso_local( + pub(crate) fn should_assume_dso_local( &self, llval: &llvm::Value, is_declaration: bool, ) -> bool { - let linkage = unsafe { llvm::LLVMRustGetLinkage(llval) }; - let visibility = unsafe { llvm::LLVMRustGetVisibility(llval) }; + let linkage = llvm::get_linkage(llval); + let visibility = llvm::get_visibility(llval); if matches!(linkage, llvm::Linkage::InternalLinkage | llvm::Linkage::PrivateLinkage) { return true; diff --git a/compiler/rustc_codegen_ssa/src/back/write.rs b/compiler/rustc_codegen_ssa/src/back/write.rs index e3d11cfaf4f..8445d16befb 100644 --- a/compiler/rustc_codegen_ssa/src/back/write.rs +++ b/compiler/rustc_codegen_ssa/src/back/write.rs @@ -514,7 +514,7 @@ pub(crate) fn start_async_codegen<B: ExtraBackendMethods>( future: Some(coordinator_thread), phantom: PhantomData, }, - output_filenames: tcx.output_filenames(()).clone(), + output_filenames: Arc::clone(tcx.output_filenames(())), } } @@ -1203,7 +1203,7 @@ fn start_executing_work<B: ExtraBackendMethods>( coordinator_send, expanded_args: tcx.sess.expanded_args.clone(), diag_emitter: shared_emitter.clone(), - output_filenames: tcx.output_filenames(()).clone(), + output_filenames: Arc::clone(tcx.output_filenames(())), regular_module_config: regular_config, metadata_module_config: metadata_config, allocator_module_config: allocator_config, diff --git a/compiler/rustc_codegen_ssa/src/base.rs b/compiler/rustc_codegen_ssa/src/base.rs index a726ee73aaa..cb4c9c078b1 100644 --- a/compiler/rustc_codegen_ssa/src/base.rs +++ b/compiler/rustc_codegen_ssa/src/base.rs @@ -7,7 +7,7 @@ use rustc_ast::expand::allocator::{ALLOCATOR_METHODS, AllocatorKind, global_fn_n use rustc_attr as attr; use rustc_data_structures::fx::{FxHashMap, FxIndexSet}; use rustc_data_structures::profiling::{get_resident_set_size, print_time_passes_entry}; -use rustc_data_structures::sync::par_map; +use rustc_data_structures::sync::{Lrc, par_map}; use rustc_data_structures::unord::UnordMap; use rustc_hir::def_id::{DefId, LOCAL_CRATE}; use rustc_hir::lang_items::LangItem; @@ -21,7 +21,7 @@ use rustc_middle::mir::BinOp; use rustc_middle::mir::mono::{CodegenUnit, CodegenUnitNameBuilder, MonoItem}; use rustc_middle::query::Providers; use rustc_middle::ty::layout::{HasTyCtxt, LayoutOf, TyAndLayout}; -use rustc_middle::ty::{self, Instance, Ty, TyCtxt}; +use rustc_middle::ty::{self, Instance, Ty, TyCtxt, TypingMode}; use rustc_session::Session; use rustc_session::config::{self, CrateType, EntryFnType, OptLevel, OutputType}; use rustc_span::symbol::sym; @@ -119,7 +119,7 @@ pub fn validate_trivial_unsize<'tcx>( ) -> bool { match (source_data.principal(), target_data.principal()) { (Some(hr_source_principal), Some(hr_target_principal)) => { - let infcx = tcx.infer_ctxt().build(); + let infcx = tcx.infer_ctxt().build(TypingMode::PostAnalysis); let universe = infcx.universe(); let ocx = ObligationCtxt::new(&infcx); infcx.enter_forall(hr_target_principal, |target_principal| { @@ -923,7 +923,7 @@ impl CrateInfo { crate_name: UnordMap::with_capacity(n_crates), used_crates, used_crate_source: UnordMap::with_capacity(n_crates), - dependency_formats: tcx.dependency_formats(()).clone(), + dependency_formats: Lrc::clone(tcx.dependency_formats(())), windows_subsystem, natvis_debugger_visualizers: Default::default(), }; @@ -936,7 +936,7 @@ impl CrateInfo { info.crate_name.insert(cnum, tcx.crate_name(cnum)); let used_crate_source = tcx.used_crate_source(cnum); - info.used_crate_source.insert(cnum, used_crate_source.clone()); + info.used_crate_source.insert(cnum, Lrc::clone(used_crate_source)); if tcx.is_profiler_runtime(cnum) { info.profiler_runtime = Some(cnum); } diff --git a/compiler/rustc_codegen_ssa/src/mir/block.rs b/compiler/rustc_codegen_ssa/src/mir/block.rs index e3553dc03e1..a17a127f014 100644 --- a/compiler/rustc_codegen_ssa/src/mir/block.rs +++ b/compiler/rustc_codegen_ssa/src/mir/block.rs @@ -438,7 +438,7 @@ impl<'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>> FunctionCx<'a, 'tcx, Bx> { _ => bug!("C-variadic function must have a `VaList` place"), } } - if self.fn_abi.ret.layout.abi.is_uninhabited() { + if self.fn_abi.ret.layout.is_uninhabited() { // Functions with uninhabited return values are marked `noreturn`, // so we should make sure that we never actually do. // We play it safe by using a well-defined `abort`, but we could go for immediate UB @@ -774,7 +774,7 @@ impl<'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>> FunctionCx<'a, 'tcx, Bx> { Some(if do_panic { let msg_str = with_no_visible_paths!({ with_no_trimmed_paths!({ - if layout.abi.is_uninhabited() { + if layout.is_uninhabited() { // Use this error even for the other intrinsics as it is more precise. format!("attempted to instantiate uninhabited type `{ty}`") } else if requirement == ValidityRequirement::Zero { diff --git a/compiler/rustc_codegen_ssa/src/mir/place.rs b/compiler/rustc_codegen_ssa/src/mir/place.rs index a7d5541481a..15c8e534461 100644 --- a/compiler/rustc_codegen_ssa/src/mir/place.rs +++ b/compiler/rustc_codegen_ssa/src/mir/place.rs @@ -55,7 +55,7 @@ impl<V: CodegenObject> PlaceValue<V> { /// Creates a `PlaceRef` to this location with the given type. pub fn with_type<'tcx>(self, layout: TyAndLayout<'tcx>) -> PlaceRef<'tcx, V> { assert!( - layout.is_unsized() || layout.abi.is_uninhabited() || self.llextra.is_none(), + layout.is_unsized() || layout.is_uninhabited() || self.llextra.is_none(), "Had pointer metadata {:?} for sized type {layout:?}", self.llextra, ); @@ -239,7 +239,7 @@ impl<'a, 'tcx, V: CodegenObject> PlaceRef<'tcx, V> { let dl = &bx.tcx().data_layout; let cast_to_layout = bx.cx().layout_of(cast_to); let cast_to = bx.cx().immediate_backend_type(cast_to_layout); - if self.layout.abi.is_uninhabited() { + if self.layout.is_uninhabited() { return bx.cx().const_poison(cast_to); } let (tag_scalar, tag_encoding, tag_field) = match self.layout.variants { @@ -358,7 +358,7 @@ impl<'a, 'tcx, V: CodegenObject> PlaceRef<'tcx, V> { bx: &mut Bx, variant_index: VariantIdx, ) { - if self.layout.for_variant(bx.cx(), variant_index).abi.is_uninhabited() { + if self.layout.for_variant(bx.cx(), variant_index).is_uninhabited() { // We play it safe by using a well-defined `abort`, but we could go for immediate UB // if that turns out to be helpful. bx.abort(); diff --git a/compiler/rustc_codegen_ssa/src/mir/rvalue.rs b/compiler/rustc_codegen_ssa/src/mir/rvalue.rs index 82fea4c58e1..6e8c193cd75 100644 --- a/compiler/rustc_codegen_ssa/src/mir/rvalue.rs +++ b/compiler/rustc_codegen_ssa/src/mir/rvalue.rs @@ -203,10 +203,10 @@ impl<'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>> FunctionCx<'a, 'tcx, Bx> { ) -> Option<OperandValue<Bx::Value>> { // Check for transmutes that are always UB. if operand.layout.size != cast.size - || operand.layout.abi.is_uninhabited() - || cast.abi.is_uninhabited() + || operand.layout.is_uninhabited() + || cast.is_uninhabited() { - if !operand.layout.abi.is_uninhabited() { + if !operand.layout.is_uninhabited() { // Since this is known statically and the input could have existed // without already having hit UB, might as well trap for it. bx.abort(); @@ -555,7 +555,7 @@ impl<'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>> FunctionCx<'a, 'tcx, Bx> { assert!(bx.cx().is_backend_immediate(cast)); let to_backend_ty = bx.cx().immediate_backend_type(cast); - if operand.layout.abi.is_uninhabited() { + if operand.layout.is_uninhabited() { let val = OperandValue::Immediate(bx.cx().const_poison(to_backend_ty)); return OperandRef { val, layout: cast }; } diff --git a/compiler/rustc_const_eval/src/check_consts/check.rs b/compiler/rustc_const_eval/src/check_consts/check.rs index 004fb12419f..5210241d5e4 100644 --- a/compiler/rustc_const_eval/src/check_consts/check.rs +++ b/compiler/rustc_const_eval/src/check_consts/check.rs @@ -16,7 +16,7 @@ use rustc_middle::mir::visit::Visitor; use rustc_middle::mir::*; use rustc_middle::span_bug; use rustc_middle::ty::adjustment::PointerCoercion; -use rustc_middle::ty::{self, Instance, InstanceKind, Ty, TypeVisitableExt}; +use rustc_middle::ty::{self, Instance, InstanceKind, Ty, TypeVisitableExt, TypingMode}; use rustc_mir_dataflow::Analysis; use rustc_mir_dataflow::impls::MaybeStorageLive; use rustc_mir_dataflow::storage::always_storage_live_locals; @@ -64,8 +64,7 @@ impl<'mir, 'tcx> Qualifs<'mir, 'tcx> { let ConstCx { tcx, body, .. } = *ccx; FlowSensitiveAnalysis::new(NeedsDrop, ccx) - .into_engine(tcx, body) - .iterate_to_fixpoint() + .iterate_to_fixpoint(tcx, body, None) .into_results_cursor(body) }); @@ -94,8 +93,7 @@ impl<'mir, 'tcx> Qualifs<'mir, 'tcx> { let ConstCx { tcx, body, .. } = *ccx; FlowSensitiveAnalysis::new(NeedsNonConstDrop, ccx) - .into_engine(tcx, body) - .iterate_to_fixpoint() + .iterate_to_fixpoint(tcx, body, None) .into_results_cursor(body) }); @@ -124,8 +122,7 @@ impl<'mir, 'tcx> Qualifs<'mir, 'tcx> { let ConstCx { tcx, body, .. } = *ccx; FlowSensitiveAnalysis::new(HasMutInterior, ccx) - .into_engine(tcx, body) - .iterate_to_fixpoint() + .iterate_to_fixpoint(tcx, body, None) .into_results_cursor(body) }); @@ -240,8 +237,7 @@ impl<'mir, 'tcx> Checker<'mir, 'tcx> { let always_live_locals = &always_storage_live_locals(&ccx.body); let mut maybe_storage_live = MaybeStorageLive::new(Cow::Borrowed(always_live_locals)) - .into_engine(ccx.tcx, &ccx.body) - .iterate_to_fixpoint() + .iterate_to_fixpoint(ccx.tcx, &ccx.body, None) .into_results_cursor(&ccx.body); // And then check all `Return` in the MIR, and if a local is "maybe live" at a @@ -593,7 +589,7 @@ impl<'tcx> Visitor<'tcx> for Checker<'_, 'tcx> { // Typeck only does a "non-const" check since it operates on HIR and cannot distinguish // which path expressions are getting called on and which path expressions are only used // as function pointers. This is required for correctness. - let infcx = tcx.infer_ctxt().build(); + let infcx = tcx.infer_ctxt().build(TypingMode::from_param_env(param_env)); let ocx = ObligationCtxt::new_with_diagnostics(&infcx); let predicates = tcx.predicates_of(callee).instantiate(tcx, fn_args); diff --git a/compiler/rustc_const_eval/src/check_consts/ops.rs b/compiler/rustc_const_eval/src/check_consts/ops.rs index 3ac06ae6491..3f977dc4b05 100644 --- a/compiler/rustc_const_eval/src/check_consts/ops.rs +++ b/compiler/rustc_const_eval/src/check_consts/ops.rs @@ -12,7 +12,7 @@ use rustc_middle::mir::CallSource; use rustc_middle::span_bug; use rustc_middle::ty::print::{PrintTraitRefExt as _, with_no_trimmed_paths}; use rustc_middle::ty::{ - self, Closure, FnDef, FnPtr, GenericArgKind, GenericArgsRef, Param, TraitRef, Ty, + self, Closure, FnDef, FnPtr, GenericArgKind, GenericArgsRef, Param, TraitRef, Ty, TypingMode, suggest_constraining_type_param, }; use rustc_middle::util::{CallDesugaringKind, CallKind, call_kind}; @@ -116,7 +116,7 @@ impl<'tcx> NonConstOp<'tcx> for FnCallNonConst<'tcx> { let obligation = Obligation::new(tcx, ObligationCause::dummy(), param_env, trait_ref); - let infcx = tcx.infer_ctxt().build(); + let infcx = tcx.infer_ctxt().build(TypingMode::from_param_env(param_env)); let mut selcx = SelectionContext::new(&infcx); let implsrc = selcx.select(&obligation); diff --git a/compiler/rustc_const_eval/src/check_consts/qualifs.rs b/compiler/rustc_const_eval/src/check_consts/qualifs.rs index 547030a1854..e8637ba45cf 100644 --- a/compiler/rustc_const_eval/src/check_consts/qualifs.rs +++ b/compiler/rustc_const_eval/src/check_consts/qualifs.rs @@ -114,11 +114,11 @@ impl Qualif for HasMutInterior { ty::TraitRef::new(cx.tcx, freeze_def_id, [ty::GenericArg::from(ty)]), ); - let infcx = cx - .tcx - .infer_ctxt() - .with_opaque_type_inference(cx.body.source.def_id().expect_local()) - .build(); + // FIXME(#132279): This should eventually use the already defined hidden types. + let infcx = cx.tcx.infer_ctxt().build(ty::TypingMode::analysis_in_body( + cx.tcx, + cx.body.source.def_id().expect_local(), + )); let ocx = ObligationCtxt::new(&infcx); ocx.register_obligation(obligation); let errors = ocx.select_all_or_error(); diff --git a/compiler/rustc_const_eval/src/const_eval/machine.rs b/compiler/rustc_const_eval/src/const_eval/machine.rs index d54c5b750f0..5f0bc8539ee 100644 --- a/compiler/rustc_const_eval/src/const_eval/machine.rs +++ b/compiler/rustc_const_eval/src/const_eval/machine.rs @@ -395,7 +395,7 @@ impl<'tcx> interpret::Machine<'tcx> for CompileTimeMachine<'tcx> { #[inline(always)] fn enforce_validity(ecx: &InterpCx<'tcx, Self>, layout: TyAndLayout<'tcx>) -> bool { - ecx.tcx.sess.opts.unstable_opts.extra_const_ub_checks || layout.abi.is_uninhabited() + ecx.tcx.sess.opts.unstable_opts.extra_const_ub_checks || layout.is_uninhabited() } fn load_mir( diff --git a/compiler/rustc_const_eval/src/interpret/discriminant.rs b/compiler/rustc_const_eval/src/interpret/discriminant.rs index 81e0b1e12ca..feed0860679 100644 --- a/compiler/rustc_const_eval/src/interpret/discriminant.rs +++ b/compiler/rustc_const_eval/src/interpret/discriminant.rs @@ -27,7 +27,7 @@ impl<'tcx, M: Machine<'tcx>> InterpCx<'tcx, M> { // discriminant, so we cannot do anything here. // When evaluating we will always error before even getting here, but ConstProp 'executes' // dead code, so we cannot ICE here. - if dest.layout().for_variant(self, variant_index).abi.is_uninhabited() { + if dest.layout().for_variant(self, variant_index).is_uninhabited() { throw_ub!(UninhabitedEnumVariantWritten(variant_index)) } @@ -86,7 +86,7 @@ impl<'tcx, M: Machine<'tcx>> InterpCx<'tcx, M> { // For consistency with `write_discriminant`, and to make sure that // `project_downcast` cannot fail due to strange layouts, we declare immediate UB // for uninhabited variants. - if op.layout().for_variant(self, index).abi.is_uninhabited() { + if op.layout().for_variant(self, index).is_uninhabited() { throw_ub!(UninhabitedEnumVariantRead(index)) } } @@ -203,7 +203,7 @@ impl<'tcx, M: Machine<'tcx>> InterpCx<'tcx, M> { // Reading the discriminant of an uninhabited variant is UB. This is the basis for the // `uninhabited_enum_branching` MIR pass. It also ensures consistency with // `write_discriminant`. - if op.layout().for_variant(self, index).abi.is_uninhabited() { + if op.layout().for_variant(self, index).is_uninhabited() { throw_ub!(UninhabitedEnumVariantRead(index)) } interp_ok(index) diff --git a/compiler/rustc_const_eval/src/interpret/eval_context.rs b/compiler/rustc_const_eval/src/interpret/eval_context.rs index a1c773a4b80..d81368e9fcc 100644 --- a/compiler/rustc_const_eval/src/interpret/eval_context.rs +++ b/compiler/rustc_const_eval/src/interpret/eval_context.rs @@ -9,7 +9,9 @@ use rustc_middle::query::TyCtxtAt; use rustc_middle::ty::layout::{ self, FnAbiError, FnAbiOfHelpers, FnAbiRequest, LayoutError, LayoutOfHelpers, TyAndLayout, }; -use rustc_middle::ty::{self, GenericArgsRef, ParamEnv, Ty, TyCtxt, TypeFoldable, Variance}; +use rustc_middle::ty::{ + self, GenericArgsRef, ParamEnv, Ty, TyCtxt, TypeFoldable, TypingMode, Variance, +}; use rustc_middle::{mir, span_bug}; use rustc_session::Limit; use rustc_span::Span; @@ -325,7 +327,7 @@ impl<'tcx, M: Machine<'tcx>> InterpCx<'tcx, M> { return true; } // Slow path: spin up an inference context to check if these traits are sufficiently equal. - let infcx = self.tcx.infer_ctxt().build(); + let infcx = self.tcx.infer_ctxt().build(TypingMode::from_param_env(self.param_env)); let ocx = ObligationCtxt::new(&infcx); let cause = ObligationCause::dummy_with_span(self.cur_span()); // equate the two trait refs after normalization diff --git a/compiler/rustc_const_eval/src/interpret/intrinsics.rs b/compiler/rustc_const_eval/src/interpret/intrinsics.rs index 4e603f57c56..6148123bdfe 100644 --- a/compiler/rustc_const_eval/src/interpret/intrinsics.rs +++ b/compiler/rustc_const_eval/src/interpret/intrinsics.rs @@ -364,7 +364,7 @@ impl<'tcx, M: Machine<'tcx>> InterpCx<'tcx, M> { let msg = match requirement { // For *all* intrinsics we first check `is_uninhabited` to give a more specific // error message. - _ if layout.abi.is_uninhabited() => format!( + _ if layout.is_uninhabited() => format!( "aborted execution: attempted to instantiate uninhabited type `{ty}`" ), ValidityRequirement::Inhabited => bug!("handled earlier"), diff --git a/compiler/rustc_const_eval/src/interpret/operator.rs b/compiler/rustc_const_eval/src/interpret/operator.rs index b28ac68ac54..380db907481 100644 --- a/compiler/rustc_const_eval/src/interpret/operator.rs +++ b/compiler/rustc_const_eval/src/interpret/operator.rs @@ -315,7 +315,7 @@ impl<'tcx, M: Machine<'tcx>> InterpCx<'tcx, M> { let ptr = left.to_scalar().to_pointer(self)?; let pointee_ty = left.layout.ty.builtin_deref(true).unwrap(); let pointee_layout = self.layout_of(pointee_ty)?; - assert!(pointee_layout.abi.is_sized()); + assert!(pointee_layout.is_sized()); // The size always fits in `i64` as it can be at most `isize::MAX`. let pointee_size = i64::try_from(pointee_layout.size.bytes()).unwrap(); @@ -518,14 +518,14 @@ impl<'tcx, M: Machine<'tcx>> InterpCx<'tcx, M> { interp_ok(match null_op { SizeOf => { - if !layout.abi.is_sized() { + if !layout.is_sized() { span_bug!(self.cur_span(), "unsized type for `NullaryOp::SizeOf`"); } let val = layout.size.bytes(); ImmTy::from_uint(val, usize_layout()) } AlignOf => { - if !layout.abi.is_sized() { + if !layout.is_sized() { span_bug!(self.cur_span(), "unsized type for `NullaryOp::AlignOf`"); } let val = layout.align.abi.bytes(); diff --git a/compiler/rustc_const_eval/src/interpret/validity.rs b/compiler/rustc_const_eval/src/interpret/validity.rs index b6120ce82fe..8b5bb1332e7 100644 --- a/compiler/rustc_const_eval/src/interpret/validity.rs +++ b/compiler/rustc_const_eval/src/interpret/validity.rs @@ -542,7 +542,7 @@ impl<'rt, 'tcx, M: Machine<'tcx>> ValidityVisitor<'rt, 'tcx, M> { throw_validation_failure!(self.path, NullPtr { ptr_kind }) } // Do not allow references to uninhabited types. - if place.layout.abi.is_uninhabited() { + if place.layout.is_uninhabited() { let ty = place.layout.ty; throw_validation_failure!(self.path, PtrToUninhabited { ptr_kind, ty }) } @@ -867,7 +867,7 @@ impl<'rt, 'tcx, M: Machine<'tcx>> ValidityVisitor<'rt, 'tcx, M> { /// Add the entire given place to the "data" range of this visit. fn add_data_range_place(&mut self, place: &PlaceTy<'tcx, M::Provenance>) { // Only sized places can be added this way. - debug_assert!(place.layout.abi.is_sized()); + debug_assert!(place.layout.is_sized()); if let Some(data_bytes) = self.data_bytes.as_mut() { let offset = Self::data_range_offset(self.ecx, place); data_bytes.add_range(offset, place.layout.size); @@ -945,7 +945,7 @@ impl<'rt, 'tcx, M: Machine<'tcx>> ValidityVisitor<'rt, 'tcx, M> { layout: TyAndLayout<'tcx>, ) -> Cow<'e, RangeSet> { assert!(layout.ty.is_union()); - assert!(layout.abi.is_sized(), "there are no unsized unions"); + assert!(layout.is_sized(), "there are no unsized unions"); let layout_cx = LayoutCx::new(*ecx.tcx, ecx.param_env); return M::cached_union_data_range(ecx, layout.ty, || { let mut out = RangeSet(Vec::new()); diff --git a/compiler/rustc_const_eval/src/util/check_validity_requirement.rs b/compiler/rustc_const_eval/src/util/check_validity_requirement.rs index 649179d5b1e..7a8b976dfc4 100644 --- a/compiler/rustc_const_eval/src/util/check_validity_requirement.rs +++ b/compiler/rustc_const_eval/src/util/check_validity_requirement.rs @@ -29,7 +29,7 @@ pub fn check_validity_requirement<'tcx>( // There is nothing strict or lax about inhabitedness. if kind == ValidityRequirement::Inhabited { - return Ok(!layout.abi.is_uninhabited()); + return Ok(!layout.is_uninhabited()); } let layout_cx = LayoutCx::new(tcx, param_env_and_ty.param_env); diff --git a/compiler/rustc_const_eval/src/util/compare_types.rs b/compiler/rustc_const_eval/src/util/compare_types.rs index 3ea54146fc7..7af977bab4d 100644 --- a/compiler/rustc_const_eval/src/util/compare_types.rs +++ b/compiler/rustc_const_eval/src/util/compare_types.rs @@ -5,7 +5,7 @@ use rustc_infer::infer::TyCtxtInferExt; use rustc_middle::traits::ObligationCause; -use rustc_middle::ty::{ParamEnv, Ty, TyCtxt, Variance}; +use rustc_middle::ty::{ParamEnv, Ty, TyCtxt, TypingMode, Variance}; use rustc_trait_selection::traits::ObligationCtxt; /// Returns whether the two types are equal up to subtyping. @@ -45,7 +45,8 @@ pub fn relate_types<'tcx>( } let mut builder = tcx.infer_ctxt().ignoring_regions(); - let infcx = builder.build(); + // FIXME(#132279): This should eventually use the already defined hidden types. + let infcx = builder.build(TypingMode::from_param_env(param_env)); let ocx = ObligationCtxt::new(&infcx); let cause = ObligationCause::dummy(); let src = ocx.normalize(&cause, param_env, src); diff --git a/compiler/rustc_driver_impl/src/lib.rs b/compiler/rustc_driver_impl/src/lib.rs index a59dea557bb..e2585c02388 100644 --- a/compiler/rustc_driver_impl/src/lib.rs +++ b/compiler/rustc_driver_impl/src/lib.rs @@ -1395,7 +1395,7 @@ pub fn install_ice_hook( } let using_internal_features = Arc::new(std::sync::atomic::AtomicBool::default()); - let using_internal_features_hook = using_internal_features.clone(); + let using_internal_features_hook = Arc::clone(&using_internal_features); panic::update_hook(Box::new( move |default_hook: &(dyn Fn(&PanicHookInfo<'_>) + Send + Sync + 'static), info: &PanicHookInfo<'_>| { diff --git a/compiler/rustc_error_codes/src/error_codes/E0539.md b/compiler/rustc_error_codes/src/error_codes/E0539.md index cd28afbc48d..6b2e23ba2d8 100644 --- a/compiler/rustc_error_codes/src/error_codes/E0539.md +++ b/compiler/rustc_error_codes/src/error_codes/E0539.md @@ -45,6 +45,7 @@ const fn unstable_fn() {} #[stable(feature = "stable_struct", since = "1.39.0")] // ok! struct Stable; +#[stable(feature = "stable_fn", since = "1.39.0")] #[rustc_const_stable(feature = "stable_fn", since = "1.39.0")] // ok! const fn stable_fn() {} ``` diff --git a/compiler/rustc_error_codes/src/error_codes/E0542.md b/compiler/rustc_error_codes/src/error_codes/E0542.md index be186dbd2cc..70590f2e48e 100644 --- a/compiler/rustc_error_codes/src/error_codes/E0542.md +++ b/compiler/rustc_error_codes/src/error_codes/E0542.md @@ -30,6 +30,7 @@ To fix this issue, you need to provide the `since` field. Example: #[stable(feature = "_stable_fn", since = "1.0.0")] // ok! fn _stable_fn() {} +#[stable(feature = "_stable_const_fn", since = "1.0.0")] #[rustc_const_stable(feature = "_stable_const_fn", since = "1.0.0")] // ok! const fn _stable_const_fn() {} diff --git a/compiler/rustc_error_codes/src/error_codes/E0667.md b/compiler/rustc_error_codes/src/error_codes/E0667.md index 0709a24c433..339bc068610 100644 --- a/compiler/rustc_error_codes/src/error_codes/E0667.md +++ b/compiler/rustc_error_codes/src/error_codes/E0667.md @@ -1,8 +1,10 @@ +#### Note: this error code is no longer emitted by the compiler. + `impl Trait` is not allowed in path parameters. Erroneous code example: -```compile_fail,E0667 +```ignore (removed error code) fn some_fn(mut x: impl Iterator) -> <impl Iterator>::Item { // error! x.next().unwrap() } @@ -11,7 +13,7 @@ fn some_fn(mut x: impl Iterator) -> <impl Iterator>::Item { // error! You cannot use `impl Trait` in path parameters. If you want something equivalent, you can do this instead: -``` +```ignore (removed error code) fn some_fn<T: Iterator>(mut x: T) -> T::Item { // ok! x.next().unwrap() } diff --git a/compiler/rustc_error_codes/src/error_codes/E0801.md b/compiler/rustc_error_codes/src/error_codes/E0801.md new file mode 100644 index 00000000000..c89feb9b308 --- /dev/null +++ b/compiler/rustc_error_codes/src/error_codes/E0801.md @@ -0,0 +1,51 @@ +The `self` parameter in a method has an invalid generic "receiver type". + +Erroneous code example: + +```compile_fail,E0801 +struct Foo; + +impl Foo { + fn foo<R: std::ops::Deref<Target=Self>>(self: R) {} +} +``` + +or alternatively, + +```compile_fail,E0801 +struct Foo; + +impl Foo { + fn foo(self: impl std::ops::Deref<Target=Self>) {} +} +``` + +Methods take a special first parameter, termed `self`. It's normal to +use `self`, `&self` or `&mut self`, which are syntactic sugar for +`self: Self`, `self: &Self`, and `self: &mut Self` respectively. +But it's also possible to use more sophisticated types of `self` +parameter, for instance `std::rc::Rc<Self>`. The set of allowable +`Self` types is extensible using the nightly feature +[Arbitrary self types][AST]. +This will extend the valid set of `Self` types to anything which implements +`std::ops::Deref<Target=Self>`, for example `Rc<Self>`, `Box<Self>`, or +your own smart pointers that do the same. + +However, even with that feature, the `self` type must be concrete. +Generic `self` types are not permitted. Specifically, a `self` type will +be rejected if it is a type parameter defined on the method. + +These are OK: + +``` +struct Foo; + +impl Foo { + fn foo(self) {} + fn foo2(self: std::rc::Rc<Self>) {} // or some other similar + // smart pointer if you enable arbitrary self types and + // the pointer implements Deref<Target=Self> +} +``` + +[AST]: https://doc.rust-lang.org/unstable-book/language-features/arbitrary-self-types.html diff --git a/compiler/rustc_error_codes/src/lib.rs b/compiler/rustc_error_codes/src/lib.rs index 27a34d6003d..29f3277d399 100644 --- a/compiler/rustc_error_codes/src/lib.rs +++ b/compiler/rustc_error_codes/src/lib.rs @@ -540,6 +540,7 @@ E0797: 0797, E0798: 0798, E0799: 0799, E0800: 0800, +E0801: 0801, ); ) } diff --git a/compiler/rustc_errors/Cargo.toml b/compiler/rustc_errors/Cargo.toml index 00eaf4d5a86..41ebe4ae267 100644 --- a/compiler/rustc_errors/Cargo.toml +++ b/compiler/rustc_errors/Cargo.toml @@ -7,6 +7,7 @@ edition = "2021" # tidy-alphabetical-start annotate-snippets = "0.11" derive_setters = "0.1.6" +rustc_abi = { path = "../rustc_abi" } rustc_ast = { path = "../rustc_ast" } rustc_ast_pretty = { path = "../rustc_ast_pretty" } rustc_data_structures = { path = "../rustc_data_structures" } diff --git a/compiler/rustc_errors/src/annotate_snippet_emitter_writer.rs b/compiler/rustc_errors/src/annotate_snippet_emitter_writer.rs index 335432c9cfe..b4a651b10b1 100644 --- a/compiler/rustc_errors/src/annotate_snippet_emitter_writer.rs +++ b/compiler/rustc_errors/src/annotate_snippet_emitter_writer.rs @@ -173,7 +173,7 @@ impl AnnotateSnippetEmitter { source_map.ensure_source_file_source_present(&file); ( format!("{}", source_map.filename_for_diagnostics(&file.name)), - source_string(file.clone(), &line), + source_string(Lrc::clone(&file), &line), line.line_index, line.annotations, ) diff --git a/compiler/rustc_errors/src/diagnostic_impls.rs b/compiler/rustc_errors/src/diagnostic_impls.rs index 19529f06ef1..09a608dda7b 100644 --- a/compiler/rustc_errors/src/diagnostic_impls.rs +++ b/compiler/rustc_errors/src/diagnostic_impls.rs @@ -5,12 +5,12 @@ use std::num::ParseIntError; use std::path::{Path, PathBuf}; use std::process::ExitStatus; +use rustc_abi::TargetDataLayoutErrors; use rustc_ast_pretty::pprust; use rustc_macros::Subdiagnostic; use rustc_span::Span; use rustc_span::edition::Edition; use rustc_span::symbol::{Ident, MacroRulesNormalizedIdent, Symbol}; -use rustc_target::abi::TargetDataLayoutErrors; use rustc_target::spec::{PanicStrategy, SplitDebuginfo, StackProtector, TargetTriple}; use rustc_type_ir::{ClosureKind, FloatTy}; use {rustc_ast as ast, rustc_hir as hir}; diff --git a/compiler/rustc_errors/src/emitter.rs b/compiler/rustc_errors/src/emitter.rs index 0ccc71ae06c..6552cf224ea 100644 --- a/compiler/rustc_errors/src/emitter.rs +++ b/compiler/rustc_errors/src/emitter.rs @@ -1555,7 +1555,7 @@ impl HumanEmitter { // Get the left-side margin to remove it let mut whitespace_margin = usize::MAX; for line_idx in 0..annotated_file.lines.len() { - let file = annotated_file.file.clone(); + let file = Lrc::clone(&annotated_file.file); let line = &annotated_file.lines[line_idx]; if let Some(source_string) = line.line_index.checked_sub(1).and_then(|l| file.get_line(l)) @@ -1646,7 +1646,7 @@ impl HumanEmitter { let depths = self.render_source_line( &mut buffer, - annotated_file.file.clone(), + Lrc::clone(&annotated_file.file), &annotated_file.lines[line_idx], width_offset, code_offset, @@ -2529,7 +2529,12 @@ impl FileWithAnnotatedLines { // | | | // | |______foo // | baz - add_annotation_to_file(&mut output, file.clone(), ann.line_start, ann.as_start()); + add_annotation_to_file( + &mut output, + Lrc::clone(&file), + ann.line_start, + ann.as_start(), + ); // 4 is the minimum vertical length of a multiline span when presented: two lines // of code and two lines of underline. This is not true for the special case where // the beginning doesn't have an underline, but the current logic seems to be @@ -2545,11 +2550,11 @@ impl FileWithAnnotatedLines { .unwrap_or(ann.line_start); for line in ann.line_start + 1..until { // Every `|` that joins the beginning of the span (`___^`) to the end (`|__^`). - add_annotation_to_file(&mut output, file.clone(), line, ann.as_line()); + add_annotation_to_file(&mut output, Lrc::clone(&file), line, ann.as_line()); } let line_end = ann.line_end - 1; if middle < line_end { - add_annotation_to_file(&mut output, file.clone(), line_end, ann.as_line()); + add_annotation_to_file(&mut output, Lrc::clone(&file), line_end, ann.as_line()); } } else { end_ann.annotation_type = AnnotationType::Singleline; diff --git a/compiler/rustc_errors/src/json.rs b/compiler/rustc_errors/src/json.rs index 1534e256520..91e2b9996cd 100644 --- a/compiler/rustc_errors/src/json.rs +++ b/compiler/rustc_errors/src/json.rs @@ -367,9 +367,9 @@ impl Diagnostic { ColorConfig::Always | ColorConfig::Auto => dst = Box::new(termcolor::Ansi::new(dst)), ColorConfig::Never => {} } - HumanEmitter::new(dst, je.fallback_bundle.clone()) + HumanEmitter::new(dst, Lrc::clone(&je.fallback_bundle)) .short_message(short) - .sm(Some(je.sm.clone())) + .sm(Some(Lrc::clone(&je.sm))) .fluent_bundle(je.fluent_bundle.clone()) .diagnostic_width(je.diagnostic_width) .macro_backtrace(je.macro_backtrace) diff --git a/compiler/rustc_expand/messages.ftl b/compiler/rustc_expand/messages.ftl index fcf3352bfc5..f26c7c1ba0b 100644 --- a/compiler/rustc_expand/messages.ftl +++ b/compiler/rustc_expand/messages.ftl @@ -74,7 +74,7 @@ expand_helper_attribute_name_invalid = `{$name}` cannot be a name of derive helper attribute expand_incomplete_parse = - macro expansion ignores token `{$token}` and any following + macro expansion ignores {$descr} and any tokens following .label = caused by the macro expansion here .note = the usage of `{$macro_path}!` is likely invalid in {$kind_name} context .suggestion_add_semi = you might be missing a semicolon here diff --git a/compiler/rustc_expand/src/errors.rs b/compiler/rustc_expand/src/errors.rs index 5682c574552..7bd7c305539 100644 --- a/compiler/rustc_expand/src/errors.rs +++ b/compiler/rustc_expand/src/errors.rs @@ -275,7 +275,7 @@ pub(crate) struct UnsupportedKeyValue { pub(crate) struct IncompleteParse<'a> { #[primary_span] pub span: Span, - pub token: Cow<'a, str>, + pub descr: String, #[label] pub label_span: Span, pub macro_path: &'a ast::Path, diff --git a/compiler/rustc_expand/src/expand.rs b/compiler/rustc_expand/src/expand.rs index 5ffafcaa542..04ac7891023 100644 --- a/compiler/rustc_expand/src/expand.rs +++ b/compiler/rustc_expand/src/expand.rs @@ -21,6 +21,7 @@ use rustc_errors::PResult; use rustc_feature::Features; use rustc_parse::parser::{ AttemptLocalParseRecovery, CommaRecoveryMode, ForceCollect, Parser, RecoverColon, RecoverComma, + token_descr, }; use rustc_parse::validate_attr; use rustc_session::lint::BuiltinLintDiag; @@ -1013,7 +1014,7 @@ pub(crate) fn ensure_complete_parse<'a>( span: Span, ) { if parser.token != token::Eof { - let token = pprust::token_to_string(&parser.token); + let descr = token_descr(&parser.token); // Avoid emitting backtrace info twice. let def_site_span = parser.token.span.with_ctxt(SyntaxContext::root()); @@ -1029,7 +1030,7 @@ pub(crate) fn ensure_complete_parse<'a>( parser.dcx().emit_err(IncompleteParse { span: def_site_span, - token, + descr, label_span: span, macro_path, kind_name, diff --git a/compiler/rustc_expand/src/mbe/diagnostics.rs b/compiler/rustc_expand/src/mbe/diagnostics.rs index 103bbb05e7f..ffcce1e52f6 100644 --- a/compiler/rustc_expand/src/mbe/diagnostics.rs +++ b/compiler/rustc_expand/src/mbe/diagnostics.rs @@ -2,10 +2,9 @@ use std::borrow::Cow; use rustc_ast::token::{self, Token, TokenKind}; use rustc_ast::tokenstream::TokenStream; -use rustc_ast_pretty::pprust; use rustc_errors::{Applicability, Diag, DiagCtxtHandle, DiagMessage}; use rustc_macros::Subdiagnostic; -use rustc_parse::parser::{Parser, Recovery}; +use rustc_parse::parser::{Parser, Recovery, token_descr}; use rustc_session::parse::ParseSess; use rustc_span::source_map::SourceMap; use rustc_span::symbol::Ident; @@ -336,17 +335,11 @@ pub(super) fn annotate_doc_comment(err: &mut Diag<'_>, sm: &SourceMap, span: Spa /// other tokens, this is "unexpected token...". pub(super) fn parse_failure_msg(tok: &Token, expected_token: Option<&Token>) -> Cow<'static, str> { if let Some(expected_token) = expected_token { - Cow::from(format!( - "expected `{}`, found `{}`", - pprust::token_to_string(expected_token), - pprust::token_to_string(tok), - )) + Cow::from(format!("expected {}, found {}", token_descr(expected_token), token_descr(tok))) } else { match tok.kind { token::Eof => Cow::from("unexpected end of macro invocation"), - _ => { - Cow::from(format!("no rules expected the token `{}`", pprust::token_to_string(tok))) - } + _ => Cow::from(format!("no rules expected {}", token_descr(tok))), } } } diff --git a/compiler/rustc_expand/src/mbe/macro_parser.rs b/compiler/rustc_expand/src/mbe/macro_parser.rs index 3903203da3d..2a8dddc1e00 100644 --- a/compiler/rustc_expand/src/mbe/macro_parser.rs +++ b/compiler/rustc_expand/src/mbe/macro_parser.rs @@ -78,11 +78,10 @@ use std::rc::Rc; pub(crate) use NamedMatch::*; pub(crate) use ParseResult::*; use rustc_ast::token::{self, DocComment, NonterminalKind, Token}; -use rustc_ast_pretty::pprust; use rustc_data_structures::fx::FxHashMap; use rustc_errors::ErrorGuaranteed; use rustc_lint_defs::pluralize; -use rustc_parse::parser::{ParseNtResult, Parser}; +use rustc_parse::parser::{ParseNtResult, Parser, token_descr}; use rustc_span::Span; use rustc_span::symbol::{Ident, MacroRulesNormalizedIdent}; @@ -150,7 +149,7 @@ impl Display for MatcherLoc { fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { match self { MatcherLoc::Token { token } | MatcherLoc::SequenceSep { separator: token } => { - write!(f, "`{}`", pprust::token_to_string(token)) + write!(f, "{}", token_descr(token)) } MatcherLoc::MetaVarDecl { bind, kind, .. } => { write!(f, "meta-variable `${bind}")?; @@ -622,7 +621,7 @@ impl TtParser { // possible next positions into `next_mps`. After some post-processing, the contents of // `next_mps` replenish `cur_mps` and we start over again. self.cur_mps.clear(); - self.cur_mps.push(MatcherPos { idx: 0, matches: self.empty_matches.clone() }); + self.cur_mps.push(MatcherPos { idx: 0, matches: Rc::clone(&self.empty_matches) }); loop { self.next_mps.clear(); diff --git a/compiler/rustc_expand/src/mbe/macro_rules.rs b/compiler/rustc_expand/src/mbe/macro_rules.rs index f40f99b6ea1..fcc90c3ce0d 100644 --- a/compiler/rustc_expand/src/mbe/macro_rules.rs +++ b/compiler/rustc_expand/src/mbe/macro_rules.rs @@ -3,12 +3,11 @@ use std::collections::hash_map::Entry; use std::{mem, slice}; use ast::token::IdentIsRaw; -use rustc_ast as ast; use rustc_ast::token::NtPatKind::*; use rustc_ast::token::TokenKind::*; use rustc_ast::token::{self, Delimiter, NonterminalKind, Token, TokenKind}; use rustc_ast::tokenstream::{DelimSpan, TokenStream}; -use rustc_ast::{DUMMY_NODE_ID, NodeId}; +use rustc_ast::{self as ast, DUMMY_NODE_ID, NodeId}; use rustc_ast_pretty::pprust; use rustc_attr::{self as attr, TransparencyError}; use rustc_data_structures::fx::{FxHashMap, FxIndexMap}; @@ -370,34 +369,32 @@ pub(super) fn try_match_macro<'matcher, T: Tracker<'matcher>>( pub fn compile_declarative_macro( sess: &Session, features: &Features, - def: &ast::Item, + macro_def: &ast::MacroDef, + ident: Ident, + attrs: &[ast::Attribute], + span: Span, + node_id: NodeId, edition: Edition, ) -> (SyntaxExtension, Vec<(usize, Span)>) { - debug!("compile_declarative_macro: {:?}", def); let mk_syn_ext = |expander| { SyntaxExtension::new( sess, features, SyntaxExtensionKind::LegacyBang(expander), - def.span, + span, Vec::new(), edition, - def.ident.name, - &def.attrs, - def.id != DUMMY_NODE_ID, + ident.name, + attrs, + node_id != DUMMY_NODE_ID, ) }; let dummy_syn_ext = |guar| (mk_syn_ext(Box::new(DummyExpander(guar))), Vec::new()); let dcx = sess.dcx(); - let lhs_nm = Ident::new(sym::lhs, def.span); - let rhs_nm = Ident::new(sym::rhs, def.span); + let lhs_nm = Ident::new(sym::lhs, span); + let rhs_nm = Ident::new(sym::rhs, span); let tt_spec = Some(NonterminalKind::TT); - - let macro_def = match &def.kind { - ast::ItemKind::MacroDef(def) => def, - _ => unreachable!(), - }; let macro_rules = macro_def.macro_rules; // Parse the macro_rules! invocation @@ -410,25 +407,22 @@ pub fn compile_declarative_macro( let argument_gram = vec![ mbe::TokenTree::Sequence(DelimSpan::dummy(), mbe::SequenceRepetition { tts: vec![ - mbe::TokenTree::MetaVarDecl(def.span, lhs_nm, tt_spec), - mbe::TokenTree::token(token::FatArrow, def.span), - mbe::TokenTree::MetaVarDecl(def.span, rhs_nm, tt_spec), + mbe::TokenTree::MetaVarDecl(span, lhs_nm, tt_spec), + mbe::TokenTree::token(token::FatArrow, span), + mbe::TokenTree::MetaVarDecl(span, rhs_nm, tt_spec), ], - separator: Some(Token::new( - if macro_rules { token::Semi } else { token::Comma }, - def.span, - )), - kleene: mbe::KleeneToken::new(mbe::KleeneOp::OneOrMore, def.span), + separator: Some(Token::new(if macro_rules { token::Semi } else { token::Comma }, span)), + kleene: mbe::KleeneToken::new(mbe::KleeneOp::OneOrMore, span), num_captures: 2, }), // to phase into semicolon-termination instead of semicolon-separation mbe::TokenTree::Sequence(DelimSpan::dummy(), mbe::SequenceRepetition { tts: vec![mbe::TokenTree::token( if macro_rules { token::Semi } else { token::Comma }, - def.span, + span, )], separator: None, - kleene: mbe::KleeneToken::new(mbe::KleeneOp::ZeroOrMore, def.span), + kleene: mbe::KleeneToken::new(mbe::KleeneOp::ZeroOrMore, span), num_captures: 0, }), ]; @@ -460,7 +454,7 @@ pub fn compile_declarative_macro( }; let s = parse_failure_msg(&token, track.get_expected_token()); - let sp = token.span.substitute_dummy(def.span); + let sp = token.span.substitute_dummy(span); let mut err = sess.dcx().struct_span_err(sp, s); err.span_label(sp, msg); annotate_doc_comment(&mut err, sess.source_map(), sp); @@ -468,7 +462,7 @@ pub fn compile_declarative_macro( return dummy_syn_ext(guar); } Error(sp, msg) => { - let guar = sess.dcx().span_err(sp.substitute_dummy(def.span), msg); + let guar = sess.dcx().span_err(sp.substitute_dummy(span), msg); return dummy_syn_ext(guar); } ErrorReported(guar) => { @@ -489,7 +483,7 @@ pub fn compile_declarative_macro( &TokenStream::new(vec![tt.clone()]), true, sess, - def.id, + node_id, features, edition, ) @@ -497,13 +491,13 @@ pub fn compile_declarative_macro( .unwrap(); // We don't handle errors here, the driver will abort // after parsing/expansion. We can report every error in every macro this way. - check_emission(check_lhs_nt_follows(sess, def, &tt)); + check_emission(check_lhs_nt_follows(sess, node_id, &tt)); return tt; } - sess.dcx().span_bug(def.span, "wrong-structured lhs") + sess.dcx().span_bug(span, "wrong-structured lhs") }) .collect::<Vec<mbe::TokenTree>>(), - _ => sess.dcx().span_bug(def.span, "wrong-structured lhs"), + _ => sess.dcx().span_bug(span, "wrong-structured lhs"), }; let rhses = match &argument_map[&MacroRulesNormalizedIdent::new(rhs_nm)] { @@ -515,17 +509,17 @@ pub fn compile_declarative_macro( &TokenStream::new(vec![tt.clone()]), false, sess, - def.id, + node_id, features, edition, ) .pop() .unwrap(); } - sess.dcx().span_bug(def.span, "wrong-structured rhs") + sess.dcx().span_bug(span, "wrong-structured rhs") }) .collect::<Vec<mbe::TokenTree>>(), - _ => sess.dcx().span_bug(def.span, "wrong-structured rhs"), + _ => sess.dcx().span_bug(span, "wrong-structured rhs"), }; for rhs in &rhses { @@ -537,15 +531,9 @@ pub fn compile_declarative_macro( check_emission(check_lhs_no_empty_seq(sess, slice::from_ref(lhs))); } - check_emission(macro_check::check_meta_variables( - &sess.psess, - def.id, - def.span, - &lhses, - &rhses, - )); + check_emission(macro_check::check_meta_variables(&sess.psess, node_id, span, &lhses, &rhses)); - let (transparency, transparency_error) = attr::find_transparency(&def.attrs, macro_rules); + let (transparency, transparency_error) = attr::find_transparency(attrs, macro_rules); match transparency_error { Some(TransparencyError::UnknownTransparency(value, span)) => { dcx.span_err(span, format!("unknown macro transparency: `{value}`")); @@ -564,7 +552,7 @@ pub fn compile_declarative_macro( // Compute the spans of the macro rules for unused rule linting. // Also, we are only interested in non-foreign macros. - let rule_spans = if def.id != DUMMY_NODE_ID { + let rule_spans = if node_id != DUMMY_NODE_ID { lhses .iter() .zip(rhses.iter()) @@ -590,15 +578,15 @@ pub fn compile_declarative_macro( mbe::TokenTree::Delimited(.., delimited) => { mbe::macro_parser::compute_locs(&delimited.tts) } - _ => sess.dcx().span_bug(def.span, "malformed macro lhs"), + _ => sess.dcx().span_bug(span, "malformed macro lhs"), } }) .collect(); let expander = Box::new(MacroRulesMacroExpander { - name: def.ident, - span: def.span, - node_id: def.id, + name: ident, + span, + node_id, transparency, lhses, rhses, @@ -608,13 +596,13 @@ pub fn compile_declarative_macro( fn check_lhs_nt_follows( sess: &Session, - def: &ast::Item, + node_id: NodeId, lhs: &mbe::TokenTree, ) -> Result<(), ErrorGuaranteed> { // lhs is going to be like TokenTree::Delimited(...), where the // entire lhs is those tts. Or, it can be a "bare sequence", not wrapped in parens. if let mbe::TokenTree::Delimited(.., delimited) = lhs { - check_matcher(sess, def, &delimited.tts) + check_matcher(sess, node_id, &delimited.tts) } else { let msg = "invalid macro matcher; matchers must be contained in balanced delimiters"; Err(sess.dcx().span_err(lhs.span(), msg)) @@ -686,12 +674,12 @@ fn check_rhs(sess: &Session, rhs: &mbe::TokenTree) -> Result<(), ErrorGuaranteed fn check_matcher( sess: &Session, - def: &ast::Item, + node_id: NodeId, matcher: &[mbe::TokenTree], ) -> Result<(), ErrorGuaranteed> { let first_sets = FirstSets::new(matcher); let empty_suffix = TokenSet::empty(); - check_matcher_core(sess, def, &first_sets, matcher, &empty_suffix)?; + check_matcher_core(sess, node_id, &first_sets, matcher, &empty_suffix)?; Ok(()) } @@ -1028,7 +1016,7 @@ impl<'tt> TokenSet<'tt> { // see `FirstSets::new`. fn check_matcher_core<'tt>( sess: &Session, - def: &ast::Item, + node_id: NodeId, first_sets: &FirstSets<'tt>, matcher: &'tt [mbe::TokenTree], follow: &TokenSet<'tt>, @@ -1082,7 +1070,7 @@ fn check_matcher_core<'tt>( token::CloseDelim(d.delim), span.close, )); - check_matcher_core(sess, def, first_sets, &d.tts, &my_suffix)?; + check_matcher_core(sess, node_id, first_sets, &d.tts, &my_suffix)?; // don't track non NT tokens last.replace_with_irrelevant(); @@ -1114,7 +1102,7 @@ fn check_matcher_core<'tt>( // At this point, `suffix_first` is built, and // `my_suffix` is some TokenSet that we can use // for checking the interior of `seq_rep`. - let next = check_matcher_core(sess, def, first_sets, &seq_rep.tts, my_suffix)?; + let next = check_matcher_core(sess, node_id, first_sets, &seq_rep.tts, my_suffix)?; if next.maybe_empty { last.add_all(&next); } else { @@ -1144,7 +1132,7 @@ fn check_matcher_core<'tt>( // macro. (See #86567.) // Macros defined in the current crate have a real node id, // whereas macros from an external crate have a dummy id. - if def.id != DUMMY_NODE_ID + if node_id != DUMMY_NODE_ID && matches!(kind, NonterminalKind::Pat(PatParam { inferred: true })) && matches!( next_token, diff --git a/compiler/rustc_expand/src/mbe/transcribe.rs b/compiler/rustc_expand/src/mbe/transcribe.rs index 34811ca2b35..b77d02e630a 100644 --- a/compiler/rustc_expand/src/mbe/transcribe.rs +++ b/compiler/rustc_expand/src/mbe/transcribe.rs @@ -5,6 +5,7 @@ use rustc_ast::mut_visit::{self, MutVisitor}; use rustc_ast::token::{self, Delimiter, IdentIsRaw, Lit, LitKind, Nonterminal, Token, TokenKind}; use rustc_ast::tokenstream::{DelimSpacing, DelimSpan, Spacing, TokenStream, TokenTree}; use rustc_data_structures::fx::FxHashMap; +use rustc_data_structures::sync::Lrc; use rustc_errors::{Diag, DiagCtxtHandle, PResult, pluralize}; use rustc_parse::lexer::nfc_normalize; use rustc_parse::parser::ParseNtResult; @@ -293,7 +294,7 @@ pub(super) fn transcribe<'a>( // `Delimiter::Invisible` to maintain parsing priorities. // `Interpolated` is currently used for such groups in rustc parser. marker.visit_span(&mut sp); - TokenTree::token_alone(token::Interpolated(nt.clone()), sp) + TokenTree::token_alone(token::Interpolated(Lrc::clone(nt)), sp) } MatchedSeq(..) => { // We were unable to descend far enough. This is an error. diff --git a/compiler/rustc_feature/src/accepted.rs b/compiler/rustc_feature/src/accepted.rs index ac922f184dd..e910415c345 100644 --- a/compiler/rustc_feature/src/accepted.rs +++ b/compiler/rustc_feature/src/accepted.rs @@ -224,6 +224,8 @@ declare_features! ( (accepted, i128_type, "1.26.0", Some(35118)), /// Allows the use of `if let` expressions. (accepted, if_let, "1.0.0", None), + /// Rescoping temporaries in `if let` to align with Rust 2024. + (accepted, if_let_rescope, "CURRENT_RUSTC_VERSION", Some(124085)), /// Allows top level or-patterns (`p | q`) in `if let` and `while let`. (accepted, if_while_or_patterns, "1.33.0", Some(48215)), /// Allows lifetime elision in `impl` headers. For example: diff --git a/compiler/rustc_feature/src/removed.rs b/compiler/rustc_feature/src/removed.rs index fe3a67fd667..8d2e1e8c804 100644 --- a/compiler/rustc_feature/src/removed.rs +++ b/compiler/rustc_feature/src/removed.rs @@ -85,6 +85,8 @@ declare_features! ( /// Allows default type parameters to influence type inference. (removed, default_type_parameter_fallback, "1.82.0", Some(27336), Some("never properly implemented; requires significant design work")), + /// Allows deriving traits as per `SmartPointer` specification + (removed, derive_smart_pointer, "1.79.0", Some(123430), Some("replaced by `CoercePointee`")), /// Allows using `#[doc(keyword = "...")]`. (removed, doc_keyword, "1.28.0", Some(51315), Some("merged into `#![feature(rustdoc_internals)]`")), diff --git a/compiler/rustc_feature/src/unstable.rs b/compiler/rustc_feature/src/unstable.rs index a81058e6ea1..a99d9048886 100644 --- a/compiler/rustc_feature/src/unstable.rs +++ b/compiler/rustc_feature/src/unstable.rs @@ -450,8 +450,6 @@ declare_features! ( (unstable, deprecated_suggestion, "1.61.0", Some(94785)), /// Allows deref patterns. (incomplete, deref_patterns, "1.79.0", Some(87121)), - /// Allows deriving `SmartPointer` traits - (unstable, derive_smart_pointer, "1.79.0", Some(123430)), /// Controls errors in trait implementations. (unstable, do_not_recommend, "1.67.0", Some(51992)), /// Tells rustdoc to automatically generate `#[doc(cfg(...))]`. @@ -507,8 +505,6 @@ declare_features! ( (unstable, half_open_range_patterns_in_slices, "1.66.0", Some(67264)), /// Allows `if let` guard in match arms. (unstable, if_let_guard, "1.47.0", Some(51114)), - /// Rescoping temporaries in `if let` to align with Rust 2024. - (unstable, if_let_rescope, "1.83.0", Some(124085)), /// Allows `impl Trait` to be used inside associated types (RFC 2515). (unstable, impl_trait_in_assoc_type, "1.70.0", Some(63063)), /// Allows `impl Trait` as output type in `Fn` traits in return position of functions. diff --git a/compiler/rustc_hir/src/hir.rs b/compiler/rustc_hir/src/hir.rs index 1c268c8bbe0..12b01266a93 100644 --- a/compiler/rustc_hir/src/hir.rs +++ b/compiler/rustc_hir/src/hir.rs @@ -2627,7 +2627,6 @@ impl<'hir> Ty<'hir> { } TyKind::Tup(tys) => tys.iter().any(Self::is_suggestable_infer_ty), TyKind::Ptr(mut_ty) | TyKind::Ref(_, mut_ty) => mut_ty.ty.is_suggestable_infer_ty(), - TyKind::OpaqueDef(_, generic_args) => are_suggestable_generic_args(generic_args), TyKind::Path(QPath::TypeRelative(ty, segment)) => { ty.is_suggestable_infer_ty() || are_suggestable_generic_args(segment.args().args) } @@ -2746,19 +2745,8 @@ pub struct BareFnTy<'hir> { pub struct OpaqueTy<'hir> { pub hir_id: HirId, pub def_id: LocalDefId, - pub generics: &'hir Generics<'hir>, pub bounds: GenericBounds<'hir>, pub origin: OpaqueTyOrigin, - /// Return-position impl traits (and async futures) must "reify" any late-bound - /// lifetimes that are captured from the function signature they originate from. - /// - /// This is done by generating a new early-bound lifetime parameter local to the - /// opaque which is instantiated in the function signature with the late-bound - /// lifetime. - /// - /// This mapping associated a captured lifetime (first parameter) with the new - /// early-bound lifetime that was generated for the opaque. - pub lifetime_mapping: &'hir [(&'hir Lifetime, LocalDefId)], pub span: Span, } @@ -2861,12 +2849,7 @@ pub enum TyKind<'hir> { /// Type parameters may be stored in each `PathSegment`. Path(QPath<'hir>), /// An opaque type definition itself. This is only used for `impl Trait`. - /// - /// The generic argument list contains the lifetimes (and in the future - /// possibly parameters) that are actually bound on the `impl Trait`. - /// - /// The last parameter specifies whether this opaque appears in a trait definition. - OpaqueDef(&'hir OpaqueTy<'hir>, &'hir [GenericArg<'hir>]), + OpaqueDef(&'hir OpaqueTy<'hir>), /// A trait object type `Bound1 + Bound2 + Bound3` /// where `Bound` is a trait or a lifetime. TraitObject(&'hir [PolyTraitRef<'hir>], &'hir Lifetime, TraitObjectSyntax), @@ -3991,7 +3974,6 @@ impl<'hir> Node<'hir> { | Node::TraitItem(TraitItem { generics, .. }) | Node::ImplItem(ImplItem { generics, .. }) => Some(generics), Node::Item(item) => item.kind.generics(), - Node::OpaqueTy(opaque) => Some(opaque.generics), _ => None, } } diff --git a/compiler/rustc_hir/src/intravisit.rs b/compiler/rustc_hir/src/intravisit.rs index 322f8e2a517..a453af3f7fd 100644 --- a/compiler/rustc_hir/src/intravisit.rs +++ b/compiler/rustc_hir/src/intravisit.rs @@ -896,9 +896,8 @@ pub fn walk_ty<'v, V: Visitor<'v>>(visitor: &mut V, typ: &'v Ty<'v>) -> V::Resul TyKind::Path(ref qpath) => { try_visit!(visitor.visit_qpath(qpath, typ.hir_id, typ.span)); } - TyKind::OpaqueDef(opaque, lifetimes) => { + TyKind::OpaqueDef(opaque) => { try_visit!(visitor.visit_opaque_ty(opaque)); - walk_list!(visitor, visit_generic_arg, lifetimes); } TyKind::Array(ref ty, ref length) => { try_visit!(visitor.visit_ty(ty)); @@ -1188,10 +1187,8 @@ pub fn walk_poly_trait_ref<'v, V: Visitor<'v>>( } pub fn walk_opaque_ty<'v, V: Visitor<'v>>(visitor: &mut V, opaque: &'v OpaqueTy<'v>) -> V::Result { - let &OpaqueTy { hir_id, def_id: _, generics, bounds, origin: _, lifetime_mapping: _, span: _ } = - opaque; + let &OpaqueTy { hir_id, def_id: _, bounds, origin: _, span: _ } = opaque; try_visit!(visitor.visit_id(hir_id)); - try_visit!(walk_generics(visitor, generics)); walk_list!(visitor, visit_param_bound, bounds); V::Result::output() } diff --git a/compiler/rustc_hir_analysis/Cargo.toml b/compiler/rustc_hir_analysis/Cargo.toml index 04ca7f123d3..3c8887f08bc 100644 --- a/compiler/rustc_hir_analysis/Cargo.toml +++ b/compiler/rustc_hir_analysis/Cargo.toml @@ -10,6 +10,7 @@ doctest = false [dependencies] # tidy-alphabetical-start itertools = "0.12" +rustc_abi = { path = "../rustc_abi" } rustc_arena = { path = "../rustc_arena" } rustc_ast = { path = "../rustc_ast" } rustc_attr = { path = "../rustc_attr" } diff --git a/compiler/rustc_hir_analysis/messages.ftl b/compiler/rustc_hir_analysis/messages.ftl index 507297ce162..38b11aa4017 100644 --- a/compiler/rustc_hir_analysis/messages.ftl +++ b/compiler/rustc_hir_analysis/messages.ftl @@ -149,10 +149,6 @@ hir_analysis_drop_impl_reservation = reservation `Drop` impls are not supported hir_analysis_duplicate_precise_capture = cannot capture parameter `{$name}` twice .label = parameter captured again here -hir_analysis_effects_without_next_solver = using `#![feature(effects)]` without enabling next trait solver globally - .note = the next trait solver must be enabled globally for the effects feature to work correctly - .help = use `-Znext-solver` to enable - hir_analysis_empty_specialization = specialization impl does not specialize any associated items .note = impl is a specialization of this impl @@ -238,6 +234,12 @@ hir_analysis_inherent_ty_outside_relevant = cannot define inherent `impl` for a .help = consider moving this inherent impl into the crate defining the type if possible .span_help = alternatively add `#[rustc_allow_incoherent_impl]` to the relevant impl items +hir_analysis_invalid_generic_receiver_ty = invalid generic `self` parameter type: `{$receiver_ty}` + .note = type of `self` must not be a method generic parameter type + +hir_analysis_invalid_generic_receiver_ty_help = + use a concrete type such as `self`, `&self`, `&mut self`, `self: Box<Self>`, `self: Rc<Self>`, `self: Arc<Self>`, or `self: Pin<P>` (where P is one of the previous types except `Self`) + hir_analysis_invalid_receiver_ty = invalid `self` parameter type: `{$receiver_ty}` .note = type of `self` must be `Self` or a type that dereferences to it diff --git a/compiler/rustc_hir_analysis/src/check/check.rs b/compiler/rustc_hir_analysis/src/check/check.rs index 97f3f1c8ef2..f830108a02f 100644 --- a/compiler/rustc_hir_analysis/src/check/check.rs +++ b/compiler/rustc_hir_analysis/src/check/check.rs @@ -1,6 +1,7 @@ use std::cell::LazyCell; use std::ops::ControlFlow; +use rustc_abi::FieldIdx; use rustc_data_structures::unord::{UnordMap, UnordSet}; use rustc_errors::MultiSpan; use rustc_errors::codes::*; @@ -23,13 +24,13 @@ use rustc_middle::ty::{ TypeVisitableExt, }; use rustc_session::lint::builtin::UNINHABITED_STATIC; -use rustc_target::abi::FieldIdx; use rustc_trait_selection::error_reporting::InferCtxtErrorExt; use rustc_trait_selection::error_reporting::traits::on_unimplemented::OnUnimplementedDirective; use rustc_trait_selection::traits; use rustc_trait_selection::traits::outlives_bounds::InferCtxtExt as _; use rustc_type_ir::fold::TypeFoldable; use tracing::{debug, instrument}; +use ty::TypingMode; use {rustc_attr as attr, rustc_hir as hir}; use super::compare_impl_item::{check_type_bounds, compare_impl_method, compare_impl_ty}; @@ -172,7 +173,7 @@ fn check_static_inhabited(tcx: TyCtxt<'_>, def_id: LocalDefId) { return; } }; - if layout.abi.is_uninhabited() { + if layout.is_uninhabited() { tcx.node_span_lint( UNINHABITED_STATIC, tcx.local_def_id_to_hir_id(def_id), @@ -276,7 +277,8 @@ fn check_opaque_meets_bounds<'tcx>( }; let param_env = tcx.param_env(defining_use_anchor); - let infcx = tcx.infer_ctxt().with_opaque_type_inference(defining_use_anchor).build(); + // FIXME(#132279): This should eventually use the already defined hidden types. + let infcx = tcx.infer_ctxt().build(TypingMode::analysis_in_body(tcx, defining_use_anchor)); let ocx = ObligationCtxt::new_with_diagnostics(&infcx); let args = match *origin { @@ -1675,8 +1677,8 @@ pub(super) fn check_coroutine_obligations( // typeck writeback gives us predicates with their regions erased. // As borrowck already has checked lifetimes, we do not need to do it again. .ignoring_regions() - .with_opaque_type_inference(def_id) - .build(); + // FIXME(#132279): This should eventually use the already defined hidden types. + .build(TypingMode::analysis_in_body(tcx, def_id)); let ocx = ObligationCtxt::new_with_diagnostics(&infcx); for (predicate, cause) in &typeck_results.coroutine_stalled_predicates { diff --git a/compiler/rustc_hir_analysis/src/check/compare_impl_item.rs b/compiler/rustc_hir_analysis/src/check/compare_impl_item.rs index 02cf1a502f1..db2c44fd29d 100644 --- a/compiler/rustc_hir_analysis/src/check/compare_impl_item.rs +++ b/compiler/rustc_hir_analysis/src/check/compare_impl_item.rs @@ -17,7 +17,7 @@ use rustc_middle::ty::fold::BottomUpFolder; use rustc_middle::ty::util::ExplicitSelf; use rustc_middle::ty::{ self, GenericArgs, GenericParamDefKind, Ty, TyCtxt, TypeFoldable, TypeFolder, - TypeSuperFoldable, TypeVisitableExt, Upcast, + TypeSuperFoldable, TypeVisitableExt, TypingMode, Upcast, }; use rustc_middle::{bug, span_bug}; use rustc_span::Span; @@ -228,7 +228,7 @@ fn compare_method_predicate_entailment<'tcx>( let param_env = traits::normalize_param_env_or_error(tcx, param_env, normalize_cause); debug!(caller_bounds=?param_env.caller_bounds()); - let infcx = &tcx.infer_ctxt().build(); + let infcx = &tcx.infer_ctxt().build(TypingMode::non_body_analysis()); let ocx = ObligationCtxt::new_with_diagnostics(infcx); // Create obligations for each predicate declared by the impl @@ -516,7 +516,7 @@ pub(super) fn collect_return_position_impl_trait_in_trait_tys<'tcx>( ObligationCause::misc(tcx.def_span(impl_m_def_id), impl_m_def_id), ); - let infcx = &tcx.infer_ctxt().build(); + let infcx = &tcx.infer_ctxt().build(TypingMode::non_body_analysis()); let ocx = ObligationCtxt::new_with_diagnostics(infcx); // Normalize the impl signature with fresh variables for lifetime inference. @@ -611,7 +611,7 @@ pub(super) fn collect_return_position_impl_trait_in_trait_tys<'tcx>( Err(terr) => { let mut diag = struct_span_code_err!( tcx.dcx(), - cause.span(), + cause.span, E0053, "method `{}` has an incompatible return type for trait", trait_m.name @@ -1169,7 +1169,7 @@ fn extract_spans_for_error_reporting<'tcx>( TypeError::ArgumentMutability(i) | TypeError::ArgumentSorts(ExpectedFound { .. }, i) => { (impl_args.nth(i).unwrap(), trait_args.and_then(|mut args| args.nth(i))) } - _ => (cause.span(), tcx.hir().span_if_local(trait_m.def_id)), + _ => (cause.span, tcx.hir().span_if_local(trait_m.def_id)), } } @@ -1196,7 +1196,7 @@ fn compare_self_type<'tcx>( let self_arg_ty = tcx.fn_sig(method.def_id).instantiate_identity().input(0); let param_env = ty::ParamEnv::reveal_all(); - let infcx = tcx.infer_ctxt().build(); + let infcx = tcx.infer_ctxt().build(TypingMode::non_body_analysis()); let self_arg_ty = tcx.liberate_late_bound_regions(method.def_id, self_arg_ty); let can_eq_self = |ty| infcx.can_eq(param_env, untransformed_self_ty, ty); match ExplicitSelf::determine(self_arg_ty, can_eq_self) { @@ -1801,7 +1801,7 @@ fn compare_const_predicate_entailment<'tcx>( ObligationCause::misc(impl_ct_span, impl_ct_def_id), ); - let infcx = tcx.infer_ctxt().build(); + let infcx = tcx.infer_ctxt().build(TypingMode::non_body_analysis()); let ocx = ObligationCtxt::new_with_diagnostics(&infcx); let impl_ct_own_bounds = impl_ct_predicates.instantiate_own_identity(); @@ -1951,7 +1951,7 @@ fn compare_type_predicate_entailment<'tcx>( let param_env = traits::normalize_param_env_or_error(tcx, param_env, normalize_cause); debug!(caller_bounds=?param_env.caller_bounds()); - let infcx = tcx.infer_ctxt().build(); + let infcx = tcx.infer_ctxt().build(TypingMode::non_body_analysis()); let ocx = ObligationCtxt::new_with_diagnostics(&infcx); for (predicate, span) in impl_ty_own_bounds { @@ -2036,7 +2036,7 @@ pub(super) fn check_type_bounds<'tcx>( let impl_ty_args = GenericArgs::identity_for_item(tcx, impl_ty.def_id); let rebased_args = impl_ty_args.rebase_onto(tcx, container_id, impl_trait_ref.args); - let infcx = tcx.infer_ctxt().build(); + let infcx = tcx.infer_ctxt().build(TypingMode::non_body_analysis()); let ocx = ObligationCtxt::new_with_diagnostics(&infcx); // A synthetic impl Trait for RPITIT desugaring or assoc type for effects desugaring has no HIR, diff --git a/compiler/rustc_hir_analysis/src/check/compare_impl_item/refine.rs b/compiler/rustc_hir_analysis/src/check/compare_impl_item/refine.rs index 2d6b9813271..646c104f1f5 100644 --- a/compiler/rustc_hir_analysis/src/check/compare_impl_item/refine.rs +++ b/compiler/rustc_hir_analysis/src/check/compare_impl_item/refine.rs @@ -8,7 +8,7 @@ use rustc_middle::span_bug; use rustc_middle::traits::{ObligationCause, Reveal}; use rustc_middle::ty::{ self, Ty, TyCtxt, TypeFoldable, TypeFolder, TypeSuperVisitable, TypeVisitable, - TypeVisitableExt, TypeVisitor, + TypeVisitableExt, TypeVisitor, TypingMode, }; use rustc_span::Span; use rustc_trait_selection::regions::InferCtxtRegionExt; @@ -132,7 +132,7 @@ pub(super) fn check_refining_return_position_impl_trait_in_trait<'tcx>( let param_env = ty::ParamEnv::new(tcx.mk_clauses_from_iter(hybrid_preds), Reveal::UserFacing); let param_env = normalize_param_env_or_error(tcx, param_env, ObligationCause::dummy()); - let ref infcx = tcx.infer_ctxt().build(); + let ref infcx = tcx.infer_ctxt().build(TypingMode::non_body_analysis()); let ocx = ObligationCtxt::new(infcx); // Normalize the bounds. This has two purposes: diff --git a/compiler/rustc_hir_analysis/src/check/dropck.rs b/compiler/rustc_hir_analysis/src/check/dropck.rs index 97a29b32c01..1c9bbe627fb 100644 --- a/compiler/rustc_hir_analysis/src/check/dropck.rs +++ b/compiler/rustc_hir_analysis/src/check/dropck.rs @@ -9,7 +9,7 @@ use rustc_infer::infer::outlives::env::OutlivesEnvironment; use rustc_infer::infer::{RegionResolutionError, TyCtxtInferExt}; use rustc_infer::traits::{ObligationCause, ObligationCauseCode}; use rustc_middle::ty::util::CheckRegions; -use rustc_middle::ty::{self, GenericArgsRef, Ty, TyCtxt}; +use rustc_middle::ty::{self, GenericArgsRef, Ty, TyCtxt, TypingMode}; use rustc_trait_selection::regions::InferCtxtRegionExt; use rustc_trait_selection::traits::{self, ObligationCtxt}; @@ -124,7 +124,7 @@ fn ensure_drop_predicates_are_implied_by_item_defn<'tcx>( adt_def_id: LocalDefId, adt_to_impl_args: GenericArgsRef<'tcx>, ) -> Result<(), ErrorGuaranteed> { - let infcx = tcx.infer_ctxt().build(); + let infcx = tcx.infer_ctxt().build(TypingMode::non_body_analysis()); let ocx = ObligationCtxt::new_with_diagnostics(&infcx); let impl_span = tcx.def_span(drop_impl_def_id.to_def_id()); diff --git a/compiler/rustc_hir_analysis/src/check/entry.rs b/compiler/rustc_hir_analysis/src/check/entry.rs index 7da2cd93d4e..0beb1f98d56 100644 --- a/compiler/rustc_hir_analysis/src/check/entry.rs +++ b/compiler/rustc_hir_analysis/src/check/entry.rs @@ -4,7 +4,7 @@ use rustc_hir as hir; use rustc_hir::Node; use rustc_infer::infer::TyCtxtInferExt; use rustc_middle::span_bug; -use rustc_middle::ty::{self, Ty, TyCtxt}; +use rustc_middle::ty::{self, Ty, TyCtxt, TypingMode}; use rustc_session::config::EntryFnType; use rustc_span::Span; use rustc_span::def_id::{CRATE_DEF_ID, DefId, LocalDefId}; @@ -128,7 +128,7 @@ fn check_main_fn_ty(tcx: TyCtxt<'_>, main_def_id: DefId) { tcx.dcx().emit_err(errors::MainFunctionReturnTypeGeneric { span: return_ty_span }); return; }; - let infcx = tcx.infer_ctxt().build(); + let infcx = tcx.infer_ctxt().build(TypingMode::non_body_analysis()); let cause = traits::ObligationCause::new( return_ty_span, main_diagnostics_def_id, diff --git a/compiler/rustc_hir_analysis/src/check/intrinsicck.rs b/compiler/rustc_hir_analysis/src/check/intrinsicck.rs index bbff00cd3b3..e95669c9d40 100644 --- a/compiler/rustc_hir_analysis/src/check/intrinsicck.rs +++ b/compiler/rustc_hir_analysis/src/check/intrinsicck.rs @@ -1,5 +1,6 @@ use std::assert_matches::debug_assert_matches; +use rustc_abi::FieldIdx; use rustc_ast::InlineAsmTemplatePiece; use rustc_data_structures::fx::FxIndexSet; use rustc_hir::{self as hir, LangItem}; @@ -8,7 +9,6 @@ use rustc_middle::ty::{self, FloatTy, IntTy, Ty, TyCtxt, TypeVisitableExt, UintT use rustc_session::lint; use rustc_span::Symbol; use rustc_span::def_id::LocalDefId; -use rustc_target::abi::FieldIdx; use rustc_target::asm::{ InlineAsmReg, InlineAsmRegClass, InlineAsmRegOrRegClass, InlineAsmType, ModifierInfo, }; diff --git a/compiler/rustc_hir_analysis/src/check/mod.rs b/compiler/rustc_hir_analysis/src/check/mod.rs index f2f9c69e49f..e9eea36a0e6 100644 --- a/compiler/rustc_hir_analysis/src/check/mod.rs +++ b/compiler/rustc_hir_analysis/src/check/mod.rs @@ -74,6 +74,7 @@ pub mod wfcheck; use std::num::NonZero; pub use check::{check_abi, check_abi_fn_ptr}; +use rustc_abi::VariantIdx; use rustc_data_structures::fx::{FxHashSet, FxIndexMap}; use rustc_errors::{Diag, ErrorGuaranteed, pluralize, struct_span_code_err}; use rustc_hir::def_id::{DefId, LocalDefId}; @@ -84,13 +85,12 @@ use rustc_infer::infer::{self, TyCtxtInferExt as _}; use rustc_infer::traits::ObligationCause; use rustc_middle::query::Providers; use rustc_middle::ty::error::{ExpectedFound, TypeError}; -use rustc_middle::ty::{self, GenericArgs, GenericArgsRef, Ty, TyCtxt}; +use rustc_middle::ty::{self, GenericArgs, GenericArgsRef, Ty, TyCtxt, TypingMode}; use rustc_middle::{bug, span_bug}; use rustc_session::parse::feature_err; use rustc_span::def_id::CRATE_DEF_ID; use rustc_span::symbol::{Ident, kw, sym}; use rustc_span::{BytePos, DUMMY_SP, Span, Symbol}; -use rustc_target::abi::VariantIdx; use rustc_target::spec::abi::Abi; use rustc_trait_selection::error_reporting::InferCtxtErrorExt; use rustc_trait_selection::error_reporting::infer::ObligationCauseExt as _; @@ -530,7 +530,7 @@ fn suggestion_signature<'tcx>( let ty = tcx.type_of(assoc.def_id).instantiate_identity(); let val = tcx .infer_ctxt() - .build() + .build(TypingMode::non_body_analysis()) .err_ctxt() .ty_kind_suggestion(tcx.param_env(assoc.def_id), ty) .unwrap_or_else(|| "value".to_string()); @@ -612,7 +612,7 @@ pub fn check_function_signature<'tcx>( match err { TypeError::ArgumentMutability(i) | TypeError::ArgumentSorts(ExpectedFound { .. }, i) => args.nth(i).unwrap(), - _ => cause.span(), + _ => cause.span, } } @@ -620,7 +620,7 @@ pub fn check_function_signature<'tcx>( let param_env = ty::ParamEnv::empty(); - let infcx = &tcx.infer_ctxt().build(); + let infcx = &tcx.infer_ctxt().build(TypingMode::non_body_analysis()); let ocx = ObligationCtxt::new_with_diagnostics(infcx); let actual_sig = tcx.fn_sig(fn_id).instantiate_identity(); diff --git a/compiler/rustc_hir_analysis/src/check/region.rs b/compiler/rustc_hir_analysis/src/check/region.rs index bfa088fdefc..679f6ccb816 100644 --- a/compiler/rustc_hir_analysis/src/check/region.rs +++ b/compiler/rustc_hir_analysis/src/check/region.rs @@ -464,8 +464,7 @@ fn resolve_expr<'tcx>(visitor: &mut RegionResolutionVisitor<'tcx>, expr: &'tcx h hir::ExprKind::If(cond, then, Some(otherwise)) => { let expr_cx = visitor.cx; - let data = if expr.span.at_least_rust_2024() && visitor.tcx.features().if_let_rescope() - { + let data = if expr.span.at_least_rust_2024() { ScopeData::IfThenRescope } else { ScopeData::IfThen @@ -480,8 +479,7 @@ fn resolve_expr<'tcx>(visitor: &mut RegionResolutionVisitor<'tcx>, expr: &'tcx h hir::ExprKind::If(cond, then, None) => { let expr_cx = visitor.cx; - let data = if expr.span.at_least_rust_2024() && visitor.tcx.features().if_let_rescope() - { + let data = if expr.span.at_least_rust_2024() { ScopeData::IfThenRescope } else { ScopeData::IfThen diff --git a/compiler/rustc_hir_analysis/src/check/wfcheck.rs b/compiler/rustc_hir_analysis/src/check/wfcheck.rs index 499e42d31c9..b20fa49eadb 100644 --- a/compiler/rustc_hir_analysis/src/check/wfcheck.rs +++ b/compiler/rustc_hir_analysis/src/check/wfcheck.rs @@ -17,7 +17,7 @@ use rustc_middle::ty::print::with_no_trimmed_paths; use rustc_middle::ty::trait_def::TraitSpecializationKind; use rustc_middle::ty::{ self, AdtKind, GenericArgKind, GenericArgs, GenericParamDefKind, Ty, TyCtxt, TypeFoldable, - TypeSuperVisitable, TypeVisitable, TypeVisitableExt, TypeVisitor, Upcast, + TypeSuperVisitable, TypeVisitable, TypeVisitableExt, TypeVisitor, TypingMode, Upcast, }; use rustc_middle::{bug, span_bug}; use rustc_session::parse::feature_err; @@ -106,7 +106,7 @@ where F: for<'a> FnOnce(&WfCheckingCtxt<'a, 'tcx>) -> Result<(), ErrorGuaranteed>, { let param_env = tcx.param_env(body_def_id); - let infcx = &tcx.infer_ctxt().build(); + let infcx = &tcx.infer_ctxt().build(TypingMode::non_body_analysis()); let ocx = ObligationCtxt::new_with_diagnostics(infcx); let mut wfcx = WfCheckingCtxt { ocx, span, body_def_id, param_env }; @@ -765,7 +765,7 @@ fn test_region_obligations<'tcx>( // Unfortunately, we have to use a new `InferCtxt` each call, because // region constraints get added and solved there and we need to test each // call individually. - let infcx = tcx.infer_ctxt().build(); + let infcx = tcx.infer_ctxt().build(TypingMode::non_body_analysis()); add_constraints(&infcx); @@ -904,7 +904,6 @@ fn check_impl_item<'tcx>( hir::ImplItemKind::Type(ty) if ty.span != DUMMY_SP => (None, ty.span), _ => (None, impl_item.span), }; - check_associated_item(tcx, impl_item.owner_id.def_id, span, method_sig) } @@ -1725,8 +1724,11 @@ fn check_method_receiver<'tcx>( } else { None }; + let generics = tcx.generics_of(method.def_id); - if !receiver_is_valid(wfcx, span, receiver_ty, self_ty, arbitrary_self_types_level) { + let receiver_validity = + receiver_is_valid(wfcx, span, receiver_ty, self_ty, arbitrary_self_types_level, generics); + if let Err(receiver_validity_err) = receiver_validity { return Err(match arbitrary_self_types_level { // Wherever possible, emit a message advising folks that the features // `arbitrary_self_types` or `arbitrary_self_types_pointers` might @@ -1737,7 +1739,9 @@ fn check_method_receiver<'tcx>( receiver_ty, self_ty, Some(ArbitrarySelfTypesLevel::Basic), - ) => + generics, + ) + .is_ok() => { // Report error; would have worked with `arbitrary_self_types`. feature_err( @@ -1759,7 +1763,9 @@ fn check_method_receiver<'tcx>( receiver_ty, self_ty, Some(ArbitrarySelfTypesLevel::WithPointers), - ) => + generics, + ) + .is_ok() => { // Report error; would have worked with `arbitrary_self_types_pointers`. feature_err( @@ -1777,13 +1783,45 @@ fn check_method_receiver<'tcx>( _ => // Report error; would not have worked with `arbitrary_self_types[_pointers]`. { - tcx.dcx().emit_err(errors::InvalidReceiverTy { span, receiver_ty }) + match receiver_validity_err { + ReceiverValidityError::DoesNotDeref => { + tcx.dcx().emit_err(errors::InvalidReceiverTy { span, receiver_ty }) + } + ReceiverValidityError::MethodGenericParamUsed => { + tcx.dcx().emit_err(errors::InvalidGenericReceiverTy { span, receiver_ty }) + } + } } }); } Ok(()) } +/// Error cases which may be returned from `receiver_is_valid`. These error +/// cases are generated in this function as they may be unearthed as we explore +/// the `autoderef` chain, but they're converted to diagnostics in the caller. +enum ReceiverValidityError { + /// The self type does not get to the receiver type by following the + /// autoderef chain. + DoesNotDeref, + /// A type was found which is a method type parameter, and that's not allowed. + MethodGenericParamUsed, +} + +/// Confirms that a type is not a type parameter referring to one of the +/// method's type params. +fn confirm_type_is_not_a_method_generic_param( + ty: Ty<'_>, + method_generics: &ty::Generics, +) -> Result<(), ReceiverValidityError> { + if let ty::Param(param) = ty.kind() { + if (param.index as usize) >= method_generics.parent_count { + return Err(ReceiverValidityError::MethodGenericParamUsed); + } + } + Ok(()) +} + /// Returns whether `receiver_ty` would be considered a valid receiver type for `self_ty`. If /// `arbitrary_self_types` is enabled, `receiver_ty` must transitively deref to `self_ty`, possibly /// through a `*const/mut T` raw pointer if `arbitrary_self_types_pointers` is also enabled. @@ -1799,7 +1837,8 @@ fn receiver_is_valid<'tcx>( receiver_ty: Ty<'tcx>, self_ty: Ty<'tcx>, arbitrary_self_types_enabled: Option<ArbitrarySelfTypesLevel>, -) -> bool { + method_generics: &ty::Generics, +) -> Result<(), ReceiverValidityError> { let infcx = wfcx.infcx; let tcx = wfcx.tcx(); let cause = @@ -1811,9 +1850,11 @@ fn receiver_is_valid<'tcx>( ocx.eq(&cause, wfcx.param_env, self_ty, receiver_ty)?; if ocx.select_all_or_error().is_empty() { Ok(()) } else { Err(NoSolution) } }) { - return true; + return Ok(()); } + confirm_type_is_not_a_method_generic_param(receiver_ty, method_generics)?; + let mut autoderef = Autoderef::new(infcx, wfcx.param_env, wfcx.body_def_id, span, receiver_ty); // The `arbitrary_self_types_pointers` feature allows raw pointer receivers like `self: *const Self`. @@ -1830,6 +1871,8 @@ fn receiver_is_valid<'tcx>( potential_self_ty, self_ty ); + confirm_type_is_not_a_method_generic_param(potential_self_ty, method_generics)?; + // Check if the self type unifies. If it does, then commit the result // since it may have region side-effects. if let Ok(()) = wfcx.infcx.commit_if_ok(|_| { @@ -1838,7 +1881,7 @@ fn receiver_is_valid<'tcx>( if ocx.select_all_or_error().is_empty() { Ok(()) } else { Err(NoSolution) } }) { wfcx.register_obligations(autoderef.into_obligations()); - return true; + return Ok(()); } // Without `feature(arbitrary_self_types)`, we require that each step in the @@ -1865,7 +1908,7 @@ fn receiver_is_valid<'tcx>( } debug!("receiver_is_valid: type `{:?}` does not deref to `{:?}`", receiver_ty, self_ty); - false + Err(ReceiverValidityError::DoesNotDeref) } fn receiver_is_implemented<'tcx>( diff --git a/compiler/rustc_hir_analysis/src/coherence/builtin.rs b/compiler/rustc_hir_analysis/src/coherence/builtin.rs index b4f6b5a9dd2..5ff52376837 100644 --- a/compiler/rustc_hir_analysis/src/coherence/builtin.rs +++ b/compiler/rustc_hir_analysis/src/coherence/builtin.rs @@ -15,7 +15,9 @@ use rustc_infer::infer::{self, RegionResolutionError, TyCtxtInferExt}; use rustc_infer::traits::Obligation; use rustc_middle::ty::adjustment::CoerceUnsizedInfo; use rustc_middle::ty::print::PrintTraitRefExt as _; -use rustc_middle::ty::{self, Ty, TyCtxt, TypeVisitableExt, suggest_constraining_type_params}; +use rustc_middle::ty::{ + self, Ty, TyCtxt, TypeVisitableExt, TypingMode, suggest_constraining_type_params, +}; use rustc_span::{DUMMY_SP, Span}; use rustc_trait_selection::error_reporting::InferCtxtErrorExt; use rustc_trait_selection::traits::misc::{ @@ -213,7 +215,7 @@ fn visit_implementation_of_dispatch_from_dyn(checker: &Checker<'_>) -> Result<() let param_env = tcx.param_env(impl_did); - let infcx = tcx.infer_ctxt().build(); + let infcx = tcx.infer_ctxt().build(TypingMode::non_body_analysis()); let cause = ObligationCause::misc(span, impl_did); // Later parts of the compiler rely on all DispatchFromDyn types to be ABI-compatible with raw @@ -354,7 +356,7 @@ pub(crate) fn coerce_unsized_info<'tcx>( debug!("visit_implementation_of_coerce_unsized: {:?} -> {:?} (free)", source, target); - let infcx = tcx.infer_ctxt().build(); + let infcx = tcx.infer_ctxt().build(TypingMode::non_body_analysis()); let cause = ObligationCause::misc(span, impl_did); let check_mutbl = |mt_a: ty::TypeAndMut<'tcx>, mt_b: ty::TypeAndMut<'tcx>, diff --git a/compiler/rustc_hir_analysis/src/coherence/orphan.rs b/compiler/rustc_hir_analysis/src/coherence/orphan.rs index 04770469132..8a1a887766c 100644 --- a/compiler/rustc_hir_analysis/src/coherence/orphan.rs +++ b/compiler/rustc_hir_analysis/src/coherence/orphan.rs @@ -7,7 +7,7 @@ use rustc_infer::infer::{InferCtxt, TyCtxtInferExt}; use rustc_lint_defs::builtin::UNCOVERED_PARAM_IN_PROJECTION; use rustc_middle::ty::{ self, Ty, TyCtxt, TypeFoldable, TypeFolder, TypeSuperFoldable, TypeSuperVisitable, - TypeVisitable, TypeVisitableExt, TypeVisitor, + TypeVisitable, TypeVisitableExt, TypeVisitor, TypingMode, }; use rustc_middle::{bug, span_bug}; use rustc_span::def_id::{DefId, LocalDefId}; @@ -302,7 +302,7 @@ fn orphan_check<'tcx>( } // (1) Instantiate all generic params with fresh inference vars. - let infcx = tcx.infer_ctxt().intercrate(true).build(); + let infcx = tcx.infer_ctxt().build(TypingMode::Coherence); let cause = traits::ObligationCause::dummy(); let args = infcx.fresh_args_for_item(cause.span, impl_def_id.to_def_id()); let trait_ref = trait_ref.instantiate(tcx, args); diff --git a/compiler/rustc_hir_analysis/src/collect.rs b/compiler/rustc_hir_analysis/src/collect.rs index 3add801cf56..c41117d213f 100644 --- a/compiler/rustc_hir_analysis/src/collect.rs +++ b/compiler/rustc_hir_analysis/src/collect.rs @@ -34,7 +34,7 @@ use rustc_infer::traits::ObligationCause; use rustc_middle::hir::nested_filter; use rustc_middle::query::Providers; use rustc_middle::ty::util::{Discr, IntTypeExt}; -use rustc_middle::ty::{self, AdtKind, Const, IsSuggestable, Ty, TyCtxt}; +use rustc_middle::ty::{self, AdtKind, Const, IsSuggestable, Ty, TyCtxt, TypingMode}; use rustc_middle::{bug, span_bug}; use rustc_span::symbol::{Ident, Symbol, kw, sym}; use rustc_span::{DUMMY_SP, Span}; @@ -1302,7 +1302,7 @@ fn trait_def(tcx: TyCtxt<'_>, def_id: LocalDefId) -> ty::TraitDef { } } -#[instrument(level = "debug", skip(tcx))] +#[instrument(level = "debug", skip(tcx), ret)] fn fn_sig(tcx: TyCtxt<'_>, def_id: LocalDefId) -> ty::EarlyBinder<'_, ty::PolyFnSig<'_>> { use rustc_hir::Node::*; use rustc_hir::*; @@ -1438,9 +1438,11 @@ fn infer_return_ty_for_fn_sig<'tcx>( Applicability::MachineApplicable, ); recovered_ret_ty = Some(suggestable_ret_ty); - } else if let Some(sugg) = - suggest_impl_trait(&tcx.infer_ctxt().build(), tcx.param_env(def_id), ret_ty) - { + } else if let Some(sugg) = suggest_impl_trait( + &tcx.infer_ctxt().build(TypingMode::non_body_analysis()), + tcx.param_env(def_id), + ret_ty, + ) { diag.span_suggestion( ty.span, "replace with an appropriate return type", diff --git a/compiler/rustc_hir_analysis/src/collect/generics_of.rs b/compiler/rustc_hir_analysis/src/collect/generics_of.rs index 3eec0e12665..c31bff28fd3 100644 --- a/compiler/rustc_hir_analysis/src/collect/generics_of.rs +++ b/compiler/rustc_hir_analysis/src/collect/generics_of.rs @@ -426,6 +426,21 @@ pub(super) fn generics_of(tcx: TyCtxt<'_>, def_id: LocalDefId) -> ty::Generics { }); } + if let Node::OpaqueTy(&hir::OpaqueTy { .. }) = node { + assert!(own_params.is_empty()); + + let lifetimes = tcx.opaque_captured_lifetimes(def_id); + debug!(?lifetimes); + + own_params.extend(lifetimes.iter().map(|&(_, param)| ty::GenericParamDef { + name: tcx.item_name(param.to_def_id()), + index: next_index(), + def_id: param.to_def_id(), + pure_wrt_drop: false, + kind: ty::GenericParamDefKind::Lifetime, + })) + } + let param_def_id_to_index = own_params.iter().map(|param| (param.def_id, param.index)).collect(); diff --git a/compiler/rustc_hir_analysis/src/collect/item_bounds.rs b/compiler/rustc_hir_analysis/src/collect/item_bounds.rs index b2ad42be6c7..5c4cecc02f0 100644 --- a/compiler/rustc_hir_analysis/src/collect/item_bounds.rs +++ b/compiler/rustc_hir_analysis/src/collect/item_bounds.rs @@ -367,20 +367,8 @@ pub(super) fn explicit_item_bounds_with_filter( // a projection self type. Some(ty::ImplTraitInTraitData::Trait { opaque_def_id, .. }) => { let opaque_ty = tcx.hir_node_by_def_id(opaque_def_id.expect_local()).expect_opaque_ty(); - let item_ty = Ty::new_projection_from_args( - tcx, - def_id.to_def_id(), - ty::GenericArgs::identity_for_item(tcx, def_id), - ); - let bounds = opaque_type_bounds( - tcx, - opaque_def_id.expect_local(), - opaque_ty.bounds, - item_ty, - opaque_ty.span, - filter, - ); - assert_only_contains_predicates_from(filter, bounds, item_ty); + let bounds = + associated_type_bounds(tcx, def_id, opaque_ty.bounds, opaque_ty.span, filter); return ty::EarlyBinder::bind(bounds); } Some(ty::ImplTraitInTraitData::Impl { .. }) => span_bug!( diff --git a/compiler/rustc_hir_analysis/src/collect/predicates_of.rs b/compiler/rustc_hir_analysis/src/collect/predicates_of.rs index 644ff0c667c..0b018053855 100644 --- a/compiler/rustc_hir_analysis/src/collect/predicates_of.rs +++ b/compiler/rustc_hir_analysis/src/collect/predicates_of.rs @@ -329,13 +329,6 @@ fn gather_explicit_predicates_of(tcx: TyCtxt<'_>, def_id: LocalDefId) -> ty::Gen // We create bi-directional Outlives predicates between the original // and the duplicated parameter, to ensure that they do not get out of sync. if let Node::OpaqueTy(..) = node { - let opaque_ty_node = tcx.parent_hir_node(hir_id); - let Node::Ty(&hir::Ty { kind: TyKind::OpaqueDef(_, lifetimes), .. }) = opaque_ty_node - else { - bug!("unexpected {opaque_ty_node:?}") - }; - debug!(?lifetimes); - compute_bidirectional_outlives_predicates(tcx, &generics.own_params, &mut predicates); debug!(?predicates); } diff --git a/compiler/rustc_hir_analysis/src/collect/resolve_bound_vars.rs b/compiler/rustc_hir_analysis/src/collect/resolve_bound_vars.rs index 95e07244a6b..9483439ae4e 100644 --- a/compiler/rustc_hir_analysis/src/collect/resolve_bound_vars.rs +++ b/compiler/rustc_hir_analysis/src/collect/resolve_bound_vars.rs @@ -6,12 +6,14 @@ //! the types in HIR to identify late-bound lifetimes and assign their Debruijn indices. This file //! is also responsible for assigning their semantics to implicit lifetimes in trait objects. -use core::ops::ControlFlow; +use std::cell::RefCell; use std::fmt; +use std::ops::ControlFlow; use rustc_ast::visit::walk_list; use rustc_data_structures::fx::{FxHashSet, FxIndexMap, FxIndexSet}; use rustc_data_structures::sorted_map::SortedMap; +use rustc_errors::ErrorGuaranteed; use rustc_hir as hir; use rustc_hir::def::{DefKind, Res}; use rustc_hir::intravisit::{self, Visitor}; @@ -25,7 +27,7 @@ use rustc_middle::query::Providers; use rustc_middle::ty::{self, TyCtxt, TypeSuperVisitable, TypeVisitor}; use rustc_middle::{bug, span_bug}; use rustc_span::Span; -use rustc_span::def_id::{DefId, LocalDefId}; +use rustc_span::def_id::{DefId, LocalDefId, LocalDefIdMap}; use rustc_span::symbol::{Ident, sym}; use tracing::{debug, debug_span, instrument}; @@ -33,18 +35,12 @@ use crate::errors; #[extension(trait RegionExt)] impl ResolvedArg { - fn early(param: &GenericParam<'_>) -> (LocalDefId, ResolvedArg) { - debug!("ResolvedArg::early: def_id={:?}", param.def_id); - (param.def_id, ResolvedArg::EarlyBound(param.def_id)) + fn early(param: &GenericParam<'_>) -> ResolvedArg { + ResolvedArg::EarlyBound(param.def_id) } - fn late(idx: u32, param: &GenericParam<'_>) -> (LocalDefId, ResolvedArg) { - let depth = ty::INNERMOST; - debug!( - "ResolvedArg::late: idx={:?}, param={:?} depth={:?} def_id={:?}", - idx, param, depth, param.def_id, - ); - (param.def_id, ResolvedArg::LateBound(depth, idx, param.def_id)) + fn late(idx: u32, param: &GenericParam<'_>) -> ResolvedArg { + ResolvedArg::LateBound(ty::INNERMOST, idx, param.def_id) } fn id(&self) -> Option<LocalDefId> { @@ -86,6 +82,9 @@ struct NamedVarMap { // - trait refs // - bound types (like `T` in `for<'a> T<'a>: Foo`) late_bound_vars: ItemLocalMap<Vec<ty::BoundVariableKind>>, + + // List captured variables for each opaque type. + opaque_captured_lifetimes: LocalDefIdMap<Vec<(ResolvedArg, LocalDefId)>>, } struct BoundVarContext<'a, 'tcx> { @@ -153,6 +152,23 @@ enum Scope<'a> { s: ScopeRef<'a>, }, + /// Remap lifetimes that appear in opaque types to fresh lifetime parameters. Given: + /// `fn foo<'a>() -> impl MyTrait<'a> { ... }` + /// + /// HIR tells us that `'a` refer to the lifetime bound on `foo`. + /// However, typeck and borrowck for opaques work based on using a new generic type. + /// `type MyAnonTy<'b> = impl MyTrait<'b>;` + /// + /// This scope collects the mapping `'a -> 'b`. + Opaque { + /// The opaque type we are traversing. + def_id: LocalDefId, + /// Mapping from each captured lifetime `'a` to the duplicate generic parameter `'b`. + captures: &'a RefCell<FxIndexMap<ResolvedArg, LocalDefId>>, + + s: ScopeRef<'a>, + }, + /// Disallows capturing late-bound vars from parent scopes. /// /// This is necessary for something like `for<T> [(); { /* references T */ }]:`, @@ -198,6 +214,12 @@ impl<'a> fmt::Debug for TruncatedScopeDebug<'a> { .field("where_bound_origin", where_bound_origin) .field("s", &"..") .finish(), + Scope::Opaque { captures, def_id, s: _ } => f + .debug_struct("Opaque") + .field("def_id", def_id) + .field("captures", &captures.borrow()) + .field("s", &"..") + .finish(), Scope::Body { id, s: _ } => { f.debug_struct("Body").field("id", id).field("s", &"..").finish() } @@ -232,6 +254,12 @@ pub(crate) fn provide(providers: &mut Providers) { is_late_bound_map, object_lifetime_default, late_bound_vars_map: |tcx, id| &tcx.resolve_bound_vars(id).late_bound_vars, + opaque_captured_lifetimes: |tcx, id| { + &tcx.resolve_bound_vars(tcx.local_def_id_to_hir_id(id).owner) + .opaque_captured_lifetimes + .get(&id) + .map_or(&[][..], |x| &x[..]) + }, ..*providers }; @@ -242,8 +270,11 @@ pub(crate) fn provide(providers: &mut Providers) { /// `named_variable_map`, `is_late_bound_map`, etc. #[instrument(level = "debug", skip(tcx))] fn resolve_bound_vars(tcx: TyCtxt<'_>, local_def_id: hir::OwnerId) -> ResolveBoundVars { - let mut named_variable_map = - NamedVarMap { defs: Default::default(), late_bound_vars: Default::default() }; + let mut named_variable_map = NamedVarMap { + defs: Default::default(), + late_bound_vars: Default::default(), + opaque_captured_lifetimes: Default::default(), + }; let mut visitor = BoundVarContext { tcx, map: &mut named_variable_map, @@ -270,36 +301,68 @@ fn resolve_bound_vars(tcx: TyCtxt<'_>, local_def_id: hir::OwnerId) -> ResolveBou let defs = named_variable_map.defs.into_sorted_stable_ord(); let late_bound_vars = named_variable_map.late_bound_vars.into_sorted_stable_ord(); + let opaque_captured_lifetimes = named_variable_map.opaque_captured_lifetimes; let rl = ResolveBoundVars { defs: SortedMap::from_presorted_elements(defs), late_bound_vars: SortedMap::from_presorted_elements(late_bound_vars), + opaque_captured_lifetimes, }; debug!(?rl.defs); debug!(?rl.late_bound_vars); + debug!(?rl.opaque_captured_lifetimes); rl } fn late_arg_as_bound_arg<'tcx>( tcx: TyCtxt<'tcx>, - arg: &ResolvedArg, param: &GenericParam<'tcx>, ) -> ty::BoundVariableKind { - match arg { - ResolvedArg::LateBound(_, _, def_id) => { - let def_id = def_id.to_def_id(); - let name = tcx.item_name(def_id); - match param.kind { - GenericParamKind::Lifetime { .. } => { - ty::BoundVariableKind::Region(ty::BrNamed(def_id, name)) - } - GenericParamKind::Type { .. } => { - ty::BoundVariableKind::Ty(ty::BoundTyKind::Param(def_id, name)) - } - GenericParamKind::Const { .. } => ty::BoundVariableKind::Const, - } + let def_id = param.def_id.to_def_id(); + let name = tcx.item_name(def_id); + match param.kind { + GenericParamKind::Lifetime { .. } => { + ty::BoundVariableKind::Region(ty::BrNamed(def_id, name)) + } + GenericParamKind::Type { .. } => { + ty::BoundVariableKind::Ty(ty::BoundTyKind::Param(def_id, name)) + } + GenericParamKind::Const { .. } => ty::BoundVariableKind::Const, + } +} + +/// Turn a [`ty::GenericParamDef`] into a bound arg. Generally, this should only +/// be used when turning early-bound vars into late-bound vars when lowering +/// return type notation. +fn generic_param_def_as_bound_arg(param: &ty::GenericParamDef) -> ty::BoundVariableKind { + match param.kind { + ty::GenericParamDefKind::Lifetime => { + ty::BoundVariableKind::Region(ty::BoundRegionKind::BrNamed(param.def_id, param.name)) + } + ty::GenericParamDefKind::Type { .. } => { + ty::BoundVariableKind::Ty(ty::BoundTyKind::Param(param.def_id, param.name)) + } + ty::GenericParamDefKind::Const { .. } => ty::BoundVariableKind::Const, + } +} + +/// Whether this opaque always captures lifetimes in scope. +/// Right now, this is all RPITIT and TAITs, and when `lifetime_capture_rules_2024` +/// is enabled. We don't check the span of the edition, since this is done +/// on a per-opaque basis to account for nested opaques. +fn opaque_captures_all_in_scope_lifetimes<'tcx>( + tcx: TyCtxt<'tcx>, + opaque: &'tcx hir::OpaqueTy<'tcx>, +) -> bool { + match opaque.origin { + // if the opaque has the `use<...>` syntax, the user is telling us that they only want + // to account for those lifetimes, so do not try to be clever. + _ if opaque.bounds.iter().any(|bound| matches!(bound, hir::GenericBound::Use(..))) => false, + hir::OpaqueTyOrigin::AsyncFn { .. } | hir::OpaqueTyOrigin::TyAlias { .. } => true, + _ if tcx.features().lifetime_capture_rules_2024() || opaque.span.at_least_rust_2024() => { + true } - _ => bug!("{:?} is not a late argument", arg), + hir::OpaqueTyOrigin::FnReturn { in_trait_or_impl, .. } => in_trait_or_impl.is_some(), } } @@ -314,7 +377,9 @@ impl<'a, 'tcx> BoundVarContext<'a, 'tcx> { break (vec![], BinderScopeType::Normal); } - Scope::ObjectLifetimeDefault { s, .. } | Scope::LateBoundary { s, .. } => { + Scope::Opaque { s, .. } + | Scope::ObjectLifetimeDefault { s, .. } + | Scope::LateBoundary { s, .. } => { scope = s; } @@ -360,10 +425,9 @@ impl<'a, 'tcx> BoundVarContext<'a, 'tcx> { let mut bound_vars: FxIndexMap<LocalDefId, ResolvedArg> = FxIndexMap::default(); let binders_iter = trait_ref.bound_generic_params.iter().enumerate().map(|(late_bound_idx, param)| { - let pair = ResolvedArg::late(initial_bound_vars + late_bound_idx as u32, param); - let r = late_arg_as_bound_arg(self.tcx, &pair.1, param); - bound_vars.insert(pair.0, pair.1); - r + let arg = ResolvedArg::late(initial_bound_vars + late_bound_idx as u32, param); + bound_vars.insert(param.def_id, arg); + late_arg_as_bound_arg(self.tcx, param) }); binders.extend(binders_iter); @@ -458,9 +522,10 @@ impl<'a, 'tcx> Visitor<'tcx> for BoundVarContext<'a, 'tcx> { .iter() .enumerate() .map(|(late_bound_idx, param)| { - let pair = ResolvedArg::late(late_bound_idx as u32, param); - let r = late_arg_as_bound_arg(self.tcx, &pair.1, param); - (pair, r) + ( + (param.def_id, ResolvedArg::late(late_bound_idx as u32, param)), + late_arg_as_bound_arg(self.tcx, param), + ) }) .unzip(); @@ -485,29 +550,85 @@ impl<'a, 'tcx> Visitor<'tcx> for BoundVarContext<'a, 'tcx> { } } + /// Resolve the lifetimes inside the opaque type, and save them into + /// `opaque_captured_lifetimes`. + /// + /// This method has special handling for opaques that capture all lifetimes, + /// like async desugaring. #[instrument(level = "debug", skip(self))] fn visit_opaque_ty(&mut self, opaque: &'tcx rustc_hir::OpaqueTy<'tcx>) { - // We want to start our early-bound indices at the end of the parent scope, - // not including any parent `impl Trait`s. - let mut bound_vars = FxIndexMap::default(); - debug!(?opaque.generics.params); - for param in opaque.generics.params { - let (def_id, reg) = ResolvedArg::early(param); - bound_vars.insert(def_id, reg); + let captures = RefCell::new(FxIndexMap::default()); + + let capture_all_in_scope_lifetimes = + opaque_captures_all_in_scope_lifetimes(self.tcx, opaque); + if capture_all_in_scope_lifetimes { + let lifetime_ident = |def_id: LocalDefId| { + let name = self.tcx.item_name(def_id.to_def_id()); + let span = self.tcx.def_span(def_id); + Ident::new(name, span) + }; + + // We list scopes outwards, this causes us to see lifetime parameters in reverse + // declaration order. In order to make it consistent with what `generics_of` might + // give, we will reverse the IndexMap after early captures. + let mut scope = self.scope; + let mut opaque_capture_scopes = vec![(opaque.def_id, &captures)]; + loop { + match *scope { + Scope::Binder { ref bound_vars, s, .. } => { + for (&original_lifetime, &def) in bound_vars.iter().rev() { + if let DefKind::LifetimeParam = self.tcx.def_kind(original_lifetime) { + let ident = lifetime_ident(original_lifetime); + self.remap_opaque_captures(&opaque_capture_scopes, def, ident); + } + } + scope = s; + } + + Scope::Root { mut opt_parent_item } => { + while let Some(parent_item) = opt_parent_item { + let parent_generics = self.tcx.generics_of(parent_item); + for param in parent_generics.own_params.iter().rev() { + if let ty::GenericParamDefKind::Lifetime = param.kind { + let def = ResolvedArg::EarlyBound(param.def_id.expect_local()); + let ident = lifetime_ident(param.def_id.expect_local()); + self.remap_opaque_captures(&opaque_capture_scopes, def, ident); + } + } + opt_parent_item = parent_generics.parent.and_then(DefId::as_local); + } + break; + } + + Scope::Opaque { captures, def_id, s } => { + opaque_capture_scopes.push((def_id, captures)); + scope = s; + } + + Scope::Body { .. } => { + bug!("{:?}", scope) + } + + Scope::ObjectLifetimeDefault { s, .. } + | Scope::Supertrait { s, .. } + | Scope::TraitRefBoundary { s, .. } + | Scope::LateBoundary { s, .. } => { + scope = s; + } + } + } + captures.borrow_mut().reverse(); } - let hir_id = self.tcx.local_def_id_to_hir_id(opaque.def_id); - let scope = Scope::Binder { - hir_id, - bound_vars, - s: self.scope, - scope_type: BinderScopeType::Normal, - where_bound_origin: None, - }; + let scope = Scope::Opaque { captures: &captures, def_id: opaque.def_id, s: self.scope }; self.with(scope, |this| { let scope = Scope::TraitRefBoundary { s: this.scope }; this.with(scope, |this| intravisit::walk_opaque_ty(this, opaque)) - }) + }); + + let captures = captures.into_inner().into_iter().collect(); + debug!(?captures); + self.map.opaque_captured_lifetimes.insert(opaque.def_id, captures); } #[instrument(level = "debug", skip(self))] @@ -618,9 +739,10 @@ impl<'a, 'tcx> Visitor<'tcx> for BoundVarContext<'a, 'tcx> { .iter() .enumerate() .map(|(late_bound_idx, param)| { - let pair = ResolvedArg::late(late_bound_idx as u32, param); - let r = late_arg_as_bound_arg(self.tcx, &pair.1, param); - (pair, r) + ( + (param.def_id, ResolvedArg::late(late_bound_idx as u32, param)), + late_arg_as_bound_arg(self.tcx, param), + ) }) .unzip(); @@ -681,67 +803,6 @@ impl<'a, 'tcx> Visitor<'tcx> for BoundVarContext<'a, 'tcx> { }; self.with(scope, |this| this.visit_ty(mt.ty)); } - hir::TyKind::OpaqueDef(opaque_ty, lifetimes) => { - self.visit_opaque_ty(opaque_ty); - - // Resolve the lifetimes in the bounds to the lifetime defs in the generics. - // `fn foo<'a>() -> impl MyTrait<'a> { ... }` desugars to - // `type MyAnonTy<'b> = impl MyTrait<'b>;` - // ^ ^ this gets resolved in the scope of - // the opaque_ty generics - - // Resolve the lifetimes that are applied to the opaque type. - // These are resolved in the current scope. - // `fn foo<'a>() -> impl MyTrait<'a> { ... }` desugars to - // `fn foo<'a>() -> MyAnonTy<'a> { ... }` - // ^ ^this gets resolved in the current scope - for lifetime in lifetimes { - let hir::GenericArg::Lifetime(lifetime) = lifetime else { continue }; - self.visit_lifetime(lifetime); - - // Check for predicates like `impl for<'a> Trait<impl OtherTrait<'a>>` - // and ban them. Type variables instantiated inside binders aren't - // well-supported at the moment, so this doesn't work. - // In the future, this should be fixed and this error should be removed. - let def = self.map.defs.get(&lifetime.hir_id.local_id).copied(); - let Some(ResolvedArg::LateBound(_, _, lifetime_def_id)) = def else { continue }; - let lifetime_hir_id = self.tcx.local_def_id_to_hir_id(lifetime_def_id); - - let bad_place = match self.tcx.hir_node(self.tcx.parent_hir_id(lifetime_hir_id)) - { - // Opaques do not declare their own lifetimes, so if a lifetime comes from an opaque - // it must be a reified late-bound lifetime from a trait goal. - hir::Node::OpaqueTy(_) => "higher-ranked lifetime from outer `impl Trait`", - // Other items are fine. - hir::Node::Item(_) | hir::Node::TraitItem(_) | hir::Node::ImplItem(_) => { - continue; - } - hir::Node::Ty(hir::Ty { kind: hir::TyKind::BareFn(_), .. }) => { - "higher-ranked lifetime from function pointer" - } - hir::Node::Ty(hir::Ty { kind: hir::TyKind::TraitObject(..), .. }) => { - "higher-ranked lifetime from `dyn` type" - } - _ => "higher-ranked lifetime", - }; - - let (span, label) = if lifetime.ident.span == self.tcx.def_span(lifetime_def_id) - { - (opaque_ty.span, Some(opaque_ty.span)) - } else { - (lifetime.ident.span, None) - }; - - // Ensure that the parent of the def is an item, not HRTB - self.tcx.dcx().emit_err(errors::OpaqueCapturesHigherRankedLifetime { - span, - label, - decl_span: self.tcx.def_span(lifetime_def_id), - bad_place, - }); - self.uninsert_lifetime_on_error(lifetime, def.unwrap()); - } - } _ => intravisit::walk_ty(self, ty), } } @@ -870,9 +931,10 @@ impl<'a, 'tcx> Visitor<'tcx> for BoundVarContext<'a, 'tcx> { .iter() .enumerate() .map(|(late_bound_idx, param)| { - let pair = ResolvedArg::late(late_bound_idx as u32, param); - let r = late_arg_as_bound_arg(self.tcx, &pair.1, param); - (pair, r) + ( + (param.def_id, ResolvedArg::late(late_bound_idx as u32, param)), + late_arg_as_bound_arg(self.tcx, param), + ) }) .unzip(); @@ -1052,19 +1114,21 @@ impl<'a, 'tcx> BoundVarContext<'a, 'tcx> { let bound_vars: FxIndexMap<LocalDefId, ResolvedArg> = generics .params .iter() - .map(|param| match param.kind { - GenericParamKind::Lifetime { .. } => { - if self.tcx.is_late_bound(param.hir_id) { - let late_bound_idx = named_late_bound_vars; - named_late_bound_vars += 1; - ResolvedArg::late(late_bound_idx, param) - } else { + .map(|param| { + (param.def_id, match param.kind { + GenericParamKind::Lifetime { .. } => { + if self.tcx.is_late_bound(param.hir_id) { + let late_bound_idx = named_late_bound_vars; + named_late_bound_vars += 1; + ResolvedArg::late(late_bound_idx, param) + } else { + ResolvedArg::early(param) + } + } + GenericParamKind::Type { .. } | GenericParamKind::Const { .. } => { ResolvedArg::early(param) } - } - GenericParamKind::Type { .. } | GenericParamKind::Const { .. } => { - ResolvedArg::early(param) - } + }) }) .collect(); @@ -1075,11 +1139,7 @@ impl<'a, 'tcx> BoundVarContext<'a, 'tcx> { matches!(param.kind, GenericParamKind::Lifetime { .. }) && self.tcx.is_late_bound(param.hir_id) }) - .enumerate() - .map(|(late_bound_idx, param)| { - let pair = ResolvedArg::late(late_bound_idx as u32, param); - late_arg_as_bound_arg(self.tcx, &pair.1, param) - }) + .map(|param| late_arg_as_bound_arg(self.tcx, param)) .collect(); self.record_late_bound_vars(hir_id, binders); let scope = Scope::Binder { @@ -1096,7 +1156,8 @@ impl<'a, 'tcx> BoundVarContext<'a, 'tcx> { where F: for<'b, 'c> FnOnce(&'b mut BoundVarContext<'c, 'tcx>), { - let bound_vars = generics.params.iter().map(ResolvedArg::early).collect(); + let bound_vars = + generics.params.iter().map(|param| (param.def_id, ResolvedArg::early(param))).collect(); self.record_late_bound_vars(hir_id, vec![]); let scope = Scope::Binder { hir_id, @@ -1125,6 +1186,7 @@ impl<'a, 'tcx> BoundVarContext<'a, 'tcx> { let mut scope = self.scope; let mut outermost_body = None; let mut crossed_late_boundary = None; + let mut opaque_capture_scopes = vec![]; let result = loop { match *scope { Scope::Body { id, s } => { @@ -1200,6 +1262,12 @@ impl<'a, 'tcx> BoundVarContext<'a, 'tcx> { scope = s; } + Scope::Opaque { captures, def_id, s } => { + opaque_capture_scopes.push((def_id, captures)); + late_depth = 0; + scope = s; + } + Scope::ObjectLifetimeDefault { s, .. } | Scope::Supertrait { s, .. } | Scope::TraitRefBoundary { s, .. } => { @@ -1214,6 +1282,8 @@ impl<'a, 'tcx> BoundVarContext<'a, 'tcx> { }; if let Some(mut def) = result { + def = self.remap_opaque_captures(&opaque_capture_scopes, def, lifetime_ref.ident); + if let ResolvedArg::EarlyBound(..) = def { // Do not free early-bound regions, only late-bound ones. } else if let ResolvedArg::LateBound(_, _, param_def_id) = def @@ -1287,6 +1357,7 @@ impl<'a, 'tcx> BoundVarContext<'a, 'tcx> { Scope::Root { .. } => break, Scope::Binder { s, .. } | Scope::Body { s, .. } + | Scope::Opaque { s, .. } | Scope::ObjectLifetimeDefault { s, .. } | Scope::Supertrait { s, .. } | Scope::TraitRefBoundary { s, .. } @@ -1302,6 +1373,79 @@ impl<'a, 'tcx> BoundVarContext<'a, 'tcx> { ); } + /// Check for predicates like `impl for<'a> Trait<impl OtherTrait<'a>>` + /// and ban them. Type variables instantiated inside binders aren't + /// well-supported at the moment, so this doesn't work. + /// In the future, this should be fixed and this error should be removed. + fn check_lifetime_is_capturable( + &self, + opaque_def_id: LocalDefId, + lifetime: ResolvedArg, + capture_span: Span, + ) -> Result<(), ErrorGuaranteed> { + let ResolvedArg::LateBound(_, _, lifetime_def_id) = lifetime else { return Ok(()) }; + let lifetime_hir_id = self.tcx.local_def_id_to_hir_id(lifetime_def_id); + let bad_place = match self.tcx.hir_node(self.tcx.parent_hir_id(lifetime_hir_id)) { + // Opaques do not declare their own lifetimes, so if a lifetime comes from an opaque + // it must be a reified late-bound lifetime from a trait goal. + hir::Node::OpaqueTy(_) => "higher-ranked lifetime from outer `impl Trait`", + // Other items are fine. + hir::Node::Item(_) | hir::Node::TraitItem(_) | hir::Node::ImplItem(_) => return Ok(()), + hir::Node::Ty(hir::Ty { kind: hir::TyKind::BareFn(_), .. }) => { + "higher-ranked lifetime from function pointer" + } + hir::Node::Ty(hir::Ty { kind: hir::TyKind::TraitObject(..), .. }) => { + "higher-ranked lifetime from `dyn` type" + } + _ => "higher-ranked lifetime", + }; + + let decl_span = self.tcx.def_span(lifetime_def_id); + let (span, label) = if capture_span != decl_span { + (capture_span, None) + } else { + let opaque_span = self.tcx.def_span(opaque_def_id); + (opaque_span, Some(opaque_span)) + }; + + // Ensure that the parent of the def is an item, not HRTB + let guar = self.tcx.dcx().emit_err(errors::OpaqueCapturesHigherRankedLifetime { + span, + label, + decl_span, + bad_place, + }); + Err(guar) + } + + #[instrument(level = "trace", skip(self, opaque_capture_scopes), ret)] + fn remap_opaque_captures( + &self, + opaque_capture_scopes: &Vec<(LocalDefId, &RefCell<FxIndexMap<ResolvedArg, LocalDefId>>)>, + mut lifetime: ResolvedArg, + ident: Ident, + ) -> ResolvedArg { + if let Some(&(opaque_def_id, _)) = opaque_capture_scopes.last() { + if let Err(guar) = + self.check_lifetime_is_capturable(opaque_def_id, lifetime, ident.span) + { + lifetime = ResolvedArg::Error(guar); + } + } + + for &(opaque_def_id, captures) in opaque_capture_scopes.iter().rev() { + let mut captures = captures.borrow_mut(); + let remapped = *captures.entry(lifetime).or_insert_with(|| { + let feed = self.tcx.create_def(opaque_def_id, ident.name, DefKind::LifetimeParam); + feed.def_span(ident.span); + feed.def_ident_span(Some(ident.span)); + feed.def_id() + }); + lifetime = ResolvedArg::EarlyBound(remapped); + } + lifetime + } + fn resolve_type_ref(&mut self, param_def_id: LocalDefId, hir_id: HirId) { // Walk up the scope chain, tracking the number of fn scopes // that we pass through, until we find a lifetime with the @@ -1341,6 +1485,7 @@ impl<'a, 'tcx> BoundVarContext<'a, 'tcx> { } Scope::ObjectLifetimeDefault { s, .. } + | Scope::Opaque { s, .. } | Scope::Supertrait { s, .. } | Scope::TraitRefBoundary { s, .. } => { scope = s; @@ -1421,6 +1566,7 @@ impl<'a, 'tcx> BoundVarContext<'a, 'tcx> { Scope::Root { .. } => break, Scope::Binder { s, .. } | Scope::Body { s, .. } + | Scope::Opaque { s, .. } | Scope::ObjectLifetimeDefault { s, .. } | Scope::Supertrait { s, .. } | Scope::TraitRefBoundary { s, .. } @@ -1497,6 +1643,7 @@ impl<'a, 'tcx> BoundVarContext<'a, 'tcx> { Scope::Binder { s, .. } | Scope::ObjectLifetimeDefault { s, .. } + | Scope::Opaque { s, .. } | Scope::Supertrait { s, .. } | Scope::TraitRefBoundary { s, .. } | Scope::LateBoundary { s, .. } => { @@ -1639,17 +1786,13 @@ impl<'a, 'tcx> BoundVarContext<'a, 'tcx> { constraint.ident, ty::AssocKind::Fn, ) { - bound_vars.extend(self.tcx.generics_of(assoc_fn.def_id).own_params.iter().map( - |param| match param.kind { - ty::GenericParamDefKind::Lifetime => ty::BoundVariableKind::Region( - ty::BoundRegionKind::BrNamed(param.def_id, param.name), - ), - ty::GenericParamDefKind::Type { .. } => ty::BoundVariableKind::Ty( - ty::BoundTyKind::Param(param.def_id, param.name), - ), - ty::GenericParamDefKind::Const { .. } => ty::BoundVariableKind::Const, - }, - )); + bound_vars.extend( + self.tcx + .generics_of(assoc_fn.def_id) + .own_params + .iter() + .map(|param| generic_param_def_as_bound_arg(param)), + ); bound_vars.extend( self.tcx.fn_sig(assoc_fn.def_id).instantiate_identity().bound_vars(), ); @@ -1786,7 +1929,8 @@ impl<'a, 'tcx> BoundVarContext<'a, 'tcx> { fn resolve_object_lifetime_default(&mut self, lifetime_ref: &'tcx hir::Lifetime) { let mut late_depth = 0; let mut scope = self.scope; - let lifetime = loop { + let mut opaque_capture_scopes = vec![]; + let mut lifetime = loop { match *scope { Scope::Binder { s, scope_type, .. } => { match scope_type { @@ -1800,7 +1944,15 @@ impl<'a, 'tcx> BoundVarContext<'a, 'tcx> { Scope::Body { .. } | Scope::ObjectLifetimeDefault { lifetime: None, .. } => return, - Scope::ObjectLifetimeDefault { lifetime: Some(l), .. } => break l, + Scope::ObjectLifetimeDefault { lifetime: Some(l), .. } => { + break l.shifted(late_depth); + } + + Scope::Opaque { captures, def_id, s } => { + opaque_capture_scopes.push((def_id, captures)); + late_depth = 0; + scope = s; + } Scope::Supertrait { s, .. } | Scope::TraitRefBoundary { s, .. } @@ -1809,7 +1961,10 @@ impl<'a, 'tcx> BoundVarContext<'a, 'tcx> { } } }; - self.insert_lifetime(lifetime_ref, lifetime.shifted(late_depth)); + + lifetime = self.remap_opaque_captures(&opaque_capture_scopes, lifetime, lifetime_ref.ident); + + self.insert_lifetime(lifetime_ref, lifetime); } #[instrument(level = "debug", skip(self))] @@ -1818,18 +1973,6 @@ impl<'a, 'tcx> BoundVarContext<'a, 'tcx> { self.map.defs.insert(lifetime_ref.hir_id.local_id, def); } - /// Sometimes we resolve a lifetime, but later find that it is an - /// error (esp. around impl trait). In that case, we remove the - /// entry into `map.defs` so as not to confuse later code. - fn uninsert_lifetime_on_error( - &mut self, - lifetime_ref: &'tcx hir::Lifetime, - bad_def: ResolvedArg, - ) { - let old_value = self.map.defs.remove(&lifetime_ref.hir_id.local_id); - assert_eq!(old_value, Some(bad_def)); - } - // When we have a return type notation type in a where clause, like // `where <T as Trait>::method(..): Send`, we need to introduce new bound // vars to the existing where clause's binder, to represent the lifetimes @@ -1968,17 +2111,13 @@ impl<'a, 'tcx> BoundVarContext<'a, 'tcx> { // Append the early-bound vars on the function, and then the late-bound ones. // We actually turn type parameters into higher-ranked types here, but we // deny them later in HIR lowering. - bound_vars.extend(self.tcx.generics_of(item_def_id).own_params.iter().map(|param| { - match param.kind { - ty::GenericParamDefKind::Lifetime => ty::BoundVariableKind::Region( - ty::BoundRegionKind::BrNamed(param.def_id, param.name), - ), - ty::GenericParamDefKind::Type { .. } => { - ty::BoundVariableKind::Ty(ty::BoundTyKind::Param(param.def_id, param.name)) - } - ty::GenericParamDefKind::Const { .. } => ty::BoundVariableKind::Const, - } - })); + bound_vars.extend( + self.tcx + .generics_of(item_def_id) + .own_params + .iter() + .map(|param| generic_param_def_as_bound_arg(param)), + ); bound_vars.extend(self.tcx.fn_sig(item_def_id).instantiate_identity().bound_vars()); // SUBTLE: Stash the old bound vars onto the *item segment* before appending @@ -2017,18 +2156,22 @@ fn is_late_bound_map( tcx: TyCtxt<'_>, owner_id: hir::OwnerId, ) -> Option<&FxIndexSet<hir::ItemLocalId>> { - let decl = tcx.hir().fn_decl_by_hir_id(owner_id.into())?; + let sig = tcx.hir().fn_sig_by_hir_id(owner_id.into())?; let generics = tcx.hir().get_generics(owner_id.def_id)?; let mut late_bound = FxIndexSet::default(); let mut constrained_by_input = ConstrainedCollector { regions: Default::default(), tcx }; - for arg_ty in decl.inputs { + for arg_ty in sig.decl.inputs { constrained_by_input.visit_ty(arg_ty); } - let mut appears_in_output = AllCollector::default(); - intravisit::walk_fn_ret_ty(&mut appears_in_output, &decl.output); + let mut appears_in_output = + AllCollector { tcx, has_fully_capturing_opaque: false, regions: Default::default() }; + intravisit::walk_fn_ret_ty(&mut appears_in_output, &sig.decl.output); + if appears_in_output.has_fully_capturing_opaque { + appears_in_output.regions.extend(generics.params.iter().map(|param| param.def_id)); + } debug!(?constrained_by_input.regions); @@ -2036,7 +2179,8 @@ fn is_late_bound_map( // // Subtle point: because we disallow nested bindings, we can just // ignore binders here and scrape up all names we see. - let mut appears_in_where_clause = AllCollector::default(); + let mut appears_in_where_clause = + AllCollector { tcx, has_fully_capturing_opaque: true, regions: Default::default() }; appears_in_where_clause.visit_generics(generics); debug!(?appears_in_where_clause.regions); @@ -2202,17 +2346,26 @@ fn is_late_bound_map( } } - #[derive(Default)] - struct AllCollector { + struct AllCollector<'tcx> { + tcx: TyCtxt<'tcx>, + has_fully_capturing_opaque: bool, regions: FxHashSet<LocalDefId>, } - impl<'v> Visitor<'v> for AllCollector { + impl<'v> Visitor<'v> for AllCollector<'v> { fn visit_lifetime(&mut self, lifetime_ref: &'v hir::Lifetime) { if let hir::LifetimeName::Param(def_id) = lifetime_ref.res { self.regions.insert(def_id); } } + + fn visit_opaque_ty(&mut self, opaque: &'v hir::OpaqueTy<'v>) { + if !self.has_fully_capturing_opaque { + self.has_fully_capturing_opaque = + opaque_captures_all_in_scope_lifetimes(self.tcx, opaque); + } + intravisit::walk_opaque_ty(self, opaque); + } } } diff --git a/compiler/rustc_hir_analysis/src/errors.rs b/compiler/rustc_hir_analysis/src/errors.rs index 77e81af3ca9..a92a5e4278c 100644 --- a/compiler/rustc_hir_analysis/src/errors.rs +++ b/compiler/rustc_hir_analysis/src/errors.rs @@ -1624,10 +1624,14 @@ pub(crate) struct InvalidReceiverTy<'tcx> { } #[derive(Diagnostic)] -#[diag(hir_analysis_effects_without_next_solver)] +#[diag(hir_analysis_invalid_generic_receiver_ty, code = E0801)] #[note] -#[help] -pub(crate) struct EffectsWithoutNextSolver; +#[help(hir_analysis_invalid_generic_receiver_ty_help)] +pub(crate) struct InvalidGenericReceiverTy<'tcx> { + #[primary_span] + pub span: Span, + pub receiver_ty: Ty<'tcx>, +} #[derive(Diagnostic)] #[diag(hir_analysis_cmse_inputs_stack_spill, code = E0798)] diff --git a/compiler/rustc_hir_analysis/src/hir_ty_lowering/bounds.rs b/compiler/rustc_hir_analysis/src/hir_ty_lowering/bounds.rs index c902e85c267..a5709089db6 100644 --- a/compiler/rustc_hir_analysis/src/hir_ty_lowering/bounds.rs +++ b/compiler/rustc_hir_analysis/src/hir_ty_lowering/bounds.rs @@ -168,13 +168,6 @@ impl<'tcx> dyn HirTyLowerer<'tcx> + '_ { match hir_bound { hir::GenericBound::Trait(poly_trait_ref) => { let hir::TraitBoundModifiers { constness, polarity } = poly_trait_ref.modifiers; - // FIXME: We could pass these directly into `lower_poly_trait_ref` - // so that we could use these spans in diagnostics within that function... - let constness = match constness { - hir::BoundConstness::Never => None, - hir::BoundConstness::Always(_) => Some(ty::BoundConstness::Const), - hir::BoundConstness::Maybe(_) => Some(ty::BoundConstness::ConstIfConst), - }; let polarity = match polarity { rustc_ast::BoundPolarity::Positive => ty::PredicatePolarity::Positive, rustc_ast::BoundPolarity::Negative(_) => ty::PredicatePolarity::Negative, diff --git a/compiler/rustc_hir_analysis/src/hir_ty_lowering/dyn_compatibility.rs b/compiler/rustc_hir_analysis/src/hir_ty_lowering/dyn_compatibility.rs index 890e8fa99e6..f2ee4b0ccd4 100644 --- a/compiler/rustc_hir_analysis/src/hir_ty_lowering/dyn_compatibility.rs +++ b/compiler/rustc_hir_analysis/src/hir_ty_lowering/dyn_compatibility.rs @@ -50,7 +50,7 @@ impl<'tcx> dyn HirTyLowerer<'tcx> + '_ { } = self.lower_poly_trait_ref( &trait_bound.trait_ref, trait_bound.span, - None, + hir::BoundConstness::Never, ty::PredicatePolarity::Positive, dummy_self, &mut bounds, diff --git a/compiler/rustc_hir_analysis/src/hir_ty_lowering/mod.rs b/compiler/rustc_hir_analysis/src/hir_ty_lowering/mod.rs index 863c077a9e0..f2bc17051ab 100644 --- a/compiler/rustc_hir_analysis/src/hir_ty_lowering/mod.rs +++ b/compiler/rustc_hir_analysis/src/hir_ty_lowering/mod.rs @@ -39,7 +39,7 @@ use rustc_middle::mir::interpret::{LitToConstError, LitToConstInput}; use rustc_middle::ty::print::PrintPolyTraitRefExt as _; use rustc_middle::ty::{ self, Const, GenericArgKind, GenericArgsRef, GenericParamDefKind, ParamEnv, Ty, TyCtxt, - TypeVisitableExt, + TypeVisitableExt, TypingMode, }; use rustc_middle::{bug, span_bug}; use rustc_session::lint::builtin::AMBIGUOUS_ASSOCIATED_ITEMS; @@ -294,13 +294,23 @@ impl<'tcx> dyn HirTyLowerer<'tcx> + '_ { lifetime: &hir::Lifetime, reason: RegionInferReason<'_>, ) -> ty::Region<'tcx> { + if let Some(resolved) = self.tcx().named_bound_var(lifetime.hir_id) { + self.lower_resolved_lifetime(resolved) + } else { + self.re_infer(lifetime.ident.span, reason) + } + } + + /// Lower a lifetime from the HIR to our internal notion of a lifetime called a *region*. + #[instrument(level = "debug", skip(self), ret)] + pub fn lower_resolved_lifetime(&self, resolved: rbv::ResolvedArg) -> ty::Region<'tcx> { let tcx = self.tcx(); let lifetime_name = |def_id| tcx.hir().name(tcx.local_def_id_to_hir_id(def_id)); - match tcx.named_bound_var(lifetime.hir_id) { - Some(rbv::ResolvedArg::StaticLifetime) => tcx.lifetimes.re_static, + match resolved { + rbv::ResolvedArg::StaticLifetime => tcx.lifetimes.re_static, - Some(rbv::ResolvedArg::LateBound(debruijn, index, def_id)) => { + rbv::ResolvedArg::LateBound(debruijn, index, def_id) => { let name = lifetime_name(def_id); let br = ty::BoundRegion { var: ty::BoundVar::from_u32(index), @@ -309,7 +319,7 @@ impl<'tcx> dyn HirTyLowerer<'tcx> + '_ { ty::Region::new_bound(tcx, debruijn, br) } - Some(rbv::ResolvedArg::EarlyBound(def_id)) => { + rbv::ResolvedArg::EarlyBound(def_id) => { let name = tcx.hir().ty_param_name(def_id); let item_def_id = tcx.hir().ty_param_owner(def_id); let generics = tcx.generics_of(item_def_id); @@ -317,7 +327,7 @@ impl<'tcx> dyn HirTyLowerer<'tcx> + '_ { ty::Region::new_early_param(tcx, ty::EarlyParamRegion { index, name }) } - Some(rbv::ResolvedArg::Free(scope, id)) => { + rbv::ResolvedArg::Free(scope, id) => { let name = lifetime_name(id); ty::Region::new_late_param( tcx, @@ -328,9 +338,7 @@ impl<'tcx> dyn HirTyLowerer<'tcx> + '_ { // (*) -- not late-bound, won't change } - Some(rbv::ResolvedArg::Error(guar)) => ty::Region::new_error(tcx, guar), - - None => self.re_infer(lifetime.ident.span, reason), + rbv::ResolvedArg::Error(guar) => ty::Region::new_error(tcx, guar), } } @@ -658,7 +666,7 @@ impl<'tcx> dyn HirTyLowerer<'tcx> + '_ { &self, trait_ref: &hir::TraitRef<'tcx>, span: Span, - constness: Option<ty::BoundConstness>, + constness: hir::BoundConstness, polarity: ty::PredicatePolarity, self_ty: Ty<'tcx>, bounds: &mut Bounds<'tcx>, @@ -681,11 +689,11 @@ impl<'tcx> dyn HirTyLowerer<'tcx> + '_ { Some(self_ty), ); - if let Some(constness) = constness + if let hir::BoundConstness::Always(span) | hir::BoundConstness::Maybe(span) = constness && !self.tcx().is_const_trait(trait_def_id) { self.dcx().emit_err(crate::errors::ConstBoundForNonConstTrait { - span: trait_ref.path.span, + span, modifier: constness.as_str(), }); } @@ -708,7 +716,7 @@ impl<'tcx> dyn HirTyLowerer<'tcx> + '_ { bounds.push_trait_bound(tcx, poly_trait_ref, span, polarity); match constness { - Some(ty::BoundConstness::Const) => { + hir::BoundConstness::Always(span) => { if polarity == ty::PredicatePolarity::Positive { bounds.push_const_bound( tcx, @@ -718,13 +726,13 @@ impl<'tcx> dyn HirTyLowerer<'tcx> + '_ { ); } } - Some(ty::BoundConstness::ConstIfConst) => { + hir::BoundConstness::Maybe(_) => { // We don't emit a const bound here, since that would mean that we // unconditionally need to prove a `HostEffect` predicate, even when // the predicates are being instantiated in a non-const context. This // is instead handled in the `const_conditions` query. } - None => {} + hir::BoundConstness::Never => {} } } // On the flip side, when filtering `ConstIfConst` bounds, we only need to convert @@ -734,12 +742,12 @@ impl<'tcx> dyn HirTyLowerer<'tcx> + '_ { // here because we only call this on self bounds, and deal with the recursive case // in `lower_assoc_item_constraint`. PredicateFilter::ConstIfConst | PredicateFilter::SelfConstIfConst => match constness { - Some(ty::BoundConstness::ConstIfConst) => { + hir::BoundConstness::Maybe(span) => { if polarity == ty::PredicatePolarity::Positive { bounds.push_const_bound(tcx, poly_trait_ref, ty::HostPolarity::Maybe, span); } } - None | Some(ty::BoundConstness::Const) => {} + hir::BoundConstness::Always(_) | hir::BoundConstness::Never => {} }, } @@ -1203,15 +1211,6 @@ impl<'tcx> dyn HirTyLowerer<'tcx> + '_ { err.emit() } else if let Err(reported) = qself_ty.error_reported() { reported - } else if let ty::Alias(ty::Opaque, alias_ty) = qself_ty.kind() { - // `<impl Trait as OtherTrait>::Assoc` makes no sense. - struct_span_code_err!( - self.dcx(), - tcx.def_span(alias_ty.def_id), - E0667, - "`impl Trait` is not allowed in path parameters" - ) - .emit() // Already reported in an earlier stage. } else { self.maybe_report_similar_assoc_fn(span, qself_ty, qself)?; @@ -1309,7 +1308,7 @@ impl<'tcx> dyn HirTyLowerer<'tcx> + '_ { Some(infcx) => infcx, None => { assert!(!self_ty.has_infer()); - infcx_ = tcx.infer_ctxt().ignoring_regions().build(); + infcx_ = tcx.infer_ctxt().ignoring_regions().build(TypingMode::non_body_analysis()); &infcx_ } }; @@ -1501,7 +1500,7 @@ impl<'tcx> dyn HirTyLowerer<'tcx> + '_ { infcx } else { assert!(!qself_ty.has_infer()); - infcx_ = tcx.infer_ctxt().build(); + infcx_ = tcx.infer_ctxt().build(TypingMode::non_body_analysis()); &infcx_ }; @@ -2103,13 +2102,11 @@ impl<'tcx> dyn HirTyLowerer<'tcx> + '_ { let opt_self_ty = maybe_qself.as_ref().map(|qself| self.lower_ty(qself)); self.lower_path(opt_self_ty, path, hir_ty.hir_id, false) } - &hir::TyKind::OpaqueDef(opaque_ty, lifetimes) => { - let local_def_id = opaque_ty.def_id; - + &hir::TyKind::OpaqueDef(opaque_ty) => { // If this is an RPITIT and we are using the new RPITIT lowering scheme, we // generate the def_id of an associated type for the trait and return as // type a projection. - match opaque_ty.origin { + let in_trait = match opaque_ty.origin { hir::OpaqueTyOrigin::FnReturn { in_trait_or_impl: Some(hir::RpitContext::Trait), .. @@ -2117,11 +2114,7 @@ impl<'tcx> dyn HirTyLowerer<'tcx> + '_ { | hir::OpaqueTyOrigin::AsyncFn { in_trait_or_impl: Some(hir::RpitContext::Trait), .. - } => self.lower_opaque_ty( - tcx.associated_type_for_impl_trait_in_trait(local_def_id).to_def_id(), - lifetimes, - true, - ), + } => true, hir::OpaqueTyOrigin::FnReturn { in_trait_or_impl: None | Some(hir::RpitContext::TraitImpl), .. @@ -2130,10 +2123,10 @@ impl<'tcx> dyn HirTyLowerer<'tcx> + '_ { in_trait_or_impl: None | Some(hir::RpitContext::TraitImpl), .. } - | hir::OpaqueTyOrigin::TyAlias { .. } => { - self.lower_opaque_ty(local_def_id.to_def_id(), lifetimes, false) - } - } + | hir::OpaqueTyOrigin::TyAlias { .. } => false, + }; + + self.lower_opaque_ty(opaque_ty.def_id, in_trait) } // If we encounter a type relative path with RTN generics, then it must have // *not* gone through `lower_ty_maybe_return_type_notation`, and therefore @@ -2273,40 +2266,34 @@ impl<'tcx> dyn HirTyLowerer<'tcx> + '_ { } /// Lower an opaque type (i.e., an existential impl-Trait type) from the HIR. - #[instrument(level = "debug", skip_all, ret)] - fn lower_opaque_ty( - &self, - def_id: DefId, - lifetimes: &[hir::GenericArg<'_>], - in_trait: bool, - ) -> Ty<'tcx> { - debug!(?def_id, ?lifetimes); + #[instrument(level = "debug", skip(self), ret)] + fn lower_opaque_ty(&self, def_id: LocalDefId, in_trait: bool) -> Ty<'tcx> { let tcx = self.tcx(); + let lifetimes = tcx.opaque_captured_lifetimes(def_id); + debug!(?lifetimes); + + // If this is an RPITIT and we are using the new RPITIT lowering scheme, we + // generate the def_id of an associated type for the trait and return as + // type a projection. + let def_id = if in_trait { + tcx.associated_type_for_impl_trait_in_trait(def_id).to_def_id() + } else { + def_id.to_def_id() + }; + let generics = tcx.generics_of(def_id); debug!(?generics); + // We use `generics.count() - lifetimes.len()` here instead of `generics.parent_count` + // since return-position impl trait in trait squashes all of the generics from its source fn + // into its own generics, so the opaque's "own" params isn't always just lifetimes. + let offset = generics.count() - lifetimes.len(); + let args = ty::GenericArgs::for_item(tcx, def_id, |param, _| { - // We use `generics.count() - lifetimes.len()` here instead of `generics.parent_count` - // since return-position impl trait in trait squashes all of the generics from its source fn - // into its own generics, so the opaque's "own" params isn't always just lifetimes. - if let Some(i) = (param.index as usize).checked_sub(generics.count() - lifetimes.len()) - { - // Resolve our own lifetime parameters. - let GenericParamDefKind::Lifetime { .. } = param.kind else { - span_bug!( - tcx.def_span(param.def_id), - "only expected lifetime for opaque's own generics, got {:?}", - param - ); - }; - let hir::GenericArg::Lifetime(lifetime) = &lifetimes[i] else { - bug!( - "expected lifetime argument for param {param:?}, found {:?}", - &lifetimes[i] - ) - }; - self.lower_lifetime(lifetime, RegionInferReason::Param(¶m)).into() + if let Some(i) = (param.index as usize).checked_sub(offset) { + let (lifetime, _) = lifetimes[i]; + self.lower_resolved_lifetime(lifetime).into() } else { tcx.mk_param_from_def(param) } diff --git a/compiler/rustc_hir_analysis/src/hir_wf_check.rs b/compiler/rustc_hir_analysis/src/hir_wf_check.rs index 2fa4ca68073..5b0165bf993 100644 --- a/compiler/rustc_hir_analysis/src/hir_wf_check.rs +++ b/compiler/rustc_hir_analysis/src/hir_wf_check.rs @@ -5,7 +5,7 @@ use rustc_infer::infer::TyCtxtInferExt; use rustc_infer::traits::{ObligationCause, WellFormedLoc}; use rustc_middle::bug; use rustc_middle::query::Providers; -use rustc_middle::ty::{self, TyCtxt}; +use rustc_middle::ty::{self, TyCtxt, TypingMode}; use rustc_span::def_id::LocalDefId; use rustc_trait_selection::traits::{self, ObligationCtxt}; use tracing::debug; @@ -68,7 +68,7 @@ fn diagnostic_hir_wf_check<'tcx>( impl<'tcx> Visitor<'tcx> for HirWfCheck<'tcx> { fn visit_ty(&mut self, ty: &'tcx hir::Ty<'tcx>) { - let infcx = self.tcx.infer_ctxt().build(); + let infcx = self.tcx.infer_ctxt().build(TypingMode::non_body_analysis()); let ocx = ObligationCtxt::new_with_diagnostics(&infcx); let tcx_ty = self.icx.lower_ty(ty); diff --git a/compiler/rustc_hir_analysis/src/impl_wf_check/min_specialization.rs b/compiler/rustc_hir_analysis/src/impl_wf_check/min_specialization.rs index a394fc2fbb1..b0c9aed5d85 100644 --- a/compiler/rustc_hir_analysis/src/impl_wf_check/min_specialization.rs +++ b/compiler/rustc_hir_analysis/src/impl_wf_check/min_specialization.rs @@ -72,7 +72,9 @@ use rustc_infer::infer::TyCtxtInferExt; use rustc_infer::infer::outlives::env::OutlivesEnvironment; use rustc_infer::traits::specialization_graph::Node; use rustc_middle::ty::trait_def::TraitSpecializationKind; -use rustc_middle::ty::{self, GenericArg, GenericArgs, GenericArgsRef, TyCtxt, TypeVisitableExt}; +use rustc_middle::ty::{ + self, GenericArg, GenericArgs, GenericArgsRef, TyCtxt, TypeVisitableExt, TypingMode, +}; use rustc_span::{ErrorGuaranteed, Span}; use rustc_trait_selection::error_reporting::InferCtxtErrorExt; use rustc_trait_selection::traits::outlives_bounds::InferCtxtExt as _; @@ -195,7 +197,7 @@ fn get_impl_args( impl1_def_id: LocalDefId, impl2_node: Node, ) -> Result<(GenericArgsRef<'_>, GenericArgsRef<'_>), ErrorGuaranteed> { - let infcx = &tcx.infer_ctxt().build(); + let infcx = &tcx.infer_ctxt().build(TypingMode::non_body_analysis()); let ocx = ObligationCtxt::new_with_diagnostics(infcx); let param_env = tcx.param_env(impl1_def_id); let impl1_span = tcx.def_span(impl1_def_id); @@ -409,7 +411,7 @@ fn check_predicates<'tcx>( // Include the well-formed predicates of the type parameters of the impl. for arg in tcx.impl_trait_ref(impl1_def_id).unwrap().instantiate_identity().args { - let infcx = &tcx.infer_ctxt().build(); + let infcx = &tcx.infer_ctxt().build(TypingMode::non_body_analysis()); let obligations = wf::obligations(infcx, tcx.param_env(impl1_def_id), impl1_def_id, 0, arg, span) .unwrap(); diff --git a/compiler/rustc_hir_analysis/src/lib.rs b/compiler/rustc_hir_analysis/src/lib.rs index 3ad35163191..339eddeeade 100644 --- a/compiler/rustc_hir_analysis/src/lib.rs +++ b/compiler/rustc_hir_analysis/src/lib.rs @@ -153,12 +153,6 @@ pub fn provide(providers: &mut Providers) { pub fn check_crate(tcx: TyCtxt<'_>) { let _prof_timer = tcx.sess.timer("type_check_crate"); - // FIXME(effects): remove once effects is implemented in old trait solver - // or if the next solver is stabilized. - if tcx.features().effects() && !tcx.next_trait_solver_globally() { - tcx.dcx().emit_err(errors::EffectsWithoutNextSolver); - } - tcx.sess.time("coherence_checking", || { tcx.hir().par_for_each_module(|module| { let _ = tcx.ensure().check_mod_type_wf(module); diff --git a/compiler/rustc_hir_pretty/src/lib.rs b/compiler/rustc_hir_pretty/src/lib.rs index 61214b99215..2073f2868b4 100644 --- a/compiler/rustc_hir_pretty/src/lib.rs +++ b/compiler/rustc_hir_pretty/src/lib.rs @@ -659,8 +659,6 @@ impl<'a> State<'a> { fn print_opaque_ty(&mut self, o: &hir::OpaqueTy<'_>) { self.head("opaque"); - self.print_generic_params(o.generics.params); - self.print_where_clause(o.generics); self.word("{"); self.print_bounds("impl", o.bounds); self.word("}"); diff --git a/compiler/rustc_hir_typeck/src/_match.rs b/compiler/rustc_hir_typeck/src/_match.rs index e68caa3e2e3..3372cae7a51 100644 --- a/compiler/rustc_hir_typeck/src/_match.rs +++ b/compiler/rustc_hir_typeck/src/_match.rs @@ -94,14 +94,11 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { (None, arm.body.span) }; - let (span, code) = match prior_arm { + let code = match prior_arm { // The reason for the first arm to fail is not that the match arms diverge, // but rather that there's a prior obligation that doesn't hold. - None => { - (arm_span, ObligationCauseCode::BlockTailExpression(arm.body.hir_id, match_src)) - } - Some((prior_arm_block_id, prior_arm_ty, prior_arm_span)) => ( - expr.span, + None => ObligationCauseCode::BlockTailExpression(arm.body.hir_id, match_src), + Some((prior_arm_block_id, prior_arm_ty, prior_arm_span)) => { ObligationCauseCode::MatchExpressionArm(Box::new(MatchExpressionArmCause { arm_block_id, arm_span, @@ -110,13 +107,14 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { prior_arm_ty, prior_arm_span, scrut_span: scrut.span, + expr_span: expr.span, source: match_src, prior_non_diverging_arms: prior_non_diverging_arms.clone(), tail_defines_return_position_impl_trait, - })), - ), + })) + } }; - let cause = self.cause(span, code); + let cause = self.cause(arm_span, code); // This is the moral equivalent of `coercion.coerce(self, cause, arm.body, arm_ty)`. // We use it this way to be able to expand on the potential error and detect when a diff --git a/compiler/rustc_hir_typeck/src/autoderef.rs b/compiler/rustc_hir_typeck/src/autoderef.rs index e4ca1cee757..c3e095b0554 100644 --- a/compiler/rustc_hir_typeck/src/autoderef.rs +++ b/compiler/rustc_hir_typeck/src/autoderef.rs @@ -23,7 +23,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { span: Span, base_ty: Ty<'tcx>, ) -> Option<InferOk<'tcx, MethodCallee<'tcx>>> { - self.try_overloaded_place_op(span, base_ty, &[], PlaceOp::Deref) + self.try_overloaded_place_op(span, base_ty, None, PlaceOp::Deref) } /// Returns the adjustment steps. diff --git a/compiler/rustc_hir_typeck/src/callee.rs b/compiler/rustc_hir_typeck/src/callee.rs index ed56bb9c455..9cf1ea3fcb8 100644 --- a/compiler/rustc_hir_typeck/src/callee.rs +++ b/compiler/rustc_hir_typeck/src/callee.rs @@ -1,4 +1,4 @@ -use std::{iter, slice}; +use std::iter; use rustc_ast::util::parser::PREC_UNAMBIGUOUS; use rustc_errors::{Applicability, Diag, ErrorGuaranteed, StashKey}; @@ -300,7 +300,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { Ident::with_dummy_span(method_name), trait_def_id, adjusted_ty, - opt_input_type.as_ref().map(slice::from_ref), + opt_input_type, ) { let method = self.register_infer_ok_obligations(ok); let mut autoref = None; diff --git a/compiler/rustc_hir_typeck/src/expr.rs b/compiler/rustc_hir_typeck/src/expr.rs index 92c2a906055..d6e5fab610e 100644 --- a/compiler/rustc_hir_typeck/src/expr.rs +++ b/compiler/rustc_hir_typeck/src/expr.rs @@ -2027,7 +2027,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { } Err(_) => { span_bug!( - cause.span(), + cause.span, "subtyping remaining fields of type changing FRU failed: {target_ty} != {fru_ty}: {}::{}", variant.name, ident.name, diff --git a/compiler/rustc_hir_typeck/src/method/confirm.rs b/compiler/rustc_hir_typeck/src/method/confirm.rs index 96784fcb61b..92b504d10bc 100644 --- a/compiler/rustc_hir_typeck/src/method/confirm.rs +++ b/compiler/rustc_hir_typeck/src/method/confirm.rs @@ -533,9 +533,6 @@ impl<'a, 'tcx> ConfirmContext<'a, 'tcx> { self.register_predicates(obligations); } Err(terr) => { - // FIXME(arbitrary_self_types): We probably should limit the - // situations where this can occur by adding additional restrictions - // to the feature, like the self type can't reference method args. if self.tcx.features().arbitrary_self_types() { self.err_ctxt() .report_mismatched_types( @@ -550,7 +547,7 @@ impl<'a, 'tcx> ConfirmContext<'a, 'tcx> { // This has/will have errored in wfcheck, which we cannot depend on from here, as typeck on functions // may run before wfcheck if the function is used in const eval. self.dcx().span_delayed_bug( - cause.span(), + cause.span, format!("{self_ty} was a subtype of {method_self_ty} but now is not?"), ); } diff --git a/compiler/rustc_hir_typeck/src/method/mod.rs b/compiler/rustc_hir_typeck/src/method/mod.rs index e20a0cb67c3..e0b6ea0ac9d 100644 --- a/compiler/rustc_hir_typeck/src/method/mod.rs +++ b/compiler/rustc_hir_typeck/src/method/mod.rs @@ -324,35 +324,6 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { Ok(pick) } - pub(super) fn obligation_for_method( - &self, - cause: ObligationCause<'tcx>, - trait_def_id: DefId, - self_ty: Ty<'tcx>, - opt_input_types: Option<&[Ty<'tcx>]>, - ) -> (traits::PredicateObligation<'tcx>, ty::GenericArgsRef<'tcx>) { - // Construct a trait-reference `self_ty : Trait<input_tys>` - let args = GenericArgs::for_item(self.tcx, trait_def_id, |param, _| { - match param.kind { - GenericParamDefKind::Lifetime | GenericParamDefKind::Const { .. } => {} - GenericParamDefKind::Type { .. } => { - if param.index == 0 { - return self_ty.into(); - } else if let Some(input_types) = opt_input_types { - return input_types[param.index as usize - 1].into(); - } - } - } - self.var_for_def(cause.span, param) - }); - - let trait_ref = ty::TraitRef::new_from_args(self.tcx, trait_def_id, args); - - // Construct an obligation - let poly_trait_ref = ty::Binder::dummy(trait_ref); - (traits::Obligation::new(self.tcx, cause, self.param_env, poly_trait_ref), args) - } - /// `lookup_method_in_trait` is used for overloaded operators. /// It does a very narrow slice of what the normal probe/confirm path does. /// In particular, it doesn't really do any probing: it simply constructs @@ -365,24 +336,34 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { m_name: Ident, trait_def_id: DefId, self_ty: Ty<'tcx>, - opt_input_types: Option<&[Ty<'tcx>]>, + opt_rhs_ty: Option<Ty<'tcx>>, ) -> Option<InferOk<'tcx, MethodCallee<'tcx>>> { - let (obligation, args) = - self.obligation_for_method(cause, trait_def_id, self_ty, opt_input_types); - self.construct_obligation_for_trait(m_name, trait_def_id, obligation, args) - } + // Construct a trait-reference `self_ty : Trait<input_tys>` + let args = GenericArgs::for_item(self.tcx, trait_def_id, |param, _| match param.kind { + GenericParamDefKind::Lifetime | GenericParamDefKind::Const { .. } => { + unreachable!("did not expect operator trait to have lifetime/const") + } + GenericParamDefKind::Type { .. } => { + if param.index == 0 { + self_ty.into() + } else if let Some(rhs_ty) = opt_rhs_ty { + assert_eq!(param.index, 1, "did not expect >1 param on operator trait"); + rhs_ty.into() + } else { + // FIXME: We should stop passing `None` for the failure case + // when probing for call exprs. I.e. `opt_rhs_ty` should always + // be set when it needs to be. + self.var_for_def(cause.span, param) + } + } + }); - // FIXME(#18741): it seems likely that we can consolidate some of this - // code with the other method-lookup code. In particular, the second half - // of this method is basically the same as confirmation. - fn construct_obligation_for_trait( - &self, - m_name: Ident, - trait_def_id: DefId, - obligation: traits::PredicateObligation<'tcx>, - args: ty::GenericArgsRef<'tcx>, - ) -> Option<InferOk<'tcx, MethodCallee<'tcx>>> { - debug!(?obligation); + let obligation = traits::Obligation::new( + self.tcx, + cause, + self.param_env, + ty::TraitRef::new_from_args(self.tcx, trait_def_id, args), + ); // Now we want to know if this can be matched if !self.predicate_may_hold(&obligation) { @@ -406,8 +387,6 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { debug!("lookup_in_trait_adjusted: method_item={:?}", method_item); let mut obligations = PredicateObligations::new(); - // FIXME(effects): revisit when binops get `#[const_trait]` - // Instantiate late-bound regions and instantiate the trait // parameters into the method type to get the actual method type. // @@ -418,12 +397,9 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { let fn_sig = self.instantiate_binder_with_fresh_vars(obligation.cause.span, infer::FnCall, fn_sig); - let InferOk { value, obligations: o } = + let InferOk { value: fn_sig, obligations: o } = self.at(&obligation.cause, self.param_env).normalize(fn_sig); - let fn_sig = { - obligations.extend(o); - value - }; + obligations.extend(o); // Register obligations for the parameters. This will include the // `Self` parameter, which in turn has a bound of the main trait, @@ -435,13 +411,9 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { // any late-bound regions appearing in its bounds. let bounds = self.tcx.predicates_of(def_id).instantiate(self.tcx, args); - let InferOk { value, obligations: o } = + let InferOk { value: bounds, obligations: o } = self.at(&obligation.cause, self.param_env).normalize(bounds); - let bounds = { - obligations.extend(o); - value - }; - + obligations.extend(o); assert!(!bounds.has_escaping_bound_vars()); let predicates_cause = obligation.cause.clone(); @@ -454,7 +426,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { // Also add an obligation for the method type being well-formed. let method_ty = Ty::new_fn_ptr(tcx, ty::Binder::dummy(fn_sig)); debug!( - "lookup_in_trait_adjusted: matched method method_ty={:?} obligation={:?}", + "lookup_method_in_trait: matched method method_ty={:?} obligation={:?}", method_ty, obligation ); obligations.push(traits::Obligation::new( @@ -467,7 +439,6 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { )); let callee = MethodCallee { def_id, args, sig: fn_sig }; - debug!("callee = {:?}", callee); Some(InferOk { obligations, value: callee }) diff --git a/compiler/rustc_hir_typeck/src/op.rs b/compiler/rustc_hir_typeck/src/op.rs index 1574e9e98d4..57ac7f7d2cd 100644 --- a/compiler/rustc_hir_typeck/src/op.rs +++ b/compiler/rustc_hir_typeck/src/op.rs @@ -15,7 +15,7 @@ use rustc_span::Span; use rustc_span::source_map::Spanned; use rustc_span::symbol::{Ident, sym}; use rustc_trait_selection::infer::InferCtxtExt; -use rustc_trait_selection::traits::{FulfillmentError, ObligationCtxt}; +use rustc_trait_selection::traits::{FulfillmentError, Obligation, ObligationCtxt}; use rustc_type_ir::TyKind::*; use tracing::debug; use {rustc_ast as ast, rustc_hir as hir}; @@ -895,7 +895,6 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { let opname = Ident::with_dummy_span(opname); let (opt_rhs_expr, opt_rhs_ty) = opt_rhs.unzip(); - let input_types = opt_rhs_ty.as_slice(); let cause = self.cause(span, ObligationCauseCode::BinOp { lhs_hir_id: lhs_expr.hir_id, rhs_hir_id: opt_rhs_expr.map(|expr| expr.hir_id), @@ -904,13 +903,8 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { output_ty: expected.only_has_type(self), }); - let method = self.lookup_method_in_trait( - cause.clone(), - opname, - trait_did, - lhs_ty, - Some(input_types), - ); + let method = + self.lookup_method_in_trait(cause.clone(), opname, trait_did, lhs_ty, opt_rhs_ty); match method { Some(ok) => { let method = self.register_infer_ok_obligations(ok); @@ -931,9 +925,27 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { self.check_expr_coercible_to_type(rhs_expr, rhs_ty, None); } - let (obligation, _) = - self.obligation_for_method(cause, trait_did, lhs_ty, Some(input_types)); - // FIXME: This should potentially just add the obligation to the `FnCtxt` + // Construct an obligation `self_ty : Trait<input_tys>` + let args = + ty::GenericArgs::for_item(self.tcx, trait_did, |param, _| match param.kind { + ty::GenericParamDefKind::Lifetime + | ty::GenericParamDefKind::Const { .. } => { + unreachable!("did not expect operand trait to have lifetime/const args") + } + ty::GenericParamDefKind::Type { .. } => { + if param.index == 0 { + lhs_ty.into() + } else { + opt_rhs_ty.expect("expected RHS for binop").into() + } + } + }); + let obligation = Obligation::new( + self.tcx, + cause, + self.param_env, + ty::TraitRef::new_from_args(self.tcx, trait_did, args), + ); let ocx = ObligationCtxt::new_with_diagnostics(&self.infcx); ocx.register_obligation(obligation); Err(ocx.select_all_or_error()) diff --git a/compiler/rustc_hir_typeck/src/place_op.rs b/compiler/rustc_hir_typeck/src/place_op.rs index 8604f5f6920..5dd51721022 100644 --- a/compiler/rustc_hir_typeck/src/place_op.rs +++ b/compiler/rustc_hir_typeck/src/place_op.rs @@ -149,7 +149,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { // If some lookup succeeded, install method in table let input_ty = self.next_ty_var(base_expr.span); let method = - self.try_overloaded_place_op(expr.span, self_ty, &[input_ty], PlaceOp::Index); + self.try_overloaded_place_op(expr.span, self_ty, Some(input_ty), PlaceOp::Index); if let Some(result) = method { debug!("try_index_step: success, using overloaded indexing"); @@ -189,7 +189,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { &self, span: Span, base_ty: Ty<'tcx>, - arg_tys: &[Ty<'tcx>], + opt_rhs_ty: Option<Ty<'tcx>>, op: PlaceOp, ) -> Option<InferOk<'tcx, MethodCallee<'tcx>>> { debug!("try_overloaded_place_op({:?},{:?},{:?})", span, base_ty, op); @@ -207,7 +207,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { Ident::with_dummy_span(imm_op), imm_tr, base_ty, - Some(arg_tys), + opt_rhs_ty, ) } @@ -215,7 +215,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { &self, span: Span, base_ty: Ty<'tcx>, - arg_tys: &[Ty<'tcx>], + opt_rhs_ty: Option<Ty<'tcx>>, op: PlaceOp, ) -> Option<InferOk<'tcx, MethodCallee<'tcx>>> { debug!("try_mutable_overloaded_place_op({:?},{:?},{:?})", span, base_ty, op); @@ -233,7 +233,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { Ident::with_dummy_span(mut_op), mut_tr, base_ty, - Some(arg_tys), + opt_rhs_ty, ) } @@ -284,7 +284,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { && let Some(ok) = self.try_mutable_overloaded_place_op( expr.span, source, - &[], + None, PlaceOp::Deref, ) { @@ -359,8 +359,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { Some(self.typeck_results.borrow().node_args(expr.hir_id).type_at(1)) } }; - let arg_tys = arg_ty.as_slice(); - let method = self.try_mutable_overloaded_place_op(expr.span, base_ty, arg_tys, op); + let method = self.try_mutable_overloaded_place_op(expr.span, base_ty, arg_ty, op); let method = match method { Some(ok) => self.register_infer_ok_obligations(ok), // Couldn't find the mutable variant of the place op, keep the diff --git a/compiler/rustc_hir_typeck/src/typeck_root_ctxt.rs b/compiler/rustc_hir_typeck/src/typeck_root_ctxt.rs index 18e40cfa428..903be7e732a 100644 --- a/compiler/rustc_hir_typeck/src/typeck_root_ctxt.rs +++ b/compiler/rustc_hir_typeck/src/typeck_root_ctxt.rs @@ -8,7 +8,7 @@ use rustc_hir::{HirId, HirIdMap}; use rustc_infer::infer::{InferCtxt, InferOk, TyCtxtInferExt}; use rustc_middle::span_bug; use rustc_middle::ty::visit::TypeVisitableExt; -use rustc_middle::ty::{self, Ty, TyCtxt}; +use rustc_middle::ty::{self, Ty, TyCtxt, TypingMode}; use rustc_span::Span; use rustc_span::def_id::LocalDefIdMap; use rustc_trait_selection::traits::query::evaluate_obligation::InferCtxtExt; @@ -81,7 +81,8 @@ impl<'tcx> TypeckRootCtxt<'tcx> { pub(crate) fn new(tcx: TyCtxt<'tcx>, def_id: LocalDefId) -> Self { let hir_owner = tcx.local_def_id_to_hir_id(def_id).owner; - let infcx = tcx.infer_ctxt().ignoring_regions().with_opaque_type_inference(def_id).build(); + let infcx = + tcx.infer_ctxt().ignoring_regions().build(TypingMode::analysis_in_body(tcx, def_id)); let typeck_results = RefCell::new(ty::TypeckResults::new(hir_owner)); TypeckRootCtxt { diff --git a/compiler/rustc_infer/src/infer/at.rs b/compiler/rustc_infer/src/infer/at.rs index 8c943a961e7..3eda3e9c67e 100644 --- a/compiler/rustc_infer/src/infer/at.rs +++ b/compiler/rustc_infer/src/infer/at.rs @@ -28,7 +28,7 @@ use relate::lattice::{LatticeOp, LatticeOpKind}; use rustc_middle::bug; use rustc_middle::ty::relate::solver_relating::RelateExt as NextSolverRelate; -use rustc_middle::ty::{Const, ImplSubject}; +use rustc_middle::ty::{Const, ImplSubject, TypingMode}; use super::*; use crate::infer::relate::type_relating::TypeRelating; @@ -67,30 +67,48 @@ impl<'tcx> InferCtxt<'tcx> { /// variables in the same state. This can be used to "branch off" many tests from the same /// common state. pub fn fork(&self) -> Self { - self.fork_with_intercrate(self.intercrate) + Self { + tcx: self.tcx, + typing_mode: self.typing_mode, + considering_regions: self.considering_regions, + skip_leak_check: self.skip_leak_check, + inner: self.inner.clone(), + lexical_region_resolutions: self.lexical_region_resolutions.clone(), + selection_cache: self.selection_cache.clone(), + evaluation_cache: self.evaluation_cache.clone(), + reported_trait_errors: self.reported_trait_errors.clone(), + reported_signature_mismatch: self.reported_signature_mismatch.clone(), + tainted_by_errors: self.tainted_by_errors.clone(), + universe: self.universe.clone(), + next_trait_solver: self.next_trait_solver, + obligation_inspector: self.obligation_inspector.clone(), + } } /// Forks the inference context, creating a new inference context with the same inference /// variables in the same state, except possibly changing the intercrate mode. This can be /// used to "branch off" many tests from the same common state. Used in negative coherence. - pub fn fork_with_intercrate(&self, intercrate: bool) -> Self { - Self { + pub fn fork_with_typing_mode(&self, typing_mode: TypingMode<'tcx>) -> Self { + // Unlike `fork`, this invalidates all cache entries as they may depend on the + // typing mode. + let forked = Self { tcx: self.tcx, - defining_opaque_types: self.defining_opaque_types, + typing_mode, considering_regions: self.considering_regions, skip_leak_check: self.skip_leak_check, inner: self.inner.clone(), lexical_region_resolutions: self.lexical_region_resolutions.clone(), - selection_cache: self.selection_cache.clone(), - evaluation_cache: self.evaluation_cache.clone(), + selection_cache: Default::default(), + evaluation_cache: Default::default(), reported_trait_errors: self.reported_trait_errors.clone(), reported_signature_mismatch: self.reported_signature_mismatch.clone(), tainted_by_errors: self.tainted_by_errors.clone(), universe: self.universe.clone(), - intercrate, next_trait_solver: self.next_trait_solver, obligation_inspector: self.obligation_inspector.clone(), - } + }; + forked.inner.borrow_mut().projection_cache().clear(); + forked } } diff --git a/compiler/rustc_infer/src/infer/canonical/canonicalizer.rs b/compiler/rustc_infer/src/infer/canonical/canonicalizer.rs index 90d07964fda..c9d8ebecef0 100644 --- a/compiler/rustc_infer/src/infer/canonical/canonicalizer.rs +++ b/compiler/rustc_infer/src/infer/canonical/canonicalizer.rs @@ -46,7 +46,7 @@ impl<'tcx> InferCtxt<'tcx> { V: TypeFoldable<TyCtxt<'tcx>>, { let (param_env, value) = value.into_parts(); - let param_env = self.tcx.canonical_param_env_cache.get_or_insert( + let canonical_param_env = self.tcx.canonical_param_env_cache.get_or_insert( self.tcx, param_env, query_state, @@ -64,7 +64,7 @@ impl<'tcx> InferCtxt<'tcx> { ); let canonical = Canonicalizer::canonicalize_with_base( - param_env, + canonical_param_env, value, Some(self), self.tcx, @@ -72,7 +72,7 @@ impl<'tcx> InferCtxt<'tcx> { query_state, ) .unchecked_map(|(param_env, value)| param_env.and(value)); - CanonicalQueryInput { canonical, defining_opaque_types: self.defining_opaque_types() } + CanonicalQueryInput { canonical, typing_mode: self.typing_mode(param_env) } } /// Canonicalizes a query *response* `V`. When we canonicalize a diff --git a/compiler/rustc_infer/src/infer/context.rs b/compiler/rustc_infer/src/infer/context.rs index 0c151a11ad4..ecda9c6eb00 100644 --- a/compiler/rustc_infer/src/infer/context.rs +++ b/compiler/rustc_infer/src/infer/context.rs @@ -1,7 +1,6 @@ ///! Definition of `InferCtxtLike` from the librarified type layer. -use rustc_hir::def_id::{DefId, LocalDefId}; +use rustc_hir::def_id::DefId; use rustc_middle::traits::ObligationCause; -use rustc_middle::traits::solve::SolverMode; use rustc_middle::ty::fold::TypeFoldable; use rustc_middle::ty::relate::RelateResult; use rustc_middle::ty::relate::combine::PredicateEmittingRelation; @@ -21,11 +20,11 @@ impl<'tcx> rustc_type_ir::InferCtxtLike for InferCtxt<'tcx> { self.next_trait_solver } - fn solver_mode(&self) -> ty::solve::SolverMode { - match self.intercrate { - true => SolverMode::Coherence, - false => SolverMode::Normal, - } + fn typing_mode( + &self, + param_env_for_debug_assertion: ty::ParamEnv<'tcx>, + ) -> ty::TypingMode<'tcx> { + self.typing_mode(param_env_for_debug_assertion) } fn universe(&self) -> ty::UniverseIndex { @@ -91,10 +90,6 @@ impl<'tcx> rustc_type_ir::InferCtxtLike for InferCtxt<'tcx> { self.inner.borrow_mut().unwrap_region_constraints().opportunistic_resolve_var(self.tcx, vid) } - fn defining_opaque_types(&self) -> &'tcx ty::List<LocalDefId> { - self.defining_opaque_types() - } - fn next_ty_infer(&self) -> Ty<'tcx> { self.next_ty_var(DUMMY_SP) } diff --git a/compiler/rustc_infer/src/infer/mod.rs b/compiler/rustc_infer/src/infer/mod.rs index be43cba97f0..fc54d69449f 100644 --- a/compiler/rustc_infer/src/infer/mod.rs +++ b/compiler/rustc_infer/src/infer/mod.rs @@ -38,11 +38,12 @@ use rustc_middle::ty::fold::{ use rustc_middle::ty::visit::TypeVisitableExt; use rustc_middle::ty::{ self, ConstVid, FloatVid, GenericArg, GenericArgKind, GenericArgs, GenericArgsRef, - GenericParamDefKind, InferConst, IntVid, Ty, TyCtxt, TyVid, + GenericParamDefKind, InferConst, IntVid, Ty, TyCtxt, TyVid, TypingMode, }; use rustc_middle::{bug, span_bug}; use rustc_span::Span; use rustc_span::symbol::Symbol; +use rustc_type_ir::solve::Reveal; use snapshot::undo_log::InferCtxtUndoLogs; use tracing::{debug, instrument}; use type_variable::TypeVariableOrigin; @@ -243,8 +244,9 @@ impl<'tcx> InferCtxtInner<'tcx> { pub struct InferCtxt<'tcx> { pub tcx: TyCtxt<'tcx>, - /// The `DefIds` of the opaque types that may have their hidden types constrained. - defining_opaque_types: &'tcx ty::List<LocalDefId>, + /// The mode of this inference context, see the struct documentation + /// for more details. + typing_mode: TypingMode<'tcx>, /// Whether this inference context should care about region obligations in /// the root universe. Most notably, this is used during hir typeck as region @@ -296,26 +298,6 @@ pub struct InferCtxt<'tcx> { /// bound. universe: Cell<ty::UniverseIndex>, - /// During coherence we have to assume that other crates may add - /// additional impls which we currently don't know about. - /// - /// To deal with this evaluation, we should be conservative - /// and consider the possibility of impls from outside this crate. - /// This comes up primarily when resolving ambiguity. Imagine - /// there is some trait reference `$0: Bar` where `$0` is an - /// inference variable. If `intercrate` is true, then we can never - /// say for sure that this reference is not implemented, even if - /// there are *no impls at all for `Bar`*, because `$0` could be - /// bound to some type that in a downstream crate that implements - /// `Bar`. - /// - /// Outside of coherence, we set this to false because we are only - /// interested in types that the user could actually have written. - /// In other words, we consider `$0: Bar` to be unimplemented if - /// there is no type that the user could *actually name* that - /// would satisfy it. This avoids crippling inference, basically. - pub intercrate: bool, - next_trait_solver: bool, pub obligation_inspector: Cell<Option<ObligationInspector<'tcx>>>, @@ -529,11 +511,8 @@ pub struct RegionObligation<'tcx> { /// Used to configure inference contexts before their creation. pub struct InferCtxtBuilder<'tcx> { tcx: TyCtxt<'tcx>, - defining_opaque_types: &'tcx ty::List<LocalDefId>, considering_regions: bool, skip_leak_check: bool, - /// Whether we are in coherence mode. - intercrate: bool, /// Whether we should use the new trait solver in the local inference context, /// which affects things like which solver is used in `predicate_may_hold`. next_trait_solver: bool, @@ -544,37 +523,19 @@ impl<'tcx> TyCtxt<'tcx> { fn infer_ctxt(self) -> InferCtxtBuilder<'tcx> { InferCtxtBuilder { tcx: self, - defining_opaque_types: ty::List::empty(), considering_regions: true, skip_leak_check: false, - intercrate: false, next_trait_solver: self.next_trait_solver_globally(), } } } impl<'tcx> InferCtxtBuilder<'tcx> { - /// Whenever the `InferCtxt` should be able to handle defining uses of opaque types, - /// you need to call this function. Otherwise the opaque type will be treated opaquely. - /// - /// It is only meant to be called in two places, for typeck - /// (via `Inherited::build`) and for the inference context used - /// in mir borrowck. - pub fn with_opaque_type_inference(mut self, defining_anchor: LocalDefId) -> Self { - self.defining_opaque_types = self.tcx.opaque_types_defined_by(defining_anchor); - self - } - pub fn with_next_trait_solver(mut self, next_trait_solver: bool) -> Self { self.next_trait_solver = next_trait_solver; self } - pub fn intercrate(mut self, intercrate: bool) -> Self { - self.intercrate = intercrate; - self - } - pub fn ignoring_regions(mut self) -> Self { self.considering_regions = false; self @@ -600,24 +561,17 @@ impl<'tcx> InferCtxtBuilder<'tcx> { where T: TypeFoldable<TyCtxt<'tcx>>, { - self.defining_opaque_types = input.defining_opaque_types; - let infcx = self.build(); + let infcx = self.build(input.typing_mode); let (value, args) = infcx.instantiate_canonical(span, &input.canonical); (infcx, value, args) } - pub fn build(&mut self) -> InferCtxt<'tcx> { - let InferCtxtBuilder { - tcx, - defining_opaque_types, - considering_regions, - skip_leak_check, - intercrate, - next_trait_solver, - } = *self; + pub fn build(&mut self, typing_mode: TypingMode<'tcx>) -> InferCtxt<'tcx> { + let InferCtxtBuilder { tcx, considering_regions, skip_leak_check, next_trait_solver } = + *self; InferCtxt { tcx, - defining_opaque_types, + typing_mode, considering_regions, skip_leak_check, inner: RefCell::new(InferCtxtInner::new()), @@ -628,7 +582,6 @@ impl<'tcx> InferCtxtBuilder<'tcx> { reported_signature_mismatch: Default::default(), tainted_by_errors: Cell::new(None), universe: Cell::new(ty::UniverseIndex::ROOT), - intercrate, next_trait_solver, obligation_inspector: Cell::new(None), } @@ -659,14 +612,30 @@ impl<'tcx> InferCtxt<'tcx> { self.tcx.dcx().taintable_handle(&self.tainted_by_errors) } - pub fn defining_opaque_types(&self) -> &'tcx ty::List<LocalDefId> { - self.defining_opaque_types - } - pub fn next_trait_solver(&self) -> bool { self.next_trait_solver } + #[inline(always)] + pub fn typing_mode( + &self, + param_env_for_debug_assertion: ty::ParamEnv<'tcx>, + ) -> TypingMode<'tcx> { + if cfg!(debug_assertions) { + match (param_env_for_debug_assertion.reveal(), self.typing_mode) { + (Reveal::All, TypingMode::PostAnalysis) + | (Reveal::UserFacing, TypingMode::Coherence | TypingMode::Analysis { .. }) => {} + (r, t) => unreachable!("TypingMode x Reveal mismatch: {r:?} {t:?}"), + } + } + self.typing_mode + } + + #[inline(always)] + pub fn typing_mode_unchecked(&self) -> TypingMode<'tcx> { + self.typing_mode + } + pub fn freshen<T: TypeFoldable<TyCtxt<'tcx>>>(&self, t: T) -> T { t.fold_with(&mut self.freshener()) } @@ -1029,8 +998,12 @@ impl<'tcx> InferCtxt<'tcx> { #[inline(always)] pub fn can_define_opaque_ty(&self, id: impl Into<DefId>) -> bool { - let Some(id) = id.into().as_local() else { return false }; - self.defining_opaque_types.contains(&id) + match self.typing_mode_unchecked() { + TypingMode::Analysis { defining_opaque_types } => { + id.into().as_local().is_some_and(|def_id| defining_opaque_types.contains(&def_id)) + } + TypingMode::Coherence | TypingMode::PostAnalysis => false, + } } pub fn ty_to_string(&self, t: Ty<'tcx>) -> String { diff --git a/compiler/rustc_infer/src/infer/opaque_types/mod.rs b/compiler/rustc_infer/src/infer/opaque_types/mod.rs index 853ae6d2641..498d25aea64 100644 --- a/compiler/rustc_infer/src/infer/opaque_types/mod.rs +++ b/compiler/rustc_infer/src/infer/opaque_types/mod.rs @@ -2,6 +2,7 @@ use hir::def_id::{DefId, LocalDefId}; use rustc_data_structures::fx::FxIndexMap; use rustc_data_structures::sync::Lrc; use rustc_hir as hir; +use rustc_middle::bug; use rustc_middle::traits::ObligationCause; use rustc_middle::traits::solve::Goal; use rustc_middle::ty::error::{ExpectedFound, TypeError}; @@ -100,7 +101,7 @@ impl<'tcx> InferCtxt<'tcx> { let process = |a: Ty<'tcx>, b: Ty<'tcx>| match *a.kind() { ty::Alias(ty::Opaque, ty::AliasTy { def_id, args, .. }) if def_id.is_local() => { let def_id = def_id.expect_local(); - if self.intercrate { + if let ty::TypingMode::Coherence = self.typing_mode(param_env) { // See comment on `insert_hidden_type` for why this is sufficient in coherence return Some(self.register_hidden_type( OpaqueTypeKey { def_id, args }, @@ -364,7 +365,7 @@ impl<'tcx> InferCtxt<'tcx> { span, concrete_ty, r, - choice_regions.clone(), + Lrc::clone(&choice_regions), ) }, }); @@ -519,28 +520,32 @@ impl<'tcx> InferCtxt<'tcx> { // value being folded. In simple cases like `-> impl Foo`, // these are the same span, but not in cases like `-> (impl // Foo, impl Bar)`. - if self.intercrate { - // During intercrate we do not define opaque types but instead always - // force ambiguity unless the hidden type is known to not implement - // our trait. - goals.push(Goal::new(self.tcx, param_env, ty::PredicateKind::Ambiguous)) - } else { - let prev = self - .inner - .borrow_mut() - .opaque_types() - .register(opaque_type_key, OpaqueHiddenType { ty: hidden_ty, span }); - if let Some(prev) = prev { - goals.extend( - self.at(&ObligationCause::dummy_with_span(span), param_env) - .eq(DefineOpaqueTypes::Yes, prev, hidden_ty)? - .obligations - .into_iter() - // FIXME: Shuttling between obligations and goals is awkward. - .map(Goal::from), - ); + match self.typing_mode(param_env) { + ty::TypingMode::Coherence => { + // During intercrate we do not define opaque types but instead always + // force ambiguity unless the hidden type is known to not implement + // our trait. + goals.push(Goal::new(self.tcx, param_env, ty::PredicateKind::Ambiguous)); } - }; + ty::TypingMode::Analysis { .. } => { + let prev = self + .inner + .borrow_mut() + .opaque_types() + .register(opaque_type_key, OpaqueHiddenType { ty: hidden_ty, span }); + if let Some(prev) = prev { + goals.extend( + self.at(&ObligationCause::dummy_with_span(span), param_env) + .eq(DefineOpaqueTypes::Yes, prev, hidden_ty)? + .obligations + .into_iter() + // FIXME: Shuttling between obligations and goals is awkward. + .map(Goal::from), + ); + } + } + ty::TypingMode::PostAnalysis => bug!("insert hidden type post-analysis"), + } Ok(()) } diff --git a/compiler/rustc_infer/src/infer/relate/generalize.rs b/compiler/rustc_infer/src/infer/relate/generalize.rs index 32817dbcb21..4c80bf4e07e 100644 --- a/compiler/rustc_infer/src/infer/relate/generalize.rs +++ b/compiler/rustc_infer/src/infer/relate/generalize.rs @@ -9,6 +9,7 @@ use rustc_middle::ty::error::TypeError; use rustc_middle::ty::visit::MaxUniverse; use rustc_middle::ty::{ self, AliasRelationDirection, InferConst, Term, Ty, TyCtxt, TypeVisitable, TypeVisitableExt, + TypingMode, }; use rustc_span::Span; use tracing::{debug, instrument, warn}; @@ -519,7 +520,10 @@ impl<'tcx> TypeRelation<TyCtxt<'tcx>> for Generalizer<'_, 'tcx> { // // cc trait-system-refactor-initiative#108 if self.infcx.next_trait_solver() - && !self.infcx.intercrate + && !matches!( + self.infcx.typing_mode_unchecked(), + TypingMode::Coherence + ) && self.in_alias { inner.type_variables().equate(vid, new_var_id); @@ -650,7 +654,10 @@ impl<'tcx> TypeRelation<TyCtxt<'tcx>> for Generalizer<'_, 'tcx> { // See the comment for type inference variables // for more details. if self.infcx.next_trait_solver() - && !self.infcx.intercrate + && !matches!( + self.infcx.typing_mode_unchecked(), + TypingMode::Coherence + ) && self.in_alias { variable_table.union(vid, new_var_id); diff --git a/compiler/rustc_interface/src/queries.rs b/compiler/rustc_interface/src/queries.rs index 3a1833452d4..b6837ec764f 100644 --- a/compiler/rustc_interface/src/queries.rs +++ b/compiler/rustc_interface/src/queries.rs @@ -142,7 +142,7 @@ impl Linker { Ok(Linker { dep_graph: tcx.dep_graph.clone(), - output_filenames: tcx.output_filenames(()).clone(), + output_filenames: Arc::clone(tcx.output_filenames(())), crate_hash: if tcx.needs_crate_hash() { Some(tcx.crate_hash(LOCAL_CRATE)) } else { diff --git a/compiler/rustc_lint/Cargo.toml b/compiler/rustc_lint/Cargo.toml index 232d4c18fa4..dd7b40d0a32 100644 --- a/compiler/rustc_lint/Cargo.toml +++ b/compiler/rustc_lint/Cargo.toml @@ -5,6 +5,7 @@ edition = "2021" [dependencies] # tidy-alphabetical-start +rustc_abi = { path = "../rustc_abi" } rustc_ast = { path = "../rustc_ast" } rustc_ast_pretty = { path = "../rustc_ast_pretty" } rustc_attr = { path = "../rustc_attr" } diff --git a/compiler/rustc_lint/messages.ftl b/compiler/rustc_lint/messages.ftl index c4d709aa1f9..3fa43296dfc 100644 --- a/compiler/rustc_lint/messages.ftl +++ b/compiler/rustc_lint/messages.ftl @@ -203,14 +203,14 @@ lint_confusable_identifier_pair = found both `{$existing_sym}` and `{$sym}` as i .current_use = this identifier can be confused with `{$existing_sym}` .other_use = other identifier used here -lint_cstring_ptr = getting the inner pointer of a temporary `CString` - .as_ptr_label = this pointer will be invalid - .unwrap_label = this `CString` is deallocated at the end of the statement, bind it to a variable to extend its lifetime - .note = pointers do not have a lifetime; when calling `as_ptr` the `CString` will be deallocated at the end of the statement because nothing is referencing it as far as the type system is concerned - .help = for more information, see https://doc.rust-lang.org/reference/destructors.html - lint_custom_inner_attribute_unstable = custom inner attributes are unstable +lint_dangling_pointers_from_temporaries = a dangling pointer will be produced because the temporary `{$ty}` will be dropped + .label_ptr = this pointer will immediately be invalid + .label_temporary = this `{$ty}` is deallocated at the end of the statement, bind it to a variable to extend its lifetime + .note = pointers do not have a lifetime; when calling `{$callee}` the `{$ty}` will be deallocated at the end of the statement because nothing is referencing it as far as the type system is concerned + .help = for more information, see <https://doc.rust-lang.org/reference/destructors.html> + lint_default_hash_types = prefer `{$preferred}` over `{$used}`, it has better performance .note = a `use rustc_data_structures::fx::{$preferred}` may be necessary diff --git a/compiler/rustc_lint/src/builtin.rs b/compiler/rustc_lint/src/builtin.rs index 3ee4980a948..77682ea9341 100644 --- a/compiler/rustc_lint/src/builtin.rs +++ b/compiler/rustc_lint/src/builtin.rs @@ -4,21 +4,14 @@ //! AST visitor. Also see `rustc_session::lint::builtin`, which contains the //! definitions of lints that are emitted directly inside the main compiler. //! -//! To add a new lint to rustc, declare it here using `declare_lint!()`. +//! To add a new lint to rustc, declare it here using [`declare_lint!`]. //! Then add code to emit the new lint in the appropriate circumstances. -//! You can do that in an existing `LintPass` if it makes sense, or in a -//! new `LintPass`, or using `Session::add_lint` elsewhere in the -//! compiler. Only do the latter if the check can't be written cleanly as a -//! `LintPass` (also, note that such lints will need to be defined in -//! `rustc_session::lint::builtin`, not here). //! -//! If you define a new `EarlyLintPass`, you will also need to add it to the -//! `add_early_builtin!` or `add_early_builtin_with_new!` invocation in -//! `lib.rs`. Use the former for unit-like structs and the latter for structs -//! with a `pub fn new()`. +//! If you define a new [`EarlyLintPass`], you will also need to add it to the +//! [`crate::early_lint_methods!`] invocation in `lib.rs`. //! -//! If you define a new `LateLintPass`, you will also need to add it to the -//! `late_lint_methods!` invocation in `lib.rs`. +//! If you define a new [`LateLintPass`], you will also need to add it to the +//! [`crate::late_lint_methods!`] invocation in `lib.rs`. use std::fmt::Write; @@ -38,7 +31,7 @@ use rustc_middle::bug; use rustc_middle::lint::in_external_macro; use rustc_middle::ty::layout::LayoutOf; use rustc_middle::ty::print::with_no_trimmed_paths; -use rustc_middle::ty::{self, Ty, TyCtxt, TypeVisitableExt, Upcast, VariantDef}; +use rustc_middle::ty::{self, Ty, TyCtxt, TypeVisitableExt, TypingMode, Upcast, VariantDef}; use rustc_session::lint::FutureIncompatibilityReason; // hardwired lints from rustc_lint_defs pub use rustc_session::lint::builtin::*; @@ -611,7 +604,7 @@ impl<'tcx> LateLintPass<'tcx> for MissingCopyImplementations { && cx .tcx .infer_ctxt() - .build() + .build(cx.typing_mode()) .type_implements_trait(iter_trait, [ty], cx.param_env) .must_apply_modulo_regions() { @@ -655,7 +648,9 @@ fn type_implements_negative_copy_modulo_regions<'tcx>( predicate: pred.upcast(tcx), }; - tcx.infer_ctxt().build().predicate_must_hold_modulo_regions(&obligation) + tcx.infer_ctxt() + .build(TypingMode::non_body_analysis()) + .predicate_must_hold_modulo_regions(&obligation) } declare_lint! { diff --git a/compiler/rustc_lint/src/context.rs b/compiler/rustc_lint/src/context.rs index 39f90a8e9ed..aa7ec2659d0 100644 --- a/compiler/rustc_lint/src/context.rs +++ b/compiler/rustc_lint/src/context.rs @@ -1,18 +1,7 @@ -//! Implementation of lint checking. +//! Basic types for managing and implementing lints. //! -//! The lint checking is mostly consolidated into one pass which runs -//! after all other analyses. Throughout compilation, lint warnings -//! can be added via the `add_lint` method on the Session structure. This -//! requires a span and an ID of the node that the lint is being added to. The -//! lint isn't actually emitted at that time because it is unknown what the -//! actual lint level at that location is. -//! -//! To actually emit lint warnings/errors, a separate pass is used. -//! A context keeps track of the current state of all lint levels. -//! Upon entering a node of the ast which can modify the lint settings, the -//! previous lint state is pushed onto a stack and the ast is then recursed -//! upon. As the ast is traversed, this keeps track of the current lint level -//! for all lint attributes. +//! See <https://rustc-dev-guide.rust-lang.org/diagnostics.html> for an +//! overview of how lints are implemented. use std::cell::Cell; use std::{iter, slice}; @@ -22,15 +11,15 @@ use rustc_data_structures::sync; use rustc_data_structures::unord::UnordMap; use rustc_errors::{Diag, LintDiagnostic, MultiSpan}; use rustc_feature::Features; -use rustc_hir as hir; use rustc_hir::def::Res; use rustc_hir::def_id::{CrateNum, DefId}; use rustc_hir::definitions::{DefPathData, DisambiguatedDefPathData}; +use rustc_infer::traits::Reveal; use rustc_middle::bug; use rustc_middle::middle::privacy::EffectiveVisibilities; use rustc_middle::ty::layout::{LayoutError, LayoutOfHelpers, TyAndLayout}; use rustc_middle::ty::print::{PrintError, PrintTraitRefExt as _, Printer, with_no_trimmed_paths}; -use rustc_middle::ty::{self, GenericArg, RegisteredTools, Ty, TyCtxt}; +use rustc_middle::ty::{self, GenericArg, RegisteredTools, Ty, TyCtxt, TypingMode}; use rustc_session::lint::{ BuiltinLintDiag, FutureIncompatibleInfo, Level, Lint, LintBuffer, LintExpectationId, LintId, }; @@ -38,8 +27,8 @@ use rustc_session::{LintStoreMarker, Session}; use rustc_span::Span; use rustc_span::edit_distance::find_best_match_for_names; use rustc_span::symbol::{Ident, Symbol, sym}; -use rustc_target::abi; use tracing::debug; +use {rustc_abi as abi, rustc_hir as hir}; use self::TargetLint::*; use crate::levels::LintLevelsBuilder; @@ -52,9 +41,6 @@ type LateLintPassFactory = dyn for<'tcx> Fn(TyCtxt<'tcx>) -> LateLintPassObject<'tcx> + sync::DynSend + sync::DynSync; /// Information about the registered lints. -/// -/// This is basically the subset of `Context` that we can -/// build early in the compile pipeline. pub struct LintStore { /// Registered lints. lints: Vec<&'static Lint>, @@ -713,6 +699,15 @@ impl LintContext for EarlyContext<'_> { } impl<'tcx> LateContext<'tcx> { + /// The typing mode of the currently visited node. Use this when + /// building a new `InferCtxt`. + pub fn typing_mode(&self) -> TypingMode<'tcx> { + debug_assert_eq!(self.param_env.reveal(), Reveal::UserFacing); + // FIXME(#132279): In case we're in a body, we should use a typing + // mode which reveals the opaque types defined by that body. + TypingMode::non_body_analysis() + } + /// Gets the type-checking results for the current body, /// or `None` if outside a body. pub fn maybe_typeck_results(&self) -> Option<&'tcx ty::TypeckResults<'tcx>> { diff --git a/compiler/rustc_lint/src/dangling.rs b/compiler/rustc_lint/src/dangling.rs new file mode 100644 index 00000000000..a34c3e26778 --- /dev/null +++ b/compiler/rustc_lint/src/dangling.rs @@ -0,0 +1,223 @@ +use rustc_ast::visit::{visit_opt, walk_list}; +use rustc_hir::def_id::LocalDefId; +use rustc_hir::intravisit::{FnKind, Visitor, walk_expr}; +use rustc_hir::{Block, Body, Expr, ExprKind, FnDecl, LangItem}; +use rustc_middle::ty::{Ty, TyCtxt}; +use rustc_session::{declare_lint, impl_lint_pass}; +use rustc_span::Span; +use rustc_span::symbol::sym; + +use crate::lints::DanglingPointersFromTemporaries; +use crate::{LateContext, LateLintPass}; + +declare_lint! { + /// The `dangling_pointers_from_temporaries` lint detects getting a pointer to data + /// of a temporary that will immediately get dropped. + /// + /// ### Example + /// + /// ```rust + /// # #![allow(unused)] + /// # unsafe fn use_data(ptr: *const u8) { } + /// fn gather_and_use(bytes: impl Iterator<Item = u8>) { + /// let x: *const u8 = bytes.collect::<Vec<u8>>().as_ptr(); + /// unsafe { use_data(x) } + /// } + /// ``` + /// + /// {{produces}} + /// + /// ### Explanation + /// + /// Getting a pointer from a temporary value will not prolong its lifetime, + /// which means that the value can be dropped and the allocation freed + /// while the pointer still exists, making the pointer dangling. + /// This is not an error (as far as the type system is concerned) + /// but probably is not what the user intended either. + /// + /// If you need stronger guarantees, consider using references instead, + /// as they are statically verified by the borrow-checker to never dangle. + pub DANGLING_POINTERS_FROM_TEMPORARIES, + Warn, + "detects getting a pointer from a temporary" +} + +/// FIXME: false negatives (i.e. the lint is not emitted when it should be) +/// 1. Method calls that are not checked for: +/// - [`temporary_unsafe_cell.get()`][`core::cell::UnsafeCell::get()`] +/// - [`temporary_sync_unsafe_cell.get()`][`core::cell::SyncUnsafeCell::get()`] +/// 2. Ways to get a temporary that are not recognized: +/// - `owning_temporary.field` +/// - `owning_temporary[index]` +/// 3. No checks for ref-to-ptr conversions: +/// - `&raw [mut] temporary` +/// - `&temporary as *(const|mut) _` +/// - `ptr::from_ref(&temporary)` and friends +#[derive(Clone, Copy, Default)] +pub(crate) struct DanglingPointers; + +impl_lint_pass!(DanglingPointers => [DANGLING_POINTERS_FROM_TEMPORARIES]); + +// This skips over const blocks, but they cannot use or return a dangling pointer anyways. +impl<'tcx> LateLintPass<'tcx> for DanglingPointers { + fn check_fn( + &mut self, + cx: &LateContext<'tcx>, + _: FnKind<'tcx>, + _: &'tcx FnDecl<'tcx>, + body: &'tcx Body<'tcx>, + _: Span, + _: LocalDefId, + ) { + DanglingPointerSearcher { cx, inside_call_args: false }.visit_body(body) + } +} + +/// This produces a dangling pointer: +/// ```ignore (example) +/// let ptr = CString::new("hello").unwrap().as_ptr(); +/// foo(ptr) +/// ``` +/// +/// But this does not: +/// ```ignore (example) +/// foo(CString::new("hello").unwrap().as_ptr()) +/// ``` +/// +/// But this does: +/// ```ignore (example) +/// foo({ let ptr = CString::new("hello").unwrap().as_ptr(); ptr }) +/// ``` +/// +/// So we have to keep track of when we are inside of a function/method call argument. +struct DanglingPointerSearcher<'lcx, 'tcx> { + cx: &'lcx LateContext<'tcx>, + /// Keeps track of whether we are inside of function/method call arguments, + /// where this lint should not be emitted. + /// + /// See [the main doc][`Self`] for examples. + inside_call_args: bool, +} + +impl Visitor<'_> for DanglingPointerSearcher<'_, '_> { + fn visit_expr(&mut self, expr: &Expr<'_>) -> Self::Result { + if !self.inside_call_args { + lint_expr(self.cx, expr) + } + match expr.kind { + ExprKind::Call(lhs, args) | ExprKind::MethodCall(_, lhs, args, _) => { + self.visit_expr(lhs); + self.with_inside_call_args(true, |this| walk_list!(this, visit_expr, args)) + } + ExprKind::Block(&Block { stmts, expr, .. }, _) => { + self.with_inside_call_args(false, |this| walk_list!(this, visit_stmt, stmts)); + visit_opt!(self, visit_expr, expr) + } + _ => walk_expr(self, expr), + } + } +} + +impl DanglingPointerSearcher<'_, '_> { + fn with_inside_call_args<R>( + &mut self, + inside_call_args: bool, + callback: impl FnOnce(&mut Self) -> R, + ) -> R { + let old = core::mem::replace(&mut self.inside_call_args, inside_call_args); + let result = callback(self); + self.inside_call_args = old; + result + } +} + +fn lint_expr(cx: &LateContext<'_>, expr: &Expr<'_>) { + if let ExprKind::MethodCall(method, receiver, _args, _span) = expr.kind + && matches!(method.ident.name, sym::as_ptr | sym::as_mut_ptr) + && is_temporary_rvalue(receiver) + && let ty = cx.typeck_results().expr_ty(receiver) + && is_interesting(cx.tcx, ty) + { + // FIXME: use `emit_node_lint` when `#[primary_span]` is added. + cx.tcx.emit_node_span_lint( + DANGLING_POINTERS_FROM_TEMPORARIES, + expr.hir_id, + method.ident.span, + DanglingPointersFromTemporaries { + callee: method.ident.name, + ty, + ptr_span: method.ident.span, + temporary_span: receiver.span, + }, + ) + } +} + +fn is_temporary_rvalue(expr: &Expr<'_>) -> bool { + match expr.kind { + // Const is not temporary. + ExprKind::ConstBlock(..) | ExprKind::Repeat(..) | ExprKind::Lit(..) => false, + + // This is literally lvalue. + ExprKind::Path(..) => false, + + // Calls return rvalues. + ExprKind::Call(..) | ExprKind::MethodCall(..) | ExprKind::Binary(..) => true, + + // Inner blocks are rvalues. + ExprKind::If(..) | ExprKind::Loop(..) | ExprKind::Match(..) | ExprKind::Block(..) => true, + + // FIXME: these should probably recurse and typecheck along the way. + // Some false negatives are possible for now. + ExprKind::Index(..) | ExprKind::Field(..) | ExprKind::Unary(..) => false, + + ExprKind::Struct(..) => true, + + // FIXME: this has false negatives, but I do not want to deal with 'static/const promotion just yet. + ExprKind::Array(..) => false, + + // These typecheck to `!` + ExprKind::Break(..) | ExprKind::Continue(..) | ExprKind::Ret(..) | ExprKind::Become(..) => { + false + } + + // These typecheck to `()` + ExprKind::Assign(..) | ExprKind::AssignOp(..) | ExprKind::Yield(..) => false, + + // Compiler-magic macros + ExprKind::AddrOf(..) | ExprKind::OffsetOf(..) | ExprKind::InlineAsm(..) => false, + + // We are not interested in these + ExprKind::Cast(..) + | ExprKind::Closure(..) + | ExprKind::Tup(..) + | ExprKind::DropTemps(..) + | ExprKind::Let(..) => false, + + // Not applicable + ExprKind::Type(..) | ExprKind::Err(..) => false, + } +} + +// Array, Vec, String, CString, MaybeUninit, Cell, Box<[_]>, Box<str>, Box<CStr>, +// or any of the above in arbitrary many nested Box'es. +fn is_interesting(tcx: TyCtxt<'_>, ty: Ty<'_>) -> bool { + if ty.is_array() { + true + } else if let Some(inner) = ty.boxed_ty() { + inner.is_slice() + || inner.is_str() + || inner.ty_adt_def().is_some_and(|def| tcx.is_lang_item(def.did(), LangItem::CStr)) + || is_interesting(tcx, inner) + } else if let Some(def) = ty.ty_adt_def() { + for lang_item in [LangItem::String, LangItem::MaybeUninit] { + if tcx.is_lang_item(def.did(), lang_item) { + return true; + } + } + tcx.get_diagnostic_name(def.did()) + .is_some_and(|name| matches!(name, sym::cstring_type | sym::Vec | sym::Cell)) + } else { + false + } +} diff --git a/compiler/rustc_lint/src/early.rs b/compiler/rustc_lint/src/early.rs index e2247d3a1f6..acccff77a10 100644 --- a/compiler/rustc_lint/src/early.rs +++ b/compiler/rustc_lint/src/early.rs @@ -1,18 +1,8 @@ -//! Implementation of lint checking. +//! Implementation of the early lint pass. //! -//! The lint checking is mostly consolidated into one pass which runs -//! after all other analyses. Throughout compilation, lint warnings -//! can be added via the `add_lint` method on the Session structure. This -//! requires a span and an ID of the node that the lint is being added to. The -//! lint isn't actually emitted at that time because it is unknown what the -//! actual lint level at that location is. -//! -//! To actually emit lint warnings/errors, a separate pass is used. -//! A context keeps track of the current state of all lint levels. -//! Upon entering a node of the ast which can modify the lint settings, the -//! previous lint state is pushed onto a stack and the ast is then recursed -//! upon. As the ast is traversed, this keeps track of the current lint level -//! for all lint attributes. +//! The early lint pass works on AST nodes after macro expansion and name +//! resolution, just before AST lowering. These lints are for purely +//! syntactical lints. use rustc_ast::ptr::P; use rustc_ast::visit::{self as ast_visit, Visitor, walk_list}; diff --git a/compiler/rustc_lint/src/for_loops_over_fallibles.rs b/compiler/rustc_lint/src/for_loops_over_fallibles.rs index fcb7a6108c0..cf68e41243f 100644 --- a/compiler/rustc_lint/src/for_loops_over_fallibles.rs +++ b/compiler/rustc_lint/src/for_loops_over_fallibles.rs @@ -166,7 +166,7 @@ fn suggest_question_mark<'tcx>( } let ty = args.type_at(0); - let infcx = cx.tcx.infer_ctxt().build(); + let infcx = cx.tcx.infer_ctxt().build(cx.typing_mode()); let ocx = ObligationCtxt::new(&infcx); let body_def_id = cx.tcx.hir().body_owner_def_id(body_id); diff --git a/compiler/rustc_lint/src/foreign_modules.rs b/compiler/rustc_lint/src/foreign_modules.rs index 816882962be..abe4e3e78ee 100644 --- a/compiler/rustc_lint/src/foreign_modules.rs +++ b/compiler/rustc_lint/src/foreign_modules.rs @@ -1,3 +1,4 @@ +use rustc_abi::FIRST_VARIANT; use rustc_data_structures::stack::ensure_sufficient_stack; use rustc_data_structures::unord::{UnordMap, UnordSet}; use rustc_hir as hir; @@ -6,7 +7,6 @@ use rustc_middle::query::Providers; use rustc_middle::ty::{self, AdtDef, Instance, Ty, TyCtxt}; use rustc_session::declare_lint; use rustc_span::{Span, Symbol, sym}; -use rustc_target::abi::FIRST_VARIANT; use tracing::{debug, instrument}; use crate::lints::{BuiltinClashingExtern, BuiltinClashingExternSub}; diff --git a/compiler/rustc_lint/src/if_let_rescope.rs b/compiler/rustc_lint/src/if_let_rescope.rs index bdfcc2c0a10..afcfbebc14b 100644 --- a/compiler/rustc_lint/src/if_let_rescope.rs +++ b/compiler/rustc_lint/src/if_let_rescope.rs @@ -24,7 +24,6 @@ declare_lint! { /// ### Example /// /// ```rust,edition2021 - /// #![feature(if_let_rescope)] /// #![warn(if_let_rescope)] /// #![allow(unused_variables)] /// @@ -243,7 +242,7 @@ impl_lint_pass!( impl<'tcx> LateLintPass<'tcx> for IfLetRescope { fn check_expr(&mut self, cx: &LateContext<'tcx>, expr: &'tcx hir::Expr<'tcx>) { - if expr.span.edition().at_least_rust_2024() || !cx.tcx.features().if_let_rescope() { + if expr.span.edition().at_least_rust_2024() { return; } if let (Level::Allow, _) = cx.tcx.lint_level_at_node(IF_LET_RESCOPE, expr.hir_id) { diff --git a/compiler/rustc_lint/src/impl_trait_overcaptures.rs b/compiler/rustc_lint/src/impl_trait_overcaptures.rs index cc40b67ab27..026826021c8 100644 --- a/compiler/rustc_lint/src/impl_trait_overcaptures.rs +++ b/compiler/rustc_lint/src/impl_trait_overcaptures.rs @@ -15,7 +15,7 @@ use rustc_middle::ty::relate::{ Relate, RelateResult, TypeRelation, structurally_relate_consts, structurally_relate_tys, }; use rustc_middle::ty::{ - self, Ty, TyCtxt, TypeSuperVisitable, TypeVisitable, TypeVisitableExt, TypeVisitor, + self, Ty, TyCtxt, TypeSuperVisitable, TypeVisitable, TypeVisitableExt, TypeVisitor, TypingMode, }; use rustc_middle::{bug, span_bug}; use rustc_session::lint::FutureIncompatibilityReason; @@ -184,7 +184,7 @@ fn check_fn(tcx: TyCtxt<'_>, parent_def_id: LocalDefId) { }), outlives_env: LazyCell::new(|| { let param_env = tcx.param_env(parent_def_id); - let infcx = tcx.infer_ctxt().build(); + let infcx = tcx.infer_ctxt().build(TypingMode::from_param_env(param_env)); let ocx = ObligationCtxt::new(&infcx); let assumed_wf_tys = ocx.assumed_wf_types(param_env, parent_def_id).unwrap_or_default(); let implied_bounds = diff --git a/compiler/rustc_lint/src/late.rs b/compiler/rustc_lint/src/late.rs index 9b1877599ba..9d35ce19b57 100644 --- a/compiler/rustc_lint/src/late.rs +++ b/compiler/rustc_lint/src/late.rs @@ -1,18 +1,7 @@ -//! Implementation of lint checking. +//! Implementation of the late lint pass. //! -//! The lint checking is mostly consolidated into one pass which runs -//! after all other analyses. Throughout compilation, lint warnings -//! can be added via the `add_lint` method on the Session structure. This -//! requires a span and an ID of the node that the lint is being added to. The -//! lint isn't actually emitted at that time because it is unknown what the -//! actual lint level at that location is. -//! -//! To actually emit lint warnings/errors, a separate pass is used. -//! A context keeps track of the current state of all lint levels. -//! Upon entering a node of the ast which can modify the lint settings, the -//! previous lint state is pushed onto a stack and the ast is then recursed -//! upon. As the ast is traversed, this keeps track of the current lint level -//! for all lint attributes. +//! The late lint pass Works on HIR nodes, towards the end of analysis (after +//! borrow checking, etc.). These lints have full type information available. use std::any::Any; use std::cell::Cell; diff --git a/compiler/rustc_lint/src/lib.rs b/compiler/rustc_lint/src/lib.rs index 5389860e23b..86112277504 100644 --- a/compiler/rustc_lint/src/lib.rs +++ b/compiler/rustc_lint/src/lib.rs @@ -6,20 +6,14 @@ //! other phases of the compiler, which are generally required to hold in order //! to compile the program at all. //! -//! Most lints can be written as [LintPass] instances. These run after +//! Most lints can be written as [`LintPass`] instances. These run after //! all other analyses. The `LintPass`es built into rustc are defined //! within [rustc_session::lint::builtin], //! which has further comments on how to add such a lint. //! rustc can also load external lint plugins, as is done for Clippy. //! -//! Some of rustc's lints are defined elsewhere in the compiler and work by -//! calling `add_lint()` on the overall `Session` object. This works when -//! it happens before the main lint pass, which emits the lints stored by -//! `add_lint()`. To emit lints after the main lint pass (from codegen, for -//! example) requires more effort. See `emit_lint` and `GatherNodeLevels` -//! in `context.rs`. -//! -//! Some code also exists in [rustc_session::lint], [rustc_middle::lint]. +//! See <https://rustc-dev-guide.rust-lang.org/diagnostics.html> for an +//! overview of how lints are implemented. //! //! ## Note //! @@ -46,6 +40,7 @@ mod async_closures; mod async_fn_in_trait; pub mod builtin; mod context; +mod dangling; mod deref_into_dyn_supertrait; mod drop_forget_useless; mod early; @@ -65,7 +60,6 @@ mod levels; mod lints; mod macro_expr_fragment_specifier_2024_migration; mod map_unit_fn; -mod methods; mod multiple_supertrait_upcastable; mod non_ascii_idents; mod non_fmt_panic; @@ -91,6 +85,7 @@ mod unused; use async_closures::AsyncClosureUsage; use async_fn_in_trait::AsyncFnInTrait; use builtin::*; +use dangling::*; use deref_into_dyn_supertrait::*; use drop_forget_useless::*; use enum_intrinsics_non_enums::EnumIntrinsicsNonEnums; @@ -103,7 +98,6 @@ use invalid_from_utf8::*; use let_underscore::*; use macro_expr_fragment_specifier_2024_migration::*; use map_unit_fn::*; -use methods::*; use multiple_supertrait_upcastable::*; use non_ascii_idents::*; use non_fmt_panic::NonPanicFmt; @@ -231,7 +225,7 @@ late_lint_methods!( UngatedAsyncFnTrackCaller: UngatedAsyncFnTrackCaller, ShadowedIntoIter: ShadowedIntoIter, DropTraitConstraints: DropTraitConstraints, - TemporaryCStringAsPtr: TemporaryCStringAsPtr, + DanglingPointers: DanglingPointers, NonPanicFmt: NonPanicFmt, NoopMethodCall: NoopMethodCall, EnumIntrinsicsNonEnums: EnumIntrinsicsNonEnums, @@ -356,6 +350,7 @@ fn register_builtins(store: &mut LintStore) { store.register_renamed("non_fmt_panic", "non_fmt_panics"); store.register_renamed("unused_tuple_struct_fields", "dead_code"); store.register_renamed("static_mut_ref", "static_mut_refs"); + store.register_renamed("temporary_cstring_as_ptr", "dangling_pointers_from_temporaries"); // These were moved to tool lints, but rustc still sees them when compiling normally, before // tool lints are registered, so `check_tool_name_for_backwards_compat` doesn't work. Use diff --git a/compiler/rustc_lint/src/lints.rs b/compiler/rustc_lint/src/lints.rs index 16cfae17d40..000f4b697bd 100644 --- a/compiler/rustc_lint/src/lints.rs +++ b/compiler/rustc_lint/src/lints.rs @@ -1137,16 +1137,19 @@ pub(crate) struct IgnoredUnlessCrateSpecified<'a> { pub name: Symbol, } -// methods.rs +// dangling.rs #[derive(LintDiagnostic)] -#[diag(lint_cstring_ptr)] +#[diag(lint_dangling_pointers_from_temporaries)] #[note] #[help] -pub(crate) struct CStringPtr { - #[label(lint_as_ptr_label)] - pub as_ptr: Span, - #[label(lint_unwrap_label)] - pub unwrap: Span, +// FIXME: put #[primary_span] on `ptr_span` once it does not cause conflicts +pub(crate) struct DanglingPointersFromTemporaries<'tcx> { + pub callee: Symbol, + pub ty: Ty<'tcx>, + #[label(lint_label_ptr)] + pub ptr_span: Span, + #[label(lint_label_temporary)] + pub temporary_span: Span, } // multiple_supertrait_upcastable.rs diff --git a/compiler/rustc_lint/src/methods.rs b/compiler/rustc_lint/src/methods.rs deleted file mode 100644 index df22bf0972d..00000000000 --- a/compiler/rustc_lint/src/methods.rs +++ /dev/null @@ -1,69 +0,0 @@ -use rustc_hir::{Expr, ExprKind}; -use rustc_middle::ty; -use rustc_session::{declare_lint, declare_lint_pass}; -use rustc_span::Span; -use rustc_span::symbol::sym; - -use crate::lints::CStringPtr; -use crate::{LateContext, LateLintPass, LintContext}; - -declare_lint! { - /// The `temporary_cstring_as_ptr` lint detects getting the inner pointer of - /// a temporary `CString`. - /// - /// ### Example - /// - /// ```rust - /// # #![allow(unused)] - /// # use std::ffi::CString; - /// let c_str = CString::new("foo").unwrap().as_ptr(); - /// ``` - /// - /// {{produces}} - /// - /// ### Explanation - /// - /// The inner pointer of a `CString` lives only as long as the `CString` it - /// points to. Getting the inner pointer of a *temporary* `CString` allows the `CString` - /// to be dropped at the end of the statement, as it is not being referenced as far as the - /// typesystem is concerned. This means outside of the statement the pointer will point to - /// freed memory, which causes undefined behavior if the pointer is later dereferenced. - pub TEMPORARY_CSTRING_AS_PTR, - Warn, - "detects getting the inner pointer of a temporary `CString`" -} - -declare_lint_pass!(TemporaryCStringAsPtr => [TEMPORARY_CSTRING_AS_PTR]); - -impl<'tcx> LateLintPass<'tcx> for TemporaryCStringAsPtr { - fn check_expr(&mut self, cx: &LateContext<'tcx>, expr: &'tcx Expr<'_>) { - if let ExprKind::MethodCall(as_ptr_path, as_ptr_receiver, ..) = expr.kind - && as_ptr_path.ident.name == sym::as_ptr - && let ExprKind::MethodCall(unwrap_path, unwrap_receiver, ..) = as_ptr_receiver.kind - && (unwrap_path.ident.name == sym::unwrap || unwrap_path.ident.name == sym::expect) - { - lint_cstring_as_ptr(cx, as_ptr_path.ident.span, unwrap_receiver, as_ptr_receiver); - } - } -} - -fn lint_cstring_as_ptr( - cx: &LateContext<'_>, - as_ptr_span: Span, - source: &rustc_hir::Expr<'_>, - unwrap: &rustc_hir::Expr<'_>, -) { - let source_type = cx.typeck_results().expr_ty(source); - if let ty::Adt(def, args) = source_type.kind() { - if cx.tcx.is_diagnostic_item(sym::Result, def.did()) { - if let ty::Adt(adt, _) = args.type_at(0).kind() { - if cx.tcx.is_diagnostic_item(sym::cstring_type, adt.did()) { - cx.emit_span_lint(TEMPORARY_CSTRING_AS_PTR, as_ptr_span, CStringPtr { - as_ptr: as_ptr_span, - unwrap: unwrap.span, - }); - } - } - } - } -} diff --git a/compiler/rustc_lint/src/non_fmt_panic.rs b/compiler/rustc_lint/src/non_fmt_panic.rs index 51877e8a034..cf25ec99e67 100644 --- a/compiler/rustc_lint/src/non_fmt_panic.rs +++ b/compiler/rustc_lint/src/non_fmt_panic.rs @@ -157,7 +157,7 @@ fn check_panic<'tcx>(cx: &LateContext<'tcx>, f: &'tcx hir::Expr<'tcx>, arg: &'tc Some(ty_def) if cx.tcx.is_lang_item(ty_def.did(), LangItem::String), ); - let infcx = cx.tcx.infer_ctxt().build(); + let infcx = cx.tcx.infer_ctxt().build(cx.typing_mode()); let suggest_display = is_str || cx.tcx.get_diagnostic_item(sym::Display).is_some_and(|t| { infcx.type_implements_trait(t, [ty], cx.param_env).may_apply() diff --git a/compiler/rustc_lint/src/opaque_hidden_inferred_bound.rs b/compiler/rustc_lint/src/opaque_hidden_inferred_bound.rs index ffbcf7f808e..5de0d4bc870 100644 --- a/compiler/rustc_lint/src/opaque_hidden_inferred_bound.rs +++ b/compiler/rustc_lint/src/opaque_hidden_inferred_bound.rs @@ -69,7 +69,7 @@ declare_lint_pass!(OpaqueHiddenInferredBound => [OPAQUE_HIDDEN_INFERRED_BOUND]); impl<'tcx> LateLintPass<'tcx> for OpaqueHiddenInferredBound { fn check_ty(&mut self, cx: &LateContext<'tcx>, ty: &'tcx hir::Ty<'tcx>) { - let hir::TyKind::OpaqueDef(opaque, _) = &ty.kind else { + let hir::TyKind::OpaqueDef(opaque) = &ty.kind else { return; }; @@ -85,7 +85,7 @@ impl<'tcx> LateLintPass<'tcx> for OpaqueHiddenInferredBound { } let def_id = opaque.def_id.to_def_id(); - let infcx = &cx.tcx.infer_ctxt().build(); + let infcx = &cx.tcx.infer_ctxt().build(cx.typing_mode()); // For every projection predicate in the opaque type's explicit bounds, // check that the type that we're assigning actually satisfies the bounds // of the associated type. diff --git a/compiler/rustc_lint/src/types/literal.rs b/compiler/rustc_lint/src/types/literal.rs index d1e850990dc..dca42fea57d 100644 --- a/compiler/rustc_lint/src/types/literal.rs +++ b/compiler/rustc_lint/src/types/literal.rs @@ -1,8 +1,8 @@ use hir::{ExprKind, Node, is_range_literal}; +use rustc_abi::{Integer, Size}; use rustc_middle::ty::Ty; use rustc_middle::ty::layout::IntegerExt; use rustc_middle::{bug, ty}; -use rustc_target::abi::{Integer, Size}; use {rustc_ast as ast, rustc_attr as attr, rustc_hir as hir}; use crate::LateContext; diff --git a/compiler/rustc_llvm/llvm-wrapper/PassWrapper.cpp b/compiler/rustc_llvm/llvm-wrapper/PassWrapper.cpp index 4b303511dbc..3e906f89c15 100644 --- a/compiler/rustc_llvm/llvm-wrapper/PassWrapper.cpp +++ b/compiler/rustc_llvm/llvm-wrapper/PassWrapper.cpp @@ -1251,12 +1251,12 @@ getFirstDefinitionForLinker(const GlobalValueSummaryList &GVSummaryList) { // here is basically the same as before threads are spawned in the `run` // function of `lib/LTO/ThinLTOCodeGenerator.cpp`. extern "C" LLVMRustThinLTOData * -LLVMRustCreateThinLTOData(LLVMRustThinLTOModule *modules, int num_modules, - const char **preserved_symbols, int num_symbols) { +LLVMRustCreateThinLTOData(LLVMRustThinLTOModule *modules, size_t num_modules, + const char **preserved_symbols, size_t num_symbols) { auto Ret = std::make_unique<LLVMRustThinLTOData>(); // Load each module's summary and merge it into one combined index - for (int i = 0; i < num_modules; i++) { + for (size_t i = 0; i < num_modules; i++) { auto module = &modules[i]; auto buffer = StringRef(module->data, module->len); auto mem_buffer = MemoryBufferRef(buffer, module->identifier); @@ -1275,7 +1275,7 @@ LLVMRustCreateThinLTOData(LLVMRustThinLTOModule *modules, int num_modules, // Convert the preserved symbols set from string to GUID, this is then needed // for internalization. - for (int i = 0; i < num_symbols; i++) { + for (size_t i = 0; i < num_symbols; i++) { auto GUID = GlobalValue::getGUID(preserved_symbols[i]); Ret->GUIDPreservedSymbols.insert(GUID); } @@ -1559,8 +1559,10 @@ extern "C" LLVMModuleRef LLVMRustParseBitcodeForLTO(LLVMContextRef Context, extern "C" const char *LLVMRustGetSliceFromObjectDataByName(const char *data, size_t len, const char *name, + size_t name_len, size_t *out_len) { *out_len = 0; + auto Name = StringRef(name, name_len); auto Data = StringRef(data, len); auto Buffer = MemoryBufferRef(Data, ""); // The id is unused. file_magic Type = identify_magic(Buffer.getBuffer()); @@ -1571,8 +1573,8 @@ extern "C" const char *LLVMRustGetSliceFromObjectDataByName(const char *data, return nullptr; } for (const object::SectionRef &Sec : (*ObjFileOrError)->sections()) { - Expected<StringRef> Name = Sec.getName(); - if (Name && *Name == name) { + Expected<StringRef> SecName = Sec.getName(); + if (SecName && *SecName == Name) { Expected<StringRef> SectionOrError = Sec.getContents(); if (!SectionOrError) { LLVMRustSetLastError(toString(SectionOrError.takeError()).c_str()); diff --git a/compiler/rustc_llvm/llvm-wrapper/RustWrapper.cpp b/compiler/rustc_llvm/llvm-wrapper/RustWrapper.cpp index cb75888abd7..645b4082be5 100644 --- a/compiler/rustc_llvm/llvm-wrapper/RustWrapper.cpp +++ b/compiler/rustc_llvm/llvm-wrapper/RustWrapper.cpp @@ -853,25 +853,63 @@ extern "C" uint32_t LLVMRustVersionMinor() { return LLVM_VERSION_MINOR; } extern "C" uint32_t LLVMRustVersionMajor() { return LLVM_VERSION_MAJOR; } -extern "C" void LLVMRustAddModuleFlagU32(LLVMModuleRef M, - Module::ModFlagBehavior MergeBehavior, - const char *Name, uint32_t Value) { - unwrap(M)->addModuleFlag(MergeBehavior, Name, Value); +// FFI equivalent of LLVM's `llvm::Module::ModFlagBehavior`. +// Must match the layout of +// `rustc_codegen_llvm::llvm::ffi::ModuleFlagMergeBehavior`. +// +// There is a stable LLVM-C version of this enum (`LLVMModuleFlagBehavior`), +// but as of LLVM 19 it does not support all of the enum values in the unstable +// C++ API. +enum class LLVMRustModuleFlagMergeBehavior { + Error = 1, + Warning = 2, + Require = 3, + Override = 4, + Append = 5, + AppendUnique = 6, + Max = 7, + Min = 8, +}; + +static Module::ModFlagBehavior +fromRust(LLVMRustModuleFlagMergeBehavior Behavior) { + switch (Behavior) { + case LLVMRustModuleFlagMergeBehavior::Error: + return Module::ModFlagBehavior::Error; + case LLVMRustModuleFlagMergeBehavior::Warning: + return Module::ModFlagBehavior::Warning; + case LLVMRustModuleFlagMergeBehavior::Require: + return Module::ModFlagBehavior::Require; + case LLVMRustModuleFlagMergeBehavior::Override: + return Module::ModFlagBehavior::Override; + case LLVMRustModuleFlagMergeBehavior::Append: + return Module::ModFlagBehavior::Append; + case LLVMRustModuleFlagMergeBehavior::AppendUnique: + return Module::ModFlagBehavior::AppendUnique; + case LLVMRustModuleFlagMergeBehavior::Max: + return Module::ModFlagBehavior::Max; + case LLVMRustModuleFlagMergeBehavior::Min: + return Module::ModFlagBehavior::Min; + } + report_fatal_error("bad LLVMRustModuleFlagMergeBehavior"); +} + +extern "C" void +LLVMRustAddModuleFlagU32(LLVMModuleRef M, + LLVMRustModuleFlagMergeBehavior MergeBehavior, + const char *Name, size_t NameLen, uint32_t Value) { + unwrap(M)->addModuleFlag(fromRust(MergeBehavior), StringRef(Name, NameLen), + Value); } extern "C" void LLVMRustAddModuleFlagString( - LLVMModuleRef M, Module::ModFlagBehavior MergeBehavior, const char *Name, - const char *Value, size_t ValueLen) { + LLVMModuleRef M, LLVMRustModuleFlagMergeBehavior MergeBehavior, + const char *Name, size_t NameLen, const char *Value, size_t ValueLen) { unwrap(M)->addModuleFlag( - MergeBehavior, Name, + fromRust(MergeBehavior), StringRef(Name, NameLen), MDString::get(unwrap(M)->getContext(), StringRef(Value, ValueLen))); } -extern "C" bool LLVMRustHasModuleFlag(LLVMModuleRef M, const char *Name, - size_t Len) { - return unwrap(M)->getModuleFlag(StringRef(Name, Len)) != nullptr; -} - extern "C" void LLVMRustGlobalAddMetadata(LLVMValueRef Global, unsigned Kind, LLVMMetadataRef MD) { unwrap<GlobalObject>(Global)->addMetadata(Kind, *unwrap<MDNode>(MD)); @@ -1231,7 +1269,7 @@ extern "C" uint64_t LLVMRustDIBuilderCreateOpPlusUconst() { return dwarf::DW_OP_plus_uconst; } -extern "C" int64_t LLVMRustDIBuilderCreateOpLLVMFragment() { +extern "C" uint64_t LLVMRustDIBuilderCreateOpLLVMFragment() { return dwarf::DW_OP_LLVM_fragment; } @@ -1499,38 +1537,6 @@ LLVMRustUnpackSMDiagnostic(LLVMSMDiagnosticRef DRef, RustStringRef MessageOut, return true; } -extern "C" OperandBundleDef *LLVMRustBuildOperandBundleDef(const char *Name, - LLVMValueRef *Inputs, - unsigned NumInputs) { - return new OperandBundleDef(Name, - ArrayRef<Value *>(unwrap(Inputs), NumInputs)); -} - -extern "C" void LLVMRustFreeOperandBundleDef(OperandBundleDef *Bundle) { - delete Bundle; -} - -// OpBundlesIndirect is an array of pointers (*not* a pointer to an array). -extern "C" LLVMValueRef LLVMRustBuildCall(LLVMBuilderRef B, LLVMTypeRef Ty, - LLVMValueRef Fn, LLVMValueRef *Args, - unsigned NumArgs, - OperandBundleDef **OpBundlesIndirect, - unsigned NumOpBundles) { - Value *Callee = unwrap(Fn); - FunctionType *FTy = unwrap<FunctionType>(Ty); - - // FIXME: Is there a way around this? - SmallVector<OperandBundleDef> OpBundles; - OpBundles.reserve(NumOpBundles); - for (unsigned i = 0; i < NumOpBundles; ++i) { - OpBundles.push_back(*OpBundlesIndirect[i]); - } - - return wrap(unwrap(B)->CreateCall(FTy, Callee, - ArrayRef<Value *>(unwrap(Args), NumArgs), - ArrayRef<OperandBundleDef>(OpBundles))); -} - extern "C" LLVMValueRef LLVMRustBuildMemCpy(LLVMBuilderRef B, LLVMValueRef Dst, unsigned DstAlign, LLVMValueRef Src, unsigned SrcAlign, @@ -1558,37 +1564,18 @@ extern "C" LLVMValueRef LLVMRustBuildMemSet(LLVMBuilderRef B, LLVMValueRef Dst, MaybeAlign(DstAlign), IsVolatile)); } -// OpBundlesIndirect is an array of pointers (*not* a pointer to an array). -extern "C" LLVMValueRef -LLVMRustBuildInvoke(LLVMBuilderRef B, LLVMTypeRef Ty, LLVMValueRef Fn, - LLVMValueRef *Args, unsigned NumArgs, - LLVMBasicBlockRef Then, LLVMBasicBlockRef Catch, - OperandBundleDef **OpBundlesIndirect, unsigned NumOpBundles, - const char *Name) { - Value *Callee = unwrap(Fn); - FunctionType *FTy = unwrap<FunctionType>(Ty); - - // FIXME: Is there a way around this? - SmallVector<OperandBundleDef> OpBundles; - OpBundles.reserve(NumOpBundles); - for (unsigned i = 0; i < NumOpBundles; ++i) { - OpBundles.push_back(*OpBundlesIndirect[i]); - } - - return wrap(unwrap(B)->CreateInvoke(FTy, Callee, unwrap(Then), unwrap(Catch), - ArrayRef<Value *>(unwrap(Args), NumArgs), - ArrayRef<OperandBundleDef>(OpBundles), - Name)); -} +// Polyfill for `LLVMBuildCallBr`, which was added in LLVM 19. +// <https://github.com/llvm/llvm-project/commit/584253c4e2f788f870488fc32193b52d67ddaccc> +// FIXME: Remove when Rust's minimum supported LLVM version reaches 19. +#if LLVM_VERSION_LT(19, 0) +DEFINE_SIMPLE_CONVERSION_FUNCTIONS(OperandBundleDef, LLVMOperandBundleRef) -// OpBundlesIndirect is an array of pointers (*not* a pointer to an array). extern "C" LLVMValueRef -LLVMRustBuildCallBr(LLVMBuilderRef B, LLVMTypeRef Ty, LLVMValueRef Fn, - LLVMBasicBlockRef DefaultDest, - LLVMBasicBlockRef *IndirectDests, unsigned NumIndirectDests, - LLVMValueRef *Args, unsigned NumArgs, - OperandBundleDef **OpBundlesIndirect, unsigned NumOpBundles, - const char *Name) { +LLVMBuildCallBr(LLVMBuilderRef B, LLVMTypeRef Ty, LLVMValueRef Fn, + LLVMBasicBlockRef DefaultDest, LLVMBasicBlockRef *IndirectDests, + unsigned NumIndirectDests, LLVMValueRef *Args, unsigned NumArgs, + LLVMOperandBundleRef *Bundles, unsigned NumBundles, + const char *Name) { Value *Callee = unwrap(Fn); FunctionType *FTy = unwrap<FunctionType>(Ty); @@ -1601,9 +1588,9 @@ LLVMRustBuildCallBr(LLVMBuilderRef B, LLVMTypeRef Ty, LLVMValueRef Fn, // FIXME: Is there a way around this? SmallVector<OperandBundleDef> OpBundles; - OpBundles.reserve(NumOpBundles); - for (unsigned i = 0; i < NumOpBundles; ++i) { - OpBundles.push_back(*OpBundlesIndirect[i]); + OpBundles.reserve(NumBundles); + for (unsigned i = 0; i < NumBundles; ++i) { + OpBundles.push_back(*unwrap(Bundles[i])); } return wrap( @@ -1612,6 +1599,7 @@ LLVMRustBuildCallBr(LLVMBuilderRef B, LLVMTypeRef Ty, LLVMValueRef Fn, ArrayRef<Value *>(unwrap(Args), NumArgs), ArrayRef<OperandBundleDef>(OpBundles), Name)); } +#endif extern "C" void LLVMRustPositionBuilderAtStart(LLVMBuilderRef B, LLVMBasicBlockRef BB) { @@ -1619,86 +1607,6 @@ extern "C" void LLVMRustPositionBuilderAtStart(LLVMBuilderRef B, unwrap(B)->SetInsertPoint(unwrap(BB), Point); } -enum class LLVMRustLinkage { - ExternalLinkage = 0, - AvailableExternallyLinkage = 1, - LinkOnceAnyLinkage = 2, - LinkOnceODRLinkage = 3, - WeakAnyLinkage = 4, - WeakODRLinkage = 5, - AppendingLinkage = 6, - InternalLinkage = 7, - PrivateLinkage = 8, - ExternalWeakLinkage = 9, - CommonLinkage = 10, -}; - -static LLVMRustLinkage toRust(LLVMLinkage Linkage) { - switch (Linkage) { - case LLVMExternalLinkage: - return LLVMRustLinkage::ExternalLinkage; - case LLVMAvailableExternallyLinkage: - return LLVMRustLinkage::AvailableExternallyLinkage; - case LLVMLinkOnceAnyLinkage: - return LLVMRustLinkage::LinkOnceAnyLinkage; - case LLVMLinkOnceODRLinkage: - return LLVMRustLinkage::LinkOnceODRLinkage; - case LLVMWeakAnyLinkage: - return LLVMRustLinkage::WeakAnyLinkage; - case LLVMWeakODRLinkage: - return LLVMRustLinkage::WeakODRLinkage; - case LLVMAppendingLinkage: - return LLVMRustLinkage::AppendingLinkage; - case LLVMInternalLinkage: - return LLVMRustLinkage::InternalLinkage; - case LLVMPrivateLinkage: - return LLVMRustLinkage::PrivateLinkage; - case LLVMExternalWeakLinkage: - return LLVMRustLinkage::ExternalWeakLinkage; - case LLVMCommonLinkage: - return LLVMRustLinkage::CommonLinkage; - default: - report_fatal_error("Invalid LLVMRustLinkage value!"); - } -} - -static LLVMLinkage fromRust(LLVMRustLinkage Linkage) { - switch (Linkage) { - case LLVMRustLinkage::ExternalLinkage: - return LLVMExternalLinkage; - case LLVMRustLinkage::AvailableExternallyLinkage: - return LLVMAvailableExternallyLinkage; - case LLVMRustLinkage::LinkOnceAnyLinkage: - return LLVMLinkOnceAnyLinkage; - case LLVMRustLinkage::LinkOnceODRLinkage: - return LLVMLinkOnceODRLinkage; - case LLVMRustLinkage::WeakAnyLinkage: - return LLVMWeakAnyLinkage; - case LLVMRustLinkage::WeakODRLinkage: - return LLVMWeakODRLinkage; - case LLVMRustLinkage::AppendingLinkage: - return LLVMAppendingLinkage; - case LLVMRustLinkage::InternalLinkage: - return LLVMInternalLinkage; - case LLVMRustLinkage::PrivateLinkage: - return LLVMPrivateLinkage; - case LLVMRustLinkage::ExternalWeakLinkage: - return LLVMExternalWeakLinkage; - case LLVMRustLinkage::CommonLinkage: - return LLVMCommonLinkage; - } - report_fatal_error("Invalid LLVMRustLinkage value!"); -} - -extern "C" LLVMRustLinkage LLVMRustGetLinkage(LLVMValueRef V) { - return toRust(LLVMGetLinkage(V)); -} - -extern "C" void LLVMRustSetLinkage(LLVMValueRef V, - LLVMRustLinkage RustLinkage) { - LLVMSetLinkage(V, fromRust(RustLinkage)); -} - extern "C" bool LLVMRustConstIntGetZExtValue(LLVMValueRef CV, uint64_t *value) { auto C = unwrap<llvm::ConstantInt>(CV); if (C->getBitWidth() > 64) @@ -1726,45 +1634,6 @@ extern "C" bool LLVMRustConstInt128Get(LLVMValueRef CV, bool sext, return true; } -enum class LLVMRustVisibility { - Default = 0, - Hidden = 1, - Protected = 2, -}; - -static LLVMRustVisibility toRust(LLVMVisibility Vis) { - switch (Vis) { - case LLVMDefaultVisibility: - return LLVMRustVisibility::Default; - case LLVMHiddenVisibility: - return LLVMRustVisibility::Hidden; - case LLVMProtectedVisibility: - return LLVMRustVisibility::Protected; - } - report_fatal_error("Invalid LLVMRustVisibility value!"); -} - -static LLVMVisibility fromRust(LLVMRustVisibility Vis) { - switch (Vis) { - case LLVMRustVisibility::Default: - return LLVMDefaultVisibility; - case LLVMRustVisibility::Hidden: - return LLVMHiddenVisibility; - case LLVMRustVisibility::Protected: - return LLVMProtectedVisibility; - } - report_fatal_error("Invalid LLVMRustVisibility value!"); -} - -extern "C" LLVMRustVisibility LLVMRustGetVisibility(LLVMValueRef V) { - return toRust(LLVMGetVisibility(V)); -} - -extern "C" void LLVMRustSetVisibility(LLVMValueRef V, - LLVMRustVisibility RustVisibility) { - LLVMSetVisibility(V, fromRust(RustVisibility)); -} - extern "C" void LLVMRustSetDSOLocal(LLVMValueRef Global, bool is_dso_local) { unwrap<GlobalValue>(Global)->setDSOLocal(is_dso_local); } diff --git a/compiler/rustc_macros/src/diagnostics/diagnostic_builder.rs b/compiler/rustc_macros/src/diagnostics/diagnostic_builder.rs index 72f1e599247..1055f27c1e4 100644 --- a/compiler/rustc_macros/src/diagnostics/diagnostic_builder.rs +++ b/compiler/rustc_macros/src/diagnostics/diagnostic_builder.rs @@ -253,7 +253,10 @@ impl DiagnosticDeriveVariantBuilder { let mut field_binding = binding_info.binding.clone(); field_binding.set_span(field.ty.span()); - let ident = field.ident.as_ref().unwrap(); + let Some(ident) = field.ident.as_ref() else { + span_err(field.span().unwrap(), "tuple structs are not supported").emit(); + return TokenStream::new(); + }; let ident = format_ident!("{}", ident); // strip `r#` prefix, if present quote! { diff --git a/compiler/rustc_macros/src/diagnostics/error.rs b/compiler/rustc_macros/src/diagnostics/error.rs index 9cdb9fbab12..a78cf2b63d0 100644 --- a/compiler/rustc_macros/src/diagnostics/error.rs +++ b/compiler/rustc_macros/src/diagnostics/error.rs @@ -56,7 +56,7 @@ fn path_to_string(path: &syn::Path) -> String { /// Returns an error diagnostic on span `span` with msg `msg`. #[must_use] pub(crate) fn span_err<T: Into<String>>(span: impl MultiSpan, msg: T) -> Diagnostic { - Diagnostic::spanned(span, Level::Error, msg) + Diagnostic::spanned(span, Level::Error, format!("derive(Diagnostic): {}", msg.into())) } /// Emit a diagnostic on span `$span` with msg `$msg` (optionally performing additional decoration diff --git a/compiler/rustc_macros/src/diagnostics/utils.rs b/compiler/rustc_macros/src/diagnostics/utils.rs index 5946b11828e..612a36ba9aa 100644 --- a/compiler/rustc_macros/src/diagnostics/utils.rs +++ b/compiler/rustc_macros/src/diagnostics/utils.rs @@ -243,7 +243,7 @@ impl<T> SetOnce<T> for SpannedOption<T> { *self = Some((value, span)); } Some((_, prev_span)) => { - span_err(span, "specified multiple times") + span_err(span, "attribute specified multiple times") .span_note(*prev_span, "previously specified here") .emit(); } diff --git a/compiler/rustc_macros/src/lib.rs b/compiler/rustc_macros/src/lib.rs index f46c795b956..0df674eb4c9 100644 --- a/compiler/rustc_macros/src/lib.rs +++ b/compiler/rustc_macros/src/lib.rs @@ -20,6 +20,7 @@ mod lift; mod query; mod serialize; mod symbols; +mod try_from; mod type_foldable; mod type_visitable; @@ -165,3 +166,12 @@ decl_derive!( suggestion_part, applicability)] => diagnostics::subdiagnostic_derive ); + +decl_derive! { + [TryFromU32] => + /// Derives `TryFrom<u32>` for the annotated `enum`, which must have no fields. + /// Each variant maps to the value it would produce under an `as u32` cast. + /// + /// The error type is `u32`. + try_from::try_from_u32 +} diff --git a/compiler/rustc_macros/src/try_from.rs b/compiler/rustc_macros/src/try_from.rs new file mode 100644 index 00000000000..9338c1c2b33 --- /dev/null +++ b/compiler/rustc_macros/src/try_from.rs @@ -0,0 +1,55 @@ +use proc_macro2::TokenStream; +use quote::{quote, quote_spanned}; +use syn::Data; +use syn::spanned::Spanned; +use synstructure::Structure; + +pub(crate) fn try_from_u32(s: Structure<'_>) -> TokenStream { + let span_error = |span, message: &str| { + quote_spanned! { span => const _: () = ::core::compile_error!(#message); } + }; + + // Must be applied to an enum type. + if let Some(span) = match &s.ast().data { + Data::Enum(_) => None, + Data::Struct(s) => Some(s.struct_token.span()), + Data::Union(u) => Some(u.union_token.span()), + } { + return span_error(span, "type is not an enum (TryFromU32)"); + } + + // The enum's variants must not have fields. + let variant_field_errors = s + .variants() + .iter() + .filter_map(|v| v.ast().fields.iter().map(|f| f.span()).next()) + .map(|span| span_error(span, "enum variant cannot have fields (TryFromU32)")) + .collect::<TokenStream>(); + if !variant_field_errors.is_empty() { + return variant_field_errors; + } + + let ctor = s + .variants() + .iter() + .map(|v| v.construct(|_, _| -> TokenStream { unreachable!() })) + .collect::<Vec<_>>(); + // FIXME(edition_2024): Fix the `keyword_idents_2024` lint to not trigger here? + #[allow(keyword_idents_2024)] + s.gen_impl(quote! { + // The surrounding code might have shadowed these identifiers. + use ::core::convert::TryFrom; + use ::core::primitive::u32; + use ::core::result::Result::{self, Ok, Err}; + + gen impl TryFrom<u32> for @Self { + type Error = u32; + + #[allow(deprecated)] // Don't warn about deprecated variants. + fn try_from(value: u32) -> Result<Self, Self::Error> { + #( if value == const { #ctor as u32 } { return Ok(#ctor) } )* + Err(value) + } + } + }) +} diff --git a/compiler/rustc_metadata/Cargo.toml b/compiler/rustc_metadata/Cargo.toml index 79d3482472a..3b0151b1f94 100644 --- a/compiler/rustc_metadata/Cargo.toml +++ b/compiler/rustc_metadata/Cargo.toml @@ -8,6 +8,7 @@ edition = "2021" bitflags = "2.4.1" libloading = "0.8.0" odht = { version = "0.3.1", features = ["nightly"] } +rustc_abi = { path = "../rustc_abi" } rustc_ast = { path = "../rustc_ast" } rustc_attr = { path = "../rustc_attr" } rustc_data_structures = { path = "../rustc_data_structures" } diff --git a/compiler/rustc_metadata/src/creader.rs b/compiler/rustc_metadata/src/creader.rs index 8adec7554a8..16623915c40 100644 --- a/compiler/rustc_metadata/src/creader.rs +++ b/compiler/rustc_metadata/src/creader.rs @@ -28,7 +28,7 @@ use rustc_session::lint::{self, BuiltinLintDiag}; use rustc_session::output::validate_crate_name; use rustc_session::search_paths::PathKind; use rustc_span::edition::Edition; -use rustc_span::symbol::{Symbol, sym}; +use rustc_span::symbol::{Ident, Symbol, sym}; use rustc_span::{DUMMY_SP, Span}; use rustc_target::spec::{PanicStrategy, Target, TargetTriple}; use tracing::{debug, info, trace}; @@ -97,7 +97,7 @@ impl<'a, 'tcx> CrateLoader<'a, 'tcx> { } pub enum LoadedMacro { - MacroDef(ast::Item, Edition), + MacroDef { def: MacroDef, ident: Ident, attrs: AttrVec, span: Span, edition: Edition }, ProcMacro(SyntaxExtension), } diff --git a/compiler/rustc_metadata/src/rmeta/decoder/cstore_impl.rs b/compiler/rustc_metadata/src/rmeta/decoder/cstore_impl.rs index 71c7231a788..926eb4f6210 100644 --- a/compiler/rustc_metadata/src/rmeta/decoder/cstore_impl.rs +++ b/compiler/rustc_metadata/src/rmeta/decoder/cstore_impl.rs @@ -1,7 +1,6 @@ use std::any::Any; use std::mem; -use rustc_ast as ast; use rustc_attr::Deprecation; use rustc_data_structures::sync::Lrc; use rustc_hir::def::{CtorKind, DefKind, Res}; @@ -592,27 +591,16 @@ impl CStore { let data = self.get_crate_data(id.krate); if data.root.is_proc_macro_crate() { - return LoadedMacro::ProcMacro(data.load_proc_macro(id.index, tcx)); - } - - let span = data.get_span(id.index, sess); - - LoadedMacro::MacroDef( - ast::Item { + LoadedMacro::ProcMacro(data.load_proc_macro(id.index, tcx)) + } else { + LoadedMacro::MacroDef { + def: data.get_macro(id.index, sess), ident: data.item_ident(id.index, sess), - id: ast::DUMMY_NODE_ID, - span, attrs: data.get_item_attrs(id.index, sess).collect(), - kind: ast::ItemKind::MacroDef(data.get_macro(id.index, sess)), - vis: ast::Visibility { - span: span.shrink_to_lo(), - kind: ast::VisibilityKind::Inherited, - tokens: None, - }, - tokens: None, - }, - data.root.edition, - ) + span: data.get_span(id.index, sess), + edition: data.root.edition, + } + } } pub fn def_span_untracked(&self, def_id: DefId, sess: &Session) -> Span { diff --git a/compiler/rustc_metadata/src/rmeta/encoder.rs b/compiler/rustc_metadata/src/rmeta/encoder.rs index 47f7a8b7c20..b5ac302c597 100644 --- a/compiler/rustc_metadata/src/rmeta/encoder.rs +++ b/compiler/rustc_metadata/src/rmeta/encoder.rs @@ -278,7 +278,7 @@ impl<'a, 'tcx> Encodable<EncodeContext<'a, 'tcx>> for SpanData { let source_map = s.tcx.sess.source_map(); let source_file_index = source_map.lookup_source_file_idx(self.lo); s.source_file_cache = - (source_map.files()[source_file_index].clone(), source_file_index); + (Lrc::clone(&source_map.files()[source_file_index]), source_file_index); } let (ref source_file, source_file_index) = s.source_file_cache; debug_assert!(source_file.contains(self.lo)); @@ -2275,7 +2275,7 @@ pub fn encode_metadata(tcx: TyCtxt<'_>, path: &Path) { encoder.emit_raw_bytes(&0u64.to_le_bytes()); let source_map_files = tcx.sess.source_map().files(); - let source_file_cache = (source_map_files[0].clone(), 0); + let source_file_cache = (Lrc::clone(&source_map_files[0]), 0); let required_source_files = Some(FxIndexSet::default()); drop(source_map_files); diff --git a/compiler/rustc_metadata/src/rmeta/mod.rs b/compiler/rustc_metadata/src/rmeta/mod.rs index a00ca27aacc..f1844045677 100644 --- a/compiler/rustc_metadata/src/rmeta/mod.rs +++ b/compiler/rustc_metadata/src/rmeta/mod.rs @@ -6,6 +6,7 @@ use decoder::{DecodeContext, Metadata}; use def_path_hash_map::DefPathHashMapRef; use encoder::EncodeContext; pub use encoder::{EncodedMetadata, encode_metadata, rendered_const}; +use rustc_abi::{FieldIdx, VariantIdx}; use rustc_ast::expand::StrippedCfgItem; use rustc_data_structures::fx::FxHashMap; use rustc_data_structures::svh::Svh; @@ -37,7 +38,6 @@ use rustc_span::edition::Edition; use rustc_span::hygiene::{ExpnIndex, MacroKind, SyntaxContextData}; use rustc_span::symbol::{Ident, Symbol}; use rustc_span::{self, ExpnData, ExpnHash, ExpnId, Span}; -use rustc_target::abi::{FieldIdx, VariantIdx}; use rustc_target::spec::{PanicStrategy, TargetTriple}; use table::TableBuilder; use {rustc_ast as ast, rustc_attr as attr, rustc_hir as hir}; diff --git a/compiler/rustc_middle/src/arena.rs b/compiler/rustc_middle/src/arena.rs index 52fe9956b47..7e77923fcdf 100644 --- a/compiler/rustc_middle/src/arena.rs +++ b/compiler/rustc_middle/src/arena.rs @@ -8,7 +8,7 @@ macro_rules! arena_types { ($macro:path) => ( $macro!([ - [] layout: rustc_target::abi::LayoutS<rustc_target::abi::FieldIdx, rustc_target::abi::VariantIdx>, + [] layout: rustc_abi::LayoutData<rustc_abi::FieldIdx, rustc_abi::VariantIdx>, [] fn_abi: rustc_target::abi::call::FnAbi<'tcx, rustc_middle::ty::Ty<'tcx>>, // AdtDef are interned and compared by address [decode] adt_def: rustc_middle::ty::AdtDefData, diff --git a/compiler/rustc_middle/src/middle/debugger_visualizer.rs b/compiler/rustc_middle/src/middle/debugger_visualizer.rs index 615a7402139..c241c06fce4 100644 --- a/compiler/rustc_middle/src/middle/debugger_visualizer.rs +++ b/compiler/rustc_middle/src/middle/debugger_visualizer.rs @@ -32,7 +32,7 @@ impl DebuggerVisualizerFile { pub fn path_erased(&self) -> Self { DebuggerVisualizerFile { - src: self.src.clone(), + src: Lrc::clone(&self.src), visualizer_type: self.visualizer_type, path: None, } diff --git a/compiler/rustc_middle/src/middle/resolve_bound_vars.rs b/compiler/rustc_middle/src/middle/resolve_bound_vars.rs index 13e35cd0909..111ac990bc7 100644 --- a/compiler/rustc_middle/src/middle/resolve_bound_vars.rs +++ b/compiler/rustc_middle/src/middle/resolve_bound_vars.rs @@ -3,7 +3,7 @@ use rustc_data_structures::sorted_map::SortedMap; use rustc_errors::ErrorGuaranteed; use rustc_hir::ItemLocalId; -use rustc_hir::def_id::{DefId, LocalDefId}; +use rustc_hir::def_id::{DefId, LocalDefId, LocalDefIdMap}; use rustc_macros::{Decodable, Encodable, HashStable, TyDecodable, TyEncodable}; use crate::ty; @@ -54,4 +54,6 @@ pub struct ResolveBoundVars { pub defs: SortedMap<ItemLocalId, ResolvedArg>, pub late_bound_vars: SortedMap<ItemLocalId, Vec<ty::BoundVariableKind>>, + + pub opaque_captured_lifetimes: LocalDefIdMap<Vec<(ResolvedArg, LocalDefId)>>, } diff --git a/compiler/rustc_middle/src/query/mod.rs b/compiler/rustc_middle/src/query/mod.rs index d7a60a843b7..d7f58963101 100644 --- a/compiler/rustc_middle/src/query/mod.rs +++ b/compiler/rustc_middle/src/query/mod.rs @@ -1781,6 +1781,23 @@ rustc_queries! { -> &'tcx SortedMap<ItemLocalId, Vec<ty::BoundVariableKind>> { desc { |tcx| "looking up late bound vars inside `{}`", tcx.def_path_str(owner_id) } } + /// For an opaque type, return the list of (captured lifetime, inner generic param). + /// ```ignore (illustrative) + /// fn foo<'a: 'a, 'b, T>(&'b u8) -> impl Into<Self> + 'b { ... } + /// ``` + /// + /// We would return `[('a, '_a), ('b, '_b)]`, with `'a` early-bound and `'b` late-bound. + /// + /// After hir_ty_lowering, we get: + /// ```ignore (pseudo-code) + /// opaque foo::<'a>::opaque<'_a, '_b>: Into<Foo<'_a>> + '_b; + /// ^^^^^^^^ inner generic params + /// fn foo<'a>: for<'b> fn(&'b u8) -> foo::<'a>::opaque::<'a, 'b> + /// ^^^^^^ captured lifetimes + /// ``` + query opaque_captured_lifetimes(def_id: LocalDefId) -> &'tcx [(ResolvedArg, LocalDefId)] { + desc { |tcx| "listing captured lifetimes for opaque `{}`", tcx.def_path_str(def_id) } + } /// Computes the visibility of the provided `def_id`. /// diff --git a/compiler/rustc_middle/src/query/on_disk_cache.rs b/compiler/rustc_middle/src/query/on_disk_cache.rs index 35a16684615..8b77a4a81ca 100644 --- a/compiler/rustc_middle/src/query/on_disk_cache.rs +++ b/compiler/rustc_middle/src/query/on_disk_cache.rs @@ -472,32 +472,27 @@ impl<'a, 'tcx> CacheDecoder<'a, 'tcx> { let CacheDecoder { tcx, file_index_to_file, file_index_to_stable_id, source_map, .. } = *self; - file_index_to_file - .borrow_mut() - .entry(index) - .or_insert_with(|| { - let source_file_id = &file_index_to_stable_id[&index]; - let source_file_cnum = - tcx.stable_crate_id_to_crate_num(source_file_id.stable_crate_id); - - // If this `SourceFile` is from a foreign crate, then make sure - // that we've imported all of the source files from that crate. - // This has usually already been done during macro invocation. - // However, when encoding query results like `TypeckResults`, - // we might encode an `AdtDef` for a foreign type (because it - // was referenced in the body of the function). There is no guarantee - // that we will load the source files from that crate during macro - // expansion, so we use `import_source_files` to ensure that the foreign - // source files are actually imported before we call `source_file_by_stable_id`. - if source_file_cnum != LOCAL_CRATE { - self.tcx.import_source_files(source_file_cnum); - } + Lrc::clone(file_index_to_file.borrow_mut().entry(index).or_insert_with(|| { + let source_file_id = &file_index_to_stable_id[&index]; + let source_file_cnum = tcx.stable_crate_id_to_crate_num(source_file_id.stable_crate_id); + + // If this `SourceFile` is from a foreign crate, then make sure + // that we've imported all of the source files from that crate. + // This has usually already been done during macro invocation. + // However, when encoding query results like `TypeckResults`, + // we might encode an `AdtDef` for a foreign type (because it + // was referenced in the body of the function). There is no guarantee + // that we will load the source files from that crate during macro + // expansion, so we use `import_source_files` to ensure that the foreign + // source files are actually imported before we call `source_file_by_stable_id`. + if source_file_cnum != LOCAL_CRATE { + self.tcx.import_source_files(source_file_cnum); + } - source_map - .source_file_by_stable_id(source_file_id.stable_source_file_id) - .expect("failed to lookup `SourceFile` in new context") - }) - .clone() + source_map + .source_file_by_stable_id(source_file_id.stable_source_file_id) + .expect("failed to lookup `SourceFile` in new context") + })) } } diff --git a/compiler/rustc_middle/src/query/plumbing.rs b/compiler/rustc_middle/src/query/plumbing.rs index 564d274bc8b..57da5b39ba7 100644 --- a/compiler/rustc_middle/src/query/plumbing.rs +++ b/compiler/rustc_middle/src/query/plumbing.rs @@ -323,7 +323,7 @@ macro_rules! define_callbacks { // Increase this limit if necessary, but do try to keep the size low if possible #[cfg(target_pointer_width = "64")] const _: () = { - if mem::size_of::<Key<'static>>() > 72 { + if mem::size_of::<Key<'static>>() > 80 { panic!("{}", concat!( "the query `", stringify!($name), diff --git a/compiler/rustc_middle/src/traits/mod.rs b/compiler/rustc_middle/src/traits/mod.rs index 8ee8b4c4823..40e5ec45959 100644 --- a/compiler/rustc_middle/src/traits/mod.rs +++ b/compiler/rustc_middle/src/traits/mod.rs @@ -92,16 +92,6 @@ impl<'tcx> ObligationCause<'tcx> { ObligationCause { span, body_id: CRATE_DEF_ID, code: Default::default() } } - pub fn span(&self) -> Span { - match *self.code() { - ObligationCauseCode::MatchExpressionArm(box MatchExpressionArmCause { - arm_span, - .. - }) => arm_span, - _ => self.span, - } - } - #[inline] pub fn code(&self) -> &ObligationCauseCode<'tcx> { &self.code @@ -517,10 +507,17 @@ pub struct MatchExpressionArmCause<'tcx> { pub prior_arm_block_id: Option<HirId>, pub prior_arm_ty: Ty<'tcx>, pub prior_arm_span: Span, + /// Span of the scrutinee of the match (the matched value). pub scrut_span: Span, + /// Source of the match, i.e. `match` or a desugaring. pub source: hir::MatchSource, + /// Span of the *whole* match expr. + pub expr_span: Span, + /// Spans of the previous arms except for those that diverge (i.e. evaluate to `!`). + /// + /// These are used for pointing out errors that may affect several arms. pub prior_non_diverging_arms: Vec<Span>, - // Is the expectation of this match expression an RPIT? + /// Is the expectation of this match expression an RPIT? pub tail_defines_return_position_impl_trait: Option<LocalDefId>, } diff --git a/compiler/rustc_middle/src/ty/context.rs b/compiler/rustc_middle/src/ty/context.rs index a6a0a6dc222..9616a533ab6 100644 --- a/compiler/rustc_middle/src/ty/context.rs +++ b/compiler/rustc_middle/src/ty/context.rs @@ -12,7 +12,7 @@ use std::marker::PhantomData; use std::ops::{Bound, Deref}; use std::{fmt, iter, mem}; -use rustc_abi::{FieldIdx, Layout, LayoutS, TargetDataLayout, VariantIdx}; +use rustc_abi::{FieldIdx, Layout, LayoutData, TargetDataLayout, VariantIdx}; use rustc_ast::{self as ast, attr}; use rustc_data_structures::defer; use rustc_data_structures::fingerprint::Fingerprint; @@ -54,7 +54,6 @@ use rustc_type_ir::TyKind::*; use rustc_type_ir::fold::TypeFoldable; use rustc_type_ir::lang_items::TraitSolverLangItem; pub use rustc_type_ir::lift::Lift; -use rustc_type_ir::solve::SolverMode; use rustc_type_ir::{CollectAndApply, Interner, TypeFlags, WithCachedTypeInfo, search_graph}; use tracing::{debug, trace}; @@ -170,15 +169,8 @@ impl<'tcx> Interner for TyCtxt<'tcx> { tracked.get(self) } - fn with_global_cache<R>( - self, - mode: SolverMode, - f: impl FnOnce(&mut search_graph::GlobalCache<Self>) -> R, - ) -> R { - match mode { - SolverMode::Normal => f(&mut *self.new_solver_evaluation_cache.lock()), - SolverMode::Coherence => f(&mut *self.new_solver_coherence_evaluation_cache.lock()), - } + fn with_global_cache<R>(self, f: impl FnOnce(&mut search_graph::GlobalCache<Self>) -> R) -> R { + f(&mut *self.new_solver_evaluation_cache.lock()) } fn evaluation_is_concurrent(&self) -> bool { @@ -629,6 +621,10 @@ impl<'tcx> Interner for TyCtxt<'tcx> { ) -> ty::Binder<'tcx, T> { self.anonymize_bound_vars(binder) } + + fn opaque_types_defined_by(self, defining_anchor: LocalDefId) -> Self::DefiningOpaqueTypes { + self.opaque_types_defined_by(defining_anchor) + } } macro_rules! bidirectional_lang_item_map { @@ -766,7 +762,7 @@ pub struct CtxtInterners<'tcx> { pat: InternedSet<'tcx, PatternKind<'tcx>>, const_allocation: InternedSet<'tcx, Allocation>, bound_variable_kinds: InternedSet<'tcx, List<ty::BoundVariableKind>>, - layout: InternedSet<'tcx, LayoutS<FieldIdx, VariantIdx>>, + layout: InternedSet<'tcx, LayoutData<FieldIdx, VariantIdx>>, adt_def: InternedSet<'tcx, AdtDefData>, external_constraints: InternedSet<'tcx, ExternalConstraintsData<TyCtxt<'tcx>>>, predefined_opaques_in_body: InternedSet<'tcx, PredefinedOpaquesData<TyCtxt<'tcx>>>, @@ -1334,7 +1330,6 @@ pub struct GlobalCtxt<'tcx> { /// Caches the results of goal evaluation in the new solver. pub new_solver_evaluation_cache: Lock<search_graph::GlobalCache<TyCtxt<'tcx>>>, - pub new_solver_coherence_evaluation_cache: Lock<search_graph::GlobalCache<TyCtxt<'tcx>>>, pub canonical_param_env_cache: CanonicalParamEnvCache<'tcx>, @@ -1561,7 +1556,6 @@ impl<'tcx> TyCtxt<'tcx> { selection_cache: Default::default(), evaluation_cache: Default::default(), new_solver_evaluation_cache: Default::default(), - new_solver_coherence_evaluation_cache: Default::default(), canonical_param_env_cache: Default::default(), data_layout, alloc_map: Lock::new(interpret::AllocMap::new()), @@ -2469,7 +2463,7 @@ direct_interners! { region: pub(crate) intern_region(RegionKind<'tcx>): Region -> Region<'tcx>, pat: pub mk_pat(PatternKind<'tcx>): Pattern -> Pattern<'tcx>, const_allocation: pub mk_const_alloc(Allocation): ConstAllocation -> ConstAllocation<'tcx>, - layout: pub mk_layout(LayoutS<FieldIdx, VariantIdx>): Layout -> Layout<'tcx>, + layout: pub mk_layout(LayoutData<FieldIdx, VariantIdx>): Layout -> Layout<'tcx>, adt_def: pub mk_adt_def_from_data(AdtDefData): AdtDef -> AdtDef<'tcx>, external_constraints: pub mk_external_constraints(ExternalConstraintsData<TyCtxt<'tcx>>): ExternalConstraints -> ExternalConstraints<'tcx>, @@ -3066,7 +3060,7 @@ impl<'tcx> TyCtxt<'tcx> { loop { let parent = self.local_parent(opaque_lifetime_param_def_id); - let hir::OpaqueTy { lifetime_mapping, .. } = self.hir().expect_opaque_ty(parent); + let lifetime_mapping = self.opaque_captured_lifetimes(parent); let Some((lifetime, _)) = lifetime_mapping .iter() @@ -3075,8 +3069,8 @@ impl<'tcx> TyCtxt<'tcx> { bug!("duplicated lifetime param should be present"); }; - match self.named_bound_var(lifetime.hir_id) { - Some(resolve_bound_vars::ResolvedArg::EarlyBound(ebv)) => { + match *lifetime { + resolve_bound_vars::ResolvedArg::EarlyBound(ebv) => { let new_parent = self.local_parent(ebv); // If we map to another opaque, then it should be a parent @@ -3095,7 +3089,7 @@ impl<'tcx> TyCtxt<'tcx> { name: self.item_name(ebv.to_def_id()), }); } - Some(resolve_bound_vars::ResolvedArg::LateBound(_, _, lbv)) => { + resolve_bound_vars::ResolvedArg::LateBound(_, _, lbv) => { let new_parent = self.local_parent(lbv); return ty::Region::new_late_param( self, @@ -3106,13 +3100,13 @@ impl<'tcx> TyCtxt<'tcx> { ), ); } - Some(resolve_bound_vars::ResolvedArg::Error(guar)) => { + resolve_bound_vars::ResolvedArg::Error(guar) => { return ty::Region::new_error(self, guar); } _ => { return ty::Region::new_error_with_message( self, - lifetime.ident.span, + self.def_span(opaque_lifetime_param_def_id), "cannot resolve lifetime", ); } diff --git a/compiler/rustc_middle/src/ty/layout.rs b/compiler/rustc_middle/src/ty/layout.rs index 7e65df6b27c..2c7a3ffd04c 100644 --- a/compiler/rustc_middle/src/ty/layout.rs +++ b/compiler/rustc_middle/src/ty/layout.rs @@ -4,7 +4,7 @@ use std::{cmp, fmt}; use rustc_abi::Primitive::{self, Float, Int, Pointer}; use rustc_abi::{ - Abi, AddressSpace, Align, FieldsShape, HasDataLayout, Integer, LayoutCalculator, LayoutS, + Abi, AddressSpace, Align, FieldsShape, HasDataLayout, Integer, LayoutCalculator, LayoutData, PointeeInfo, PointerKind, ReprOptions, Scalar, Size, TagEncoding, TargetDataLayout, Variants, }; use rustc_error_messages::DiagMessage; @@ -346,7 +346,7 @@ impl<'tcx> SizeSkeleton<'tcx> { // First try computing a static layout. let err = match tcx.layout_of(param_env.and(ty)) { Ok(layout) => { - if layout.abi.is_sized() { + if layout.is_sized() { return Ok(SizeSkeleton::Known(layout.size, Some(layout.align.abi))); } else { // Just to be safe, don't claim a known layout for unsized types. @@ -751,7 +751,7 @@ where ty::Adt(def, _) => def.variant(variant_index).fields.len(), _ => bug!("`ty_and_layout_for_variant` on unexpected type {}", this.ty), }; - tcx.mk_layout(LayoutS { + tcx.mk_layout(LayoutData { variants: Variants::Single { index: variant_index }, fields: match NonZero::new(fields) { Some(fields) => FieldsShape::Union(fields), @@ -788,7 +788,7 @@ where let tcx = cx.tcx(); let tag_layout = |tag: Scalar| -> TyAndLayout<'tcx> { TyAndLayout { - layout: tcx.mk_layout(LayoutS::scalar(cx, tag)), + layout: tcx.mk_layout(LayoutData::scalar(cx, tag)), ty: tag.primitive().to_ty(tcx), } }; diff --git a/compiler/rustc_middle/src/ty/mod.rs b/compiler/rustc_middle/src/ty/mod.rs index b92fc864b49..bd32e5837b3 100644 --- a/compiler/rustc_middle/src/ty/mod.rs +++ b/compiler/rustc_middle/src/ty/mod.rs @@ -100,7 +100,7 @@ pub use self::rvalue_scopes::RvalueScopes; pub use self::sty::{ AliasTy, Article, Binder, BoundTy, BoundTyKind, BoundVariableKind, CanonicalPolyFnSig, CoroutineArgsExt, EarlyBinder, FnSig, InlineConstArgs, InlineConstArgsParts, ParamConst, - ParamTy, PolyFnSig, TyKind, TypeAndMut, UpvarArgs, + ParamTy, PolyFnSig, TyKind, TypeAndMut, TypingMode, UpvarArgs, }; pub use self::trait_def::TraitDef; pub use self::typeck_results::{ diff --git a/compiler/rustc_middle/src/ty/sty.rs b/compiler/rustc_middle/src/ty/sty.rs index d8362ccc0a9..f54afdbc929 100644 --- a/compiler/rustc_middle/src/ty/sty.rs +++ b/compiler/rustc_middle/src/ty/sty.rs @@ -40,6 +40,7 @@ pub type AliasTy<'tcx> = ir::AliasTy<TyCtxt<'tcx>>; pub type FnSig<'tcx> = ir::FnSig<TyCtxt<'tcx>>; pub type Binder<'tcx, T> = ir::Binder<TyCtxt<'tcx>, T>; pub type EarlyBinder<'tcx, T> = ir::EarlyBinder<TyCtxt<'tcx>, T>; +pub type TypingMode<'tcx> = ir::TypingMode<TyCtxt<'tcx>>; pub trait Article { fn article(&self) -> &'static str; @@ -1353,6 +1354,7 @@ impl<'tcx> Ty<'tcx> { } } + #[tracing::instrument(level = "trace", skip(tcx))] pub fn fn_sig(self, tcx: TyCtxt<'tcx>) -> PolyFnSig<'tcx> { match self.kind() { FnDef(def_id, args) => tcx.fn_sig(*def_id).instantiate(tcx, args), diff --git a/compiler/rustc_mir_build/src/build/mod.rs b/compiler/rustc_mir_build/src/build/mod.rs index 8c20d2e0d3a..e15ea4d8d8b 100644 --- a/compiler/rustc_mir_build/src/build/mod.rs +++ b/compiler/rustc_mir_build/src/build/mod.rs @@ -16,7 +16,7 @@ use rustc_middle::middle::region; use rustc_middle::mir::*; use rustc_middle::query::TyCtxtAt; use rustc_middle::thir::{self, ExprId, LintLevel, LocalVarId, Param, ParamId, PatKind, Thir}; -use rustc_middle::ty::{self, ScalarInt, Ty, TyCtxt, TypeVisitableExt}; +use rustc_middle::ty::{self, ScalarInt, Ty, TyCtxt, TypeVisitableExt, TypingMode}; use rustc_middle::{bug, span_bug}; use rustc_span::symbol::sym; use rustc_span::{Span, Symbol}; @@ -500,7 +500,9 @@ fn construct_fn<'tcx>( ); } - let infcx = tcx.infer_ctxt().build(); + // FIXME(#132279): This should be able to reveal opaque + // types defined during HIR typeck. + let infcx = tcx.infer_ctxt().build(TypingMode::non_body_analysis()); let mut builder = Builder::new( thir, infcx, @@ -578,7 +580,9 @@ fn construct_const<'a, 'tcx>( _ => span_bug!(tcx.def_span(def), "can't build MIR for {:?}", def), }; - let infcx = tcx.infer_ctxt().build(); + // FIXME(#132279): We likely want to be able to use the hidden types of + // opaques used by this function here. + let infcx = tcx.infer_ctxt().build(TypingMode::non_body_analysis()); let mut builder = Builder::new(thir, infcx, def, hir_id, span, 0, const_ty, const_ty_span, None); diff --git a/compiler/rustc_mir_build/src/thir/cx/expr.rs b/compiler/rustc_mir_build/src/thir/cx/expr.rs index e2823456477..d20e5fcf4ec 100644 --- a/compiler/rustc_mir_build/src/thir/cx/expr.rs +++ b/compiler/rustc_mir_build/src/thir/cx/expr.rs @@ -784,7 +784,7 @@ impl<'tcx> Cx<'tcx> { if_then_scope: region::Scope { id: then.hir_id.local_id, data: { - if expr.span.at_least_rust_2024() && tcx.features().if_let_rescope() { + if expr.span.at_least_rust_2024() { region::ScopeData::IfThenRescope } else { region::ScopeData::IfThen diff --git a/compiler/rustc_mir_build/src/thir/pattern/check_match.rs b/compiler/rustc_mir_build/src/thir/pattern/check_match.rs index 8498df59ce6..f222a869c03 100644 --- a/compiler/rustc_mir_build/src/thir/pattern/check_match.rs +++ b/compiler/rustc_mir_build/src/thir/pattern/check_match.rs @@ -79,6 +79,8 @@ enum LetSource { IfLetGuard, LetElse, WhileLet, + Else, + ElseIfLet, } struct MatchVisitor<'p, 'tcx> { @@ -129,15 +131,20 @@ impl<'p, 'tcx> Visitor<'p, 'tcx> for MatchVisitor<'p, 'tcx> { // Give a specific `let_source` for the condition. let let_source = match ex.span.desugaring_kind() { Some(DesugaringKind::WhileLoop) => LetSource::WhileLet, - _ => LetSource::IfLet, + _ => match self.let_source { + LetSource::Else => LetSource::ElseIfLet, + _ => LetSource::IfLet, + }, }; self.with_let_source(let_source, |this| this.visit_expr(&self.thir[cond])); self.with_let_source(LetSource::None, |this| { this.visit_expr(&this.thir[then]); - if let Some(else_) = else_opt { - this.visit_expr(&this.thir[else_]); - } }); + if let Some(else_) = else_opt { + self.with_let_source(LetSource::Else, |this| { + this.visit_expr(&this.thir[else_]) + }); + } return; } ExprKind::Match { scrutinee, scrutinee_hir_id: _, box ref arms, match_source } => { @@ -573,9 +580,13 @@ impl<'p, 'tcx> MatchVisitor<'p, 'tcx> { // and we shouldn't lint. // For let guards inside a match, prefixes might use bindings of the match pattern, // so can't always be moved out. + // For `else if let`, an extra indentation level would be required to move the bindings. // FIXME: Add checking whether the bindings are actually used in the prefix, // and lint if they are not. - if !matches!(self.let_source, LetSource::WhileLet | LetSource::IfLetGuard) { + if !matches!( + self.let_source, + LetSource::WhileLet | LetSource::IfLetGuard | LetSource::ElseIfLet + ) { // Emit the lint let prefix = &chain_refutabilities[..until]; let span_start = prefix[0].unwrap().0; @@ -906,8 +917,8 @@ fn report_irrefutable_let_patterns( } match source { - LetSource::None | LetSource::PlainLet => bug!(), - LetSource::IfLet => emit_diag!(IrrefutableLetPatternsIfLet), + LetSource::None | LetSource::PlainLet | LetSource::Else => bug!(), + LetSource::IfLet | LetSource::ElseIfLet => emit_diag!(IrrefutableLetPatternsIfLet), LetSource::IfLetGuard => emit_diag!(IrrefutableLetPatternsIfLetGuard), LetSource::LetElse => emit_diag!(IrrefutableLetPatternsLetElse), LetSource::WhileLet => emit_diag!(IrrefutableLetPatternsWhileLet), diff --git a/compiler/rustc_mir_build/src/thir/pattern/const_to_pat.rs b/compiler/rustc_mir_build/src/thir/pattern/const_to_pat.rs index 0dfa9168f7c..c89f526aa17 100644 --- a/compiler/rustc_mir_build/src/thir/pattern/const_to_pat.rs +++ b/compiler/rustc_mir_build/src/thir/pattern/const_to_pat.rs @@ -7,7 +7,7 @@ use rustc_infer::traits::Obligation; use rustc_middle::mir; use rustc_middle::mir::interpret::ErrorHandled; use rustc_middle::thir::{FieldPat, Pat, PatKind}; -use rustc_middle::ty::{self, Ty, TyCtxt, TypeVisitableExt, ValTree}; +use rustc_middle::ty::{self, Ty, TyCtxt, TypeVisitableExt, TypingMode, ValTree}; use rustc_span::Span; use rustc_target::abi::{FieldIdx, VariantIdx}; use rustc_trait_selection::traits::ObligationCause; @@ -36,7 +36,9 @@ impl<'a, 'tcx> PatCtxt<'a, 'tcx> { id: hir::HirId, span: Span, ) -> Box<Pat<'tcx>> { - let infcx = self.tcx.infer_ctxt().build(); + // FIXME(#132279): We likely want to be able to reveal the hidden types + // of opaques defined in this function here. + let infcx = self.tcx.infer_ctxt().build(TypingMode::non_body_analysis()); let mut convert = ConstToPat::new(self, id, span, infcx); convert.to_pat(c, ty) } diff --git a/compiler/rustc_mir_dataflow/Cargo.toml b/compiler/rustc_mir_dataflow/Cargo.toml index 7199db677c4..62a69b3464f 100644 --- a/compiler/rustc_mir_dataflow/Cargo.toml +++ b/compiler/rustc_mir_dataflow/Cargo.toml @@ -7,6 +7,7 @@ edition = "2021" # tidy-alphabetical-start polonius-engine = "0.13.0" regex = "1" +rustc_abi = { path = "../rustc_abi" } rustc_ast = { path = "../rustc_ast" } rustc_data_structures = { path = "../rustc_data_structures" } rustc_errors = { path = "../rustc_errors" } diff --git a/compiler/rustc_mir_dataflow/src/drop_flag_effects.rs b/compiler/rustc_mir_dataflow/src/drop_flag_effects.rs index bb53eaf6cbd..e5cddd0e5e4 100644 --- a/compiler/rustc_mir_dataflow/src/drop_flag_effects.rs +++ b/compiler/rustc_mir_dataflow/src/drop_flag_effects.rs @@ -1,5 +1,5 @@ +use rustc_abi::VariantIdx; use rustc_middle::mir::{self, Body, Location, Terminator, TerminatorKind}; -use rustc_target::abi::VariantIdx; use tracing::debug; use super::move_paths::{InitKind, LookupResult, MoveData, MovePathIndex}; diff --git a/compiler/rustc_mir_dataflow/src/elaborate_drops.rs b/compiler/rustc_mir_dataflow/src/elaborate_drops.rs index 7f2a07e2f5e..9a1f000d39d 100644 --- a/compiler/rustc_mir_dataflow/src/elaborate_drops.rs +++ b/compiler/rustc_mir_dataflow/src/elaborate_drops.rs @@ -1,5 +1,6 @@ use std::{fmt, iter}; +use rustc_abi::{FIRST_VARIANT, FieldIdx, VariantIdx}; use rustc_hir::lang_items::LangItem; use rustc_index::Idx; use rustc_middle::mir::patch::MirPatch; @@ -10,7 +11,6 @@ use rustc_middle::ty::util::IntTypeExt; use rustc_middle::ty::{self, GenericArgsRef, Ty, TyCtxt}; use rustc_span::DUMMY_SP; use rustc_span::source_map::Spanned; -use rustc_target::abi::{FIRST_VARIANT, FieldIdx, VariantIdx}; use tracing::{debug, instrument}; /// The value of an inserted drop flag. diff --git a/compiler/rustc_mir_dataflow/src/framework/graphviz.rs b/compiler/rustc_mir_dataflow/src/framework/graphviz.rs index 96a70f4fa5b..bac75b972f9 100644 --- a/compiler/rustc_mir_dataflow/src/framework/graphviz.rs +++ b/compiler/rustc_mir_dataflow/src/framework/graphviz.rs @@ -32,8 +32,11 @@ pub(crate) struct Formatter<'mir, 'tcx, A> where A: Analysis<'tcx>, { - body: &'mir Body<'tcx>, - results: RefCell<Option<Results<'tcx, A>>>, + // The `RefCell` is used because `<Formatter as Labeller>::node_label` + // takes `&self`, but it needs to modify the cursor. This is also the + // reason for the `Formatter`/`BlockFormatter` split; `BlockFormatter` has + // the operations that involve the mutation, i.e. within the `borrow_mut`. + cursor: RefCell<ResultsCursor<'mir, 'tcx, A>>, style: OutputStyle, reachable: BitSet<BasicBlock>, } @@ -48,11 +51,15 @@ where style: OutputStyle, ) -> Self { let reachable = mir::traversal::reachable_as_bitset(body); - Formatter { body, results: Some(results).into(), style, reachable } + Formatter { cursor: results.into_results_cursor(body).into(), style, reachable } + } + + fn body(&self) -> &'mir Body<'tcx> { + self.cursor.borrow().body() } pub(crate) fn into_results(self) -> Results<'tcx, A> { - self.results.into_inner().unwrap() + self.cursor.into_inner().into_results() } } @@ -81,7 +88,7 @@ where type Edge = CfgEdge; fn graph_id(&self) -> dot::Id<'_> { - let name = graphviz_safe_def_name(self.body.source.def_id()); + let name = graphviz_safe_def_name(self.body().source.def_id()); dot::Id::new(format!("graph_for_def_id_{name}")).unwrap() } @@ -90,20 +97,11 @@ where } fn node_label(&self, block: &Self::Node) -> dot::LabelText<'_> { - let mut label = Vec::new(); - self.results.replace_with(|results| { - // `Formatter::result` is a `RefCell<Option<_>>` so we can replace - // the value with `None`, move it into the results cursor, move it - // back out, and return it to the refcell wrapped in `Some`. - let mut fmt = BlockFormatter { - results: results.take().unwrap().into_results_cursor(self.body), - style: self.style, - bg: Background::Light, - }; + let mut cursor = self.cursor.borrow_mut(); + let mut fmt = + BlockFormatter { cursor: &mut cursor, style: self.style, bg: Background::Light }; + let label = fmt.write_node_label(*block).unwrap(); - fmt.write_node_label(&mut label, *block).unwrap(); - Some(fmt.results.into_results()) - }); dot::LabelText::html(String::from_utf8(label).unwrap()) } @@ -112,12 +110,12 @@ where } fn edge_label(&self, e: &Self::Edge) -> dot::LabelText<'_> { - let label = &self.body[e.source].terminator().kind.fmt_successor_labels()[e.index]; + let label = &self.body()[e.source].terminator().kind.fmt_successor_labels()[e.index]; dot::LabelText::label(label.clone()) } } -impl<'mir, 'tcx, A> dot::GraphWalk<'mir> for Formatter<'mir, 'tcx, A> +impl<'tcx, A> dot::GraphWalk<'_> for Formatter<'_, 'tcx, A> where A: Analysis<'tcx>, { @@ -125,7 +123,7 @@ where type Edge = CfgEdge; fn nodes(&self) -> dot::Nodes<'_, Self::Node> { - self.body + self.body() .basic_blocks .indices() .filter(|&idx| self.reachable.contains(idx)) @@ -134,10 +132,10 @@ where } fn edges(&self) -> dot::Edges<'_, Self::Edge> { - self.body - .basic_blocks + let body = self.body(); + body.basic_blocks .indices() - .flat_map(|bb| dataflow_successors(self.body, bb)) + .flat_map(|bb| dataflow_successors(body, bb)) .collect::<Vec<_>>() .into() } @@ -147,20 +145,20 @@ where } fn target(&self, edge: &Self::Edge) -> Self::Node { - self.body[edge.source].terminator().successors().nth(edge.index).unwrap() + self.body()[edge.source].terminator().successors().nth(edge.index).unwrap() } } -struct BlockFormatter<'mir, 'tcx, A> +struct BlockFormatter<'a, 'mir, 'tcx, A> where A: Analysis<'tcx>, { - results: ResultsCursor<'mir, 'tcx, A>, + cursor: &'a mut ResultsCursor<'mir, 'tcx, A>, bg: Background, style: OutputStyle, } -impl<'mir, 'tcx, A> BlockFormatter<'mir, 'tcx, A> +impl<'tcx, A> BlockFormatter<'_, '_, 'tcx, A> where A: Analysis<'tcx>, A::Domain: DebugWithContext<A>, @@ -173,7 +171,9 @@ where bg } - fn write_node_label(&mut self, w: &mut impl io::Write, block: BasicBlock) -> io::Result<()> { + fn write_node_label(&mut self, block: BasicBlock) -> io::Result<Vec<u8>> { + use std::io::Write; + // Sample output: // +-+-----------------------------------------------+ // A | bb4 | @@ -200,6 +200,9 @@ where // attributes. Make sure to test the output before trying to remove the redundancy. // Notably, `align` was found to have no effect when applied only to <table>. + let mut v = vec![]; + let w = &mut v; + let table_fmt = concat!( " border=\"1\"", " cellborder=\"1\"", @@ -219,8 +222,8 @@ where // C: State at start of block self.bg = Background::Light; - self.results.seek_to_block_start(block); - let block_start_state = self.results.get().clone(); + self.cursor.seek_to_block_start(block); + let block_start_state = self.cursor.get().clone(); self.write_row_with_full_state(w, "", "(on start)")?; // D + E: Statement and terminator transfer functions @@ -228,12 +231,12 @@ where // F: State at end of block - let terminator = self.results.body()[block].terminator(); + let terminator = self.cursor.body()[block].terminator(); // Write the full dataflow state immediately after the terminator if it differs from the // state at block entry. - self.results.seek_to_block_end(block); - if self.results.get() != &block_start_state || A::Direction::IS_BACKWARD { + self.cursor.seek_to_block_end(block); + if self.cursor.get() != &block_start_state || A::Direction::IS_BACKWARD { let after_terminator_name = match terminator.kind { mir::TerminatorKind::Call { target: Some(_), .. } => "(on unwind)", _ => "(on end)", @@ -250,8 +253,8 @@ where match terminator.kind { mir::TerminatorKind::Call { destination, .. } => { self.write_row(w, "", "(on successful return)", |this, w, fmt| { - let state_on_unwind = this.results.get().clone(); - this.results.apply_custom_effect(|analysis, state| { + let state_on_unwind = this.cursor.get().clone(); + this.cursor.apply_custom_effect(|analysis, state| { analysis.apply_call_return_effect( state, block, @@ -265,9 +268,9 @@ where colspan = this.style.num_state_columns(), fmt = fmt, diff = diff_pretty( - this.results.get(), + this.cursor.get(), &state_on_unwind, - this.results.analysis() + this.cursor.analysis() ), ) })?; @@ -275,8 +278,8 @@ where mir::TerminatorKind::Yield { resume, resume_arg, .. } => { self.write_row(w, "", "(on yield resume)", |this, w, fmt| { - let state_on_coroutine_drop = this.results.get().clone(); - this.results.apply_custom_effect(|analysis, state| { + let state_on_coroutine_drop = this.cursor.get().clone(); + this.cursor.apply_custom_effect(|analysis, state| { analysis.apply_call_return_effect( state, resume, @@ -290,9 +293,9 @@ where colspan = this.style.num_state_columns(), fmt = fmt, diff = diff_pretty( - this.results.get(), + this.cursor.get(), &state_on_coroutine_drop, - this.results.analysis() + this.cursor.analysis() ), ) })?; @@ -302,8 +305,8 @@ where if !targets.is_empty() => { self.write_row(w, "", "(on successful return)", |this, w, fmt| { - let state_on_unwind = this.results.get().clone(); - this.results.apply_custom_effect(|analysis, state| { + let state_on_unwind = this.cursor.get().clone(); + this.cursor.apply_custom_effect(|analysis, state| { analysis.apply_call_return_effect( state, block, @@ -317,9 +320,9 @@ where colspan = this.style.num_state_columns(), fmt = fmt, diff = diff_pretty( - this.results.get(), + this.cursor.get(), &state_on_unwind, - this.results.analysis() + this.cursor.analysis() ), ) })?; @@ -328,7 +331,9 @@ where _ => {} }; - write!(w, "</table>") + write!(w, "</table>")?; + + Ok(v) } fn write_block_header_simple( @@ -407,9 +412,9 @@ where block: BasicBlock, ) -> io::Result<()> { let diffs = StateDiffCollector::run( - self.results.body(), + self.cursor.body(), block, - self.results.mut_results(), + self.cursor.mut_results(), self.style, ); @@ -420,7 +425,7 @@ where if A::Direction::IS_FORWARD { it.next().unwrap() } else { it.next_back().unwrap() } }; - for (i, statement) in self.results.body()[block].statements.iter().enumerate() { + for (i, statement) in self.cursor.body()[block].statements.iter().enumerate() { let statement_str = format!("{statement:?}"); let index_str = format!("{i}"); @@ -442,7 +447,7 @@ where assert!(diffs_after.is_empty()); assert!(diffs_before.as_ref().map_or(true, ExactSizeIterator::is_empty)); - let terminator = self.results.body()[block].terminator(); + let terminator = self.cursor.body()[block].terminator(); let mut terminator_str = String::new(); terminator.kind.fmt_head(&mut terminator_str).unwrap(); @@ -492,8 +497,8 @@ where mir: &str, ) -> io::Result<()> { self.write_row(w, i, mir, |this, w, fmt| { - let state = this.results.get(); - let analysis = this.results.analysis(); + let state = this.cursor.get(); + let analysis = this.cursor.analysis(); // FIXME: The full state vector can be quite long. It would be nice to split on commas // and use some text wrapping algorithm. diff --git a/compiler/rustc_mir_dataflow/src/framework/mod.rs b/compiler/rustc_mir_dataflow/src/framework/mod.rs index 959f1ea5340..8f81da8bb04 100644 --- a/compiler/rustc_mir_dataflow/src/framework/mod.rs +++ b/compiler/rustc_mir_dataflow/src/framework/mod.rs @@ -7,18 +7,17 @@ //! //! The `impls` module contains several examples of dataflow analyses. //! -//! Create an `Engine` for your analysis using the `into_engine` method on the `Analysis` trait, -//! then call `iterate_to_fixpoint`. From there, you can use a `ResultsCursor` to inspect the -//! fixpoint solution to your dataflow problem, or implement the `ResultsVisitor` interface and use -//! `visit_results`. The following example uses the `ResultsCursor` approach. +//! Then call `iterate_to_fixpoint` on your type that impls `Analysis` to get a `Results`. From +//! there, you can use a `ResultsCursor` to inspect the fixpoint solution to your dataflow problem, +//! or implement the `ResultsVisitor` interface and use `visit_results`. The following example uses +//! the `ResultsCursor` approach. //! //! ```ignore (cross-crate-imports) -//! use rustc_const_eval::dataflow::Analysis; // Makes `into_engine` available. +//! use rustc_const_eval::dataflow::Analysis; // Makes `iterate_to_fixpoint` available. //! //! fn do_my_analysis(tcx: TyCtxt<'tcx>, body: &mir::Body<'tcx>) { //! let analysis = MyAnalysis::new() -//! .into_engine(tcx, body) -//! .iterate_to_fixpoint() +//! .iterate_to_fixpoint(tcx, body, None) //! .into_results_cursor(body); //! //! // Print the dataflow state *after* each statement in the start block. @@ -34,23 +33,29 @@ use std::cmp::Ordering; -use rustc_index::Idx; +use rustc_data_structures::work_queue::WorkQueue; use rustc_index::bit_set::{BitSet, ChunkedBitSet, HybridBitSet}; -use rustc_middle::mir::{self, BasicBlock, CallReturnPlaces, Location, TerminatorEdges}; +use rustc_index::{Idx, IndexVec}; +use rustc_middle::bug; +use rustc_middle::mir::{self, BasicBlock, CallReturnPlaces, Location, TerminatorEdges, traversal}; use rustc_middle::ty::TyCtxt; +use tracing::error; + +use self::results::write_graphviz_results; +use super::fmt::DebugWithContext; mod cursor; mod direction; -mod engine; pub mod fmt; pub mod graphviz; pub mod lattice; +mod results; mod visitor; pub use self::cursor::ResultsCursor; pub use self::direction::{Backward, Direction, Forward}; -pub use self::engine::{Engine, Results}; pub use self::lattice::{JoinSemiLattice, MaybeReachable}; +pub use self::results::Results; pub use self::visitor::{ResultsVisitable, ResultsVisitor, visit_results}; /// Analysis domains are all bitsets of various kinds. This trait holds @@ -223,26 +228,92 @@ pub trait Analysis<'tcx> { /* Extension methods */ - /// Creates an `Engine` to find the fixpoint for this dataflow problem. + /// Finds the fixpoint for this dataflow problem. /// /// You shouldn't need to override this. Its purpose is to enable method chaining like so: /// /// ```ignore (cross-crate-imports) /// let results = MyAnalysis::new(tcx, body) - /// .into_engine(tcx, body, def_id) - /// .iterate_to_fixpoint() + /// .iterate_to_fixpoint(tcx, body, None) /// .into_results_cursor(body); /// ``` - #[inline] - fn into_engine<'mir>( - self, + /// You can optionally add a `pass_name` to the graphviz output for this particular run of a + /// dataflow analysis. Some analyses are run multiple times in the compilation pipeline. + /// Without a `pass_name` to differentiates them, only the results for the latest run will be + /// saved. + fn iterate_to_fixpoint<'mir>( + mut self, tcx: TyCtxt<'tcx>, body: &'mir mir::Body<'tcx>, - ) -> Engine<'mir, 'tcx, Self> + pass_name: Option<&'static str>, + ) -> Results<'tcx, Self> where Self: Sized, + Self::Domain: DebugWithContext<Self>, { - Engine::new(tcx, body, self) + let mut entry_sets = + IndexVec::from_fn_n(|_| self.bottom_value(body), body.basic_blocks.len()); + self.initialize_start_block(body, &mut entry_sets[mir::START_BLOCK]); + + if Self::Direction::IS_BACKWARD && entry_sets[mir::START_BLOCK] != self.bottom_value(body) { + bug!("`initialize_start_block` is not yet supported for backward dataflow analyses"); + } + + let mut dirty_queue: WorkQueue<BasicBlock> = WorkQueue::with_none(body.basic_blocks.len()); + + if Self::Direction::IS_FORWARD { + for (bb, _) in traversal::reverse_postorder(body) { + dirty_queue.insert(bb); + } + } else { + // Reverse post-order on the reverse CFG may generate a better iteration order for + // backward dataflow analyses, but probably not enough to matter. + for (bb, _) in traversal::postorder(body) { + dirty_queue.insert(bb); + } + } + + // `state` is not actually used between iterations; + // this is just an optimization to avoid reallocating + // every iteration. + let mut state = self.bottom_value(body); + while let Some(bb) = dirty_queue.pop() { + let bb_data = &body[bb]; + + // Set the state to the entry state of the block. + // This is equivalent to `state = entry_sets[bb].clone()`, + // but it saves an allocation, thus improving compile times. + state.clone_from(&entry_sets[bb]); + + // Apply the block transfer function, using the cached one if it exists. + let edges = Self::Direction::apply_effects_in_block(&mut self, &mut state, bb, bb_data); + + Self::Direction::join_state_into_successors_of( + &mut self, + body, + &mut state, + bb, + edges, + |target: BasicBlock, state: &Self::Domain| { + let set_changed = entry_sets[target].join(state); + if set_changed { + dirty_queue.insert(target); + } + }, + ); + } + + let results = Results { analysis: self, entry_sets }; + + if tcx.sess.opts.unstable_opts.dump_mir_dataflow { + let (res, results) = write_graphviz_results(tcx, body, results, pass_name); + if let Err(e) = res { + error!("Failed to write graphviz dataflow results: {}", e); + } + results + } else { + results + } } } diff --git a/compiler/rustc_mir_dataflow/src/framework/engine.rs b/compiler/rustc_mir_dataflow/src/framework/results.rs index cbd1083d037..366fcbf33ba 100644 --- a/compiler/rustc_mir_dataflow/src/framework/engine.rs +++ b/compiler/rustc_mir_dataflow/src/framework/results.rs @@ -1,23 +1,19 @@ -//! A solver for dataflow problems. +//! Dataflow analysis results. use std::ffi::OsString; use std::path::PathBuf; -use rustc_data_structures::work_queue::WorkQueue; use rustc_hir::def_id::DefId; use rustc_index::IndexVec; -use rustc_middle::bug; use rustc_middle::mir::{self, BasicBlock, create_dump_file, dump_enabled, traversal}; use rustc_middle::ty::TyCtxt; use rustc_middle::ty::print::with_no_trimmed_paths; use rustc_span::symbol::{Symbol, sym}; -use tracing::{debug, error}; +use tracing::debug; use {rustc_ast as ast, rustc_graphviz as dot}; use super::fmt::DebugWithContext; -use super::{ - Analysis, Direction, JoinSemiLattice, ResultsCursor, ResultsVisitor, graphviz, visit_results, -}; +use super::{Analysis, ResultsCursor, ResultsVisitor, graphviz, visit_results}; use crate::errors::{ DuplicateValuesFor, PathMustEndInFilename, RequiresAnArgument, UnknownFormatter, }; @@ -65,124 +61,17 @@ where body: &'mir mir::Body<'tcx>, vis: &mut impl ResultsVisitor<'mir, 'tcx, Self, Domain = A::Domain>, ) { - let blocks = mir::traversal::reachable(body); + let blocks = traversal::reachable(body); visit_results(body, blocks.map(|(bb, _)| bb), self, vis) } } -/// A solver for dataflow problems. -pub struct Engine<'mir, 'tcx, A> -where - A: Analysis<'tcx>, -{ - tcx: TyCtxt<'tcx>, - body: &'mir mir::Body<'tcx>, - entry_sets: IndexVec<BasicBlock, A::Domain>, - pass_name: Option<&'static str>, - analysis: A, -} - -impl<'mir, 'tcx, A, D> Engine<'mir, 'tcx, A> -where - A: Analysis<'tcx, Domain = D>, - D: Clone + JoinSemiLattice, -{ - /// Creates a new `Engine` to solve a dataflow problem with an arbitrary transfer - /// function. - pub(crate) fn new(tcx: TyCtxt<'tcx>, body: &'mir mir::Body<'tcx>, analysis: A) -> Self { - let mut entry_sets = - IndexVec::from_fn_n(|_| analysis.bottom_value(body), body.basic_blocks.len()); - analysis.initialize_start_block(body, &mut entry_sets[mir::START_BLOCK]); - - if A::Direction::IS_BACKWARD && entry_sets[mir::START_BLOCK] != analysis.bottom_value(body) - { - bug!("`initialize_start_block` is not yet supported for backward dataflow analyses"); - } - - Engine { analysis, tcx, body, pass_name: None, entry_sets } - } - - /// Adds an identifier to the graphviz output for this particular run of a dataflow analysis. - /// - /// Some analyses are run multiple times in the compilation pipeline. Give them a `pass_name` - /// to differentiate them. Otherwise, only the results for the latest run will be saved. - pub fn pass_name(mut self, name: &'static str) -> Self { - self.pass_name = Some(name); - self - } - - /// Computes the fixpoint for this dataflow problem and returns it. - pub fn iterate_to_fixpoint(self) -> Results<'tcx, A> - where - A::Domain: DebugWithContext<A>, - { - let Engine { mut analysis, body, mut entry_sets, tcx, pass_name } = self; - - let mut dirty_queue: WorkQueue<BasicBlock> = WorkQueue::with_none(body.basic_blocks.len()); - - if A::Direction::IS_FORWARD { - for (bb, _) in traversal::reverse_postorder(body) { - dirty_queue.insert(bb); - } - } else { - // Reverse post-order on the reverse CFG may generate a better iteration order for - // backward dataflow analyses, but probably not enough to matter. - for (bb, _) in traversal::postorder(body) { - dirty_queue.insert(bb); - } - } - - // `state` is not actually used between iterations; - // this is just an optimization to avoid reallocating - // every iteration. - let mut state = analysis.bottom_value(body); - while let Some(bb) = dirty_queue.pop() { - let bb_data = &body[bb]; - - // Set the state to the entry state of the block. - // This is equivalent to `state = entry_sets[bb].clone()`, - // but it saves an allocation, thus improving compile times. - state.clone_from(&entry_sets[bb]); - - // Apply the block transfer function, using the cached one if it exists. - let edges = - A::Direction::apply_effects_in_block(&mut analysis, &mut state, bb, bb_data); - - A::Direction::join_state_into_successors_of( - &mut analysis, - body, - &mut state, - bb, - edges, - |target: BasicBlock, state: &A::Domain| { - let set_changed = entry_sets[target].join(state); - if set_changed { - dirty_queue.insert(target); - } - }, - ); - } - - let results = Results { analysis, entry_sets }; - - if tcx.sess.opts.unstable_opts.dump_mir_dataflow { - let (res, results) = write_graphviz_results(tcx, body, results, pass_name); - if let Err(e) = res { - error!("Failed to write graphviz dataflow results: {}", e); - } - results - } else { - results - } - } -} - // Graphviz /// Writes a DOT file containing the results of a dataflow analysis if the user requested it via /// `rustc_mir` attributes and `-Z dump-mir-dataflow`. The `Result` in and the `Results` out are /// the same. -fn write_graphviz_results<'tcx, A>( +pub(super) fn write_graphviz_results<'tcx, A>( tcx: TyCtxt<'tcx>, body: &mir::Body<'tcx>, results: Results<'tcx, A>, diff --git a/compiler/rustc_mir_dataflow/src/lib.rs b/compiler/rustc_mir_dataflow/src/lib.rs index b284f0308f9..b404e3bfb72 100644 --- a/compiler/rustc_mir_dataflow/src/lib.rs +++ b/compiler/rustc_mir_dataflow/src/lib.rs @@ -18,9 +18,9 @@ pub use self::drop_flag_effects::{ move_path_children_matching, on_all_children_bits, on_lookup_result_bits, }; pub use self::framework::{ - Analysis, Backward, Direction, Engine, Forward, GenKill, JoinSemiLattice, MaybeReachable, - Results, ResultsCursor, ResultsVisitable, ResultsVisitor, SwitchIntEdgeEffects, fmt, graphviz, - lattice, visit_results, + Analysis, Backward, Direction, Forward, GenKill, JoinSemiLattice, MaybeReachable, Results, + ResultsCursor, ResultsVisitable, ResultsVisitor, SwitchIntEdgeEffects, fmt, graphviz, lattice, + visit_results, }; use self::move_paths::MoveData; diff --git a/compiler/rustc_mir_dataflow/src/rustc_peek.rs b/compiler/rustc_mir_dataflow/src/rustc_peek.rs index 5727517bd61..99d0ccde105 100644 --- a/compiler/rustc_mir_dataflow/src/rustc_peek.rs +++ b/compiler/rustc_mir_dataflow/src/rustc_peek.rs @@ -43,31 +43,28 @@ pub fn sanity_check<'tcx>(tcx: TyCtxt<'tcx>, body: &Body<'tcx>) { let move_data = MoveData::gather_moves(body, tcx, |_| true); if has_rustc_mir_with(tcx, def_id, sym::rustc_peek_maybe_init).is_some() { - let flow_inits = MaybeInitializedPlaces::new(tcx, body, &move_data) - .into_engine(tcx, body) - .iterate_to_fixpoint(); + let flow_inits = + MaybeInitializedPlaces::new(tcx, body, &move_data).iterate_to_fixpoint(tcx, body, None); sanity_check_via_rustc_peek(tcx, flow_inits.into_results_cursor(body)); } if has_rustc_mir_with(tcx, def_id, sym::rustc_peek_maybe_uninit).is_some() { let flow_uninits = MaybeUninitializedPlaces::new(tcx, body, &move_data) - .into_engine(tcx, body) - .iterate_to_fixpoint(); + .iterate_to_fixpoint(tcx, body, None); sanity_check_via_rustc_peek(tcx, flow_uninits.into_results_cursor(body)); } if has_rustc_mir_with(tcx, def_id, sym::rustc_peek_definite_init).is_some() { - let flow_def_inits = DefinitelyInitializedPlaces::new(body, &move_data) - .into_engine(tcx, body) - .iterate_to_fixpoint(); + let flow_def_inits = + DefinitelyInitializedPlaces::new(body, &move_data).iterate_to_fixpoint(tcx, body, None); sanity_check_via_rustc_peek(tcx, flow_def_inits.into_results_cursor(body)); } if has_rustc_mir_with(tcx, def_id, sym::rustc_peek_liveness).is_some() { - let flow_liveness = MaybeLiveLocals.into_engine(tcx, body).iterate_to_fixpoint(); + let flow_liveness = MaybeLiveLocals.iterate_to_fixpoint(tcx, body, None); sanity_check_via_rustc_peek(tcx, flow_liveness.into_results_cursor(body)); } diff --git a/compiler/rustc_mir_dataflow/src/value_analysis.rs b/compiler/rustc_mir_dataflow/src/value_analysis.rs index d0f62bd82d1..f7d4a082779 100644 --- a/compiler/rustc_mir_dataflow/src/value_analysis.rs +++ b/compiler/rustc_mir_dataflow/src/value_analysis.rs @@ -36,6 +36,7 @@ use std::assert_matches::assert_matches; use std::fmt::{Debug, Formatter}; use std::ops::Range; +use rustc_abi::{FieldIdx, VariantIdx}; use rustc_data_structures::captures::Captures; use rustc_data_structures::fx::{FxHashMap, FxIndexSet, StdEntry}; use rustc_data_structures::stack::ensure_sufficient_stack; @@ -46,7 +47,6 @@ use rustc_middle::mir::tcx::PlaceTy; use rustc_middle::mir::visit::{MutatingUseContext, PlaceContext, Visitor}; use rustc_middle::mir::*; use rustc_middle::ty::{self, Ty, TyCtxt}; -use rustc_target::abi::{FieldIdx, VariantIdx}; use tracing::debug; use crate::fmt::DebugWithContext; diff --git a/compiler/rustc_mir_transform/Cargo.toml b/compiler/rustc_mir_transform/Cargo.toml index 07ca51a67ae..4b648d21084 100644 --- a/compiler/rustc_mir_transform/Cargo.toml +++ b/compiler/rustc_mir_transform/Cargo.toml @@ -7,6 +7,7 @@ edition = "2021" # tidy-alphabetical-start either = "1" itertools = "0.12" +rustc_abi = { path = "../rustc_abi" } rustc_arena = { path = "../rustc_arena" } rustc_ast = { path = "../rustc_ast" } rustc_attr = { path = "../rustc_attr" } diff --git a/compiler/rustc_mir_transform/src/coroutine.rs b/compiler/rustc_mir_transform/src/coroutine.rs index cd291058977..6d5665b4331 100644 --- a/compiler/rustc_mir_transform/src/coroutine.rs +++ b/compiler/rustc_mir_transform/src/coroutine.rs @@ -64,7 +64,7 @@ use rustc_index::{Idx, IndexVec}; use rustc_middle::mir::visit::{MutVisitor, PlaceContext, Visitor}; use rustc_middle::mir::*; use rustc_middle::ty::{ - self, CoroutineArgs, CoroutineArgsExt, GenericArgsRef, InstanceKind, Ty, TyCtxt, + self, CoroutineArgs, CoroutineArgsExt, GenericArgsRef, InstanceKind, Ty, TyCtxt, TypingMode, }; use rustc_middle::{bug, span_bug}; use rustc_mir_dataflow::Analysis; @@ -666,14 +666,13 @@ fn locals_live_across_suspend_points<'tcx>( // Calculate when MIR locals have live storage. This gives us an upper bound of their // lifetimes. let mut storage_live = MaybeStorageLive::new(std::borrow::Cow::Borrowed(always_live_locals)) - .into_engine(tcx, body) - .iterate_to_fixpoint() + .iterate_to_fixpoint(tcx, body, None) .into_results_cursor(body); // Calculate the MIR locals which have been previously // borrowed (even if they are still active). let borrowed_locals_results = - MaybeBorrowedLocals.into_engine(tcx, body).pass_name("coroutine").iterate_to_fixpoint(); + MaybeBorrowedLocals.iterate_to_fixpoint(tcx, body, Some("coroutine")); let mut borrowed_locals_cursor = borrowed_locals_results.clone().into_results_cursor(body); @@ -681,16 +680,12 @@ fn locals_live_across_suspend_points<'tcx>( // for. let mut requires_storage_cursor = MaybeRequiresStorage::new(borrowed_locals_results.into_results_cursor(body)) - .into_engine(tcx, body) - .iterate_to_fixpoint() + .iterate_to_fixpoint(tcx, body, None) .into_results_cursor(body); // Calculate the liveness of MIR locals ignoring borrows. - let mut liveness = MaybeLiveLocals - .into_engine(tcx, body) - .pass_name("coroutine") - .iterate_to_fixpoint() - .into_results_cursor(body); + let mut liveness = + MaybeLiveLocals.iterate_to_fixpoint(tcx, body, Some("coroutine")).into_results_cursor(body); let mut storage_liveness_map = IndexVec::from_elem(None, &body.basic_blocks); let mut live_locals_at_suspension_points = Vec::new(); @@ -1501,7 +1496,11 @@ fn check_field_tys_sized<'tcx>( return; } - let infcx = tcx.infer_ctxt().ignoring_regions().build(); + // FIXME(#132279): @lcnr believes that we may want to support coroutines + // whose `Sized`-ness relies on the hidden types of opaques defined by the + // parent function. In this case we'd have to be able to reveal only these + // opaques here. + let infcx = tcx.infer_ctxt().ignoring_regions().build(TypingMode::non_body_analysis()); let param_env = tcx.param_env(def_id); let ocx = ObligationCtxt::new_with_diagnostics(&infcx); diff --git a/compiler/rustc_mir_transform/src/coverage/counters.rs b/compiler/rustc_mir_transform/src/coverage/counters.rs index 9a533ea024d..cf9f6981c5a 100644 --- a/compiler/rustc_mir_transform/src/coverage/counters.rs +++ b/compiler/rustc_mir_transform/src/coverage/counters.rs @@ -280,13 +280,12 @@ impl<'a> CountersBuilder<'a> { // // The traversal tries to ensure that, when a loop is encountered, all // nodes within the loop are visited before visiting any nodes outside - // the loop. It also keeps track of which loop(s) the traversal is - // currently inside. + // the loop. let mut traversal = TraverseCoverageGraphWithLoops::new(self.graph); while let Some(bcb) = traversal.next() { let _span = debug_span!("traversal", ?bcb).entered(); if self.bcb_needs_counter.contains(bcb) { - self.make_node_counter_and_out_edge_counters(&traversal, bcb); + self.make_node_counter_and_out_edge_counters(bcb); } } @@ -299,12 +298,8 @@ impl<'a> CountersBuilder<'a> { /// Make sure the given node has a node counter, and then make sure each of /// its out-edges has an edge counter (if appropriate). - #[instrument(level = "debug", skip(self, traversal))] - fn make_node_counter_and_out_edge_counters( - &mut self, - traversal: &TraverseCoverageGraphWithLoops<'_>, - from_bcb: BasicCoverageBlock, - ) { + #[instrument(level = "debug", skip(self))] + fn make_node_counter_and_out_edge_counters(&mut self, from_bcb: BasicCoverageBlock) { // First, ensure that this node has a counter of some kind. // We might also use that counter to compute one of the out-edge counters. let node_counter = self.get_or_make_node_counter(from_bcb); @@ -337,8 +332,7 @@ impl<'a> CountersBuilder<'a> { // If there are out-edges without counters, choose one to be given an expression // (computed from this node and the other out-edges) instead of a physical counter. - let Some(target_bcb) = - self.choose_out_edge_for_expression(traversal, &candidate_successors) + let Some(target_bcb) = self.choose_out_edge_for_expression(from_bcb, &candidate_successors) else { return; }; @@ -462,12 +456,12 @@ impl<'a> CountersBuilder<'a> { /// choose one to be given a counter expression instead of a physical counter. fn choose_out_edge_for_expression( &self, - traversal: &TraverseCoverageGraphWithLoops<'_>, + from_bcb: BasicCoverageBlock, candidate_successors: &[BasicCoverageBlock], ) -> Option<BasicCoverageBlock> { // Try to find a candidate that leads back to the top of a loop, // because reloop edges tend to be executed more times than loop-exit edges. - if let Some(reloop_target) = self.find_good_reloop_edge(traversal, &candidate_successors) { + if let Some(reloop_target) = self.find_good_reloop_edge(from_bcb, &candidate_successors) { debug!("Selecting reloop target {reloop_target:?} to get an expression"); return Some(reloop_target); } @@ -486,7 +480,7 @@ impl<'a> CountersBuilder<'a> { /// for them to be able to avoid a physical counter increment. fn find_good_reloop_edge( &self, - traversal: &TraverseCoverageGraphWithLoops<'_>, + from_bcb: BasicCoverageBlock, candidate_successors: &[BasicCoverageBlock], ) -> Option<BasicCoverageBlock> { // If there are no candidates, avoid iterating over the loop stack. @@ -495,14 +489,15 @@ impl<'a> CountersBuilder<'a> { } // Consider each loop on the current traversal context stack, top-down. - for reloop_bcbs in traversal.reloop_bcbs_per_loop() { + for loop_header_node in self.graph.loop_headers_containing(from_bcb) { // Try to find a candidate edge that doesn't exit this loop. for &target_bcb in candidate_successors { // An edge is a reloop edge if its target dominates any BCB that has // an edge back to the loop header. (Otherwise it's an exit edge.) - let is_reloop_edge = reloop_bcbs - .iter() - .any(|&reloop_bcb| self.graph.dominates(target_bcb, reloop_bcb)); + let is_reloop_edge = self + .graph + .reloop_predecessors(loop_header_node) + .any(|reloop_bcb| self.graph.dominates(target_bcb, reloop_bcb)); if is_reloop_edge { // We found a good out-edge to be given an expression. return Some(target_bcb); diff --git a/compiler/rustc_mir_transform/src/coverage/graph.rs b/compiler/rustc_mir_transform/src/coverage/graph.rs index 930fa129ef2..168262bf01c 100644 --- a/compiler/rustc_mir_transform/src/coverage/graph.rs +++ b/compiler/rustc_mir_transform/src/coverage/graph.rs @@ -1,10 +1,11 @@ use std::cmp::Ordering; use std::collections::VecDeque; +use std::iter; use std::ops::{Index, IndexMut}; use rustc_data_structures::captures::Captures; use rustc_data_structures::fx::FxHashSet; -use rustc_data_structures::graph::dominators::{self, Dominators}; +use rustc_data_structures::graph::dominators::Dominators; use rustc_data_structures::graph::{self, DirectedGraph, StartNode}; use rustc_index::IndexVec; use rustc_index::bit_set::BitSet; @@ -20,11 +21,17 @@ pub(crate) struct CoverageGraph { bb_to_bcb: IndexVec<BasicBlock, Option<BasicCoverageBlock>>, pub(crate) successors: IndexVec<BasicCoverageBlock, Vec<BasicCoverageBlock>>, pub(crate) predecessors: IndexVec<BasicCoverageBlock, Vec<BasicCoverageBlock>>, + dominators: Option<Dominators<BasicCoverageBlock>>, /// Allows nodes to be compared in some total order such that _if_ /// `a` dominates `b`, then `a < b`. If neither node dominates the other, /// their relative order is consistent but arbitrary. dominator_order_rank: IndexVec<BasicCoverageBlock, u32>, + /// A loop header is a node that dominates one or more of its predecessors. + is_loop_header: BitSet<BasicCoverageBlock>, + /// For each node, the loop header node of its nearest enclosing loop. + /// This forms a linked list that can be traversed to find all enclosing loops. + enclosing_loop_header: IndexVec<BasicCoverageBlock, Option<BasicCoverageBlock>>, } impl CoverageGraph { @@ -66,17 +73,38 @@ impl CoverageGraph { predecessors, dominators: None, dominator_order_rank: IndexVec::from_elem_n(0, num_nodes), + is_loop_header: BitSet::new_empty(num_nodes), + enclosing_loop_header: IndexVec::from_elem_n(None, num_nodes), }; assert_eq!(num_nodes, this.num_nodes()); - this.dominators = Some(dominators::dominators(&this)); + // Set the dominators first, because later init steps rely on them. + this.dominators = Some(graph::dominators::dominators(&this)); - // The dominator rank of each node is just its index in a reverse-postorder traversal. - let reverse_post_order = graph::iterate::reverse_post_order(&this, this.start_node()); + // Iterate over all nodes, such that dominating nodes are visited before + // the nodes they dominate. Either preorder or reverse postorder is fine. + let dominator_order = graph::iterate::reverse_post_order(&this, this.start_node()); // The coverage graph is created by traversal, so all nodes are reachable. - assert_eq!(reverse_post_order.len(), this.num_nodes()); - for (rank, bcb) in (0u32..).zip(reverse_post_order) { + assert_eq!(dominator_order.len(), this.num_nodes()); + for (rank, bcb) in (0u32..).zip(dominator_order) { + // The dominator rank of each node is its index in a dominator-order traversal. this.dominator_order_rank[bcb] = rank; + + // A node is a loop header if it dominates any of its predecessors. + if this.reloop_predecessors(bcb).next().is_some() { + this.is_loop_header.insert(bcb); + } + + // If the immediate dominator is a loop header, that's our enclosing loop. + // Otherwise, inherit the immediate dominator's enclosing loop. + // (Dominator order ensures that we already processed the dominator.) + if let Some(dom) = this.dominators().immediate_dominator(bcb) { + this.enclosing_loop_header[bcb] = this + .is_loop_header + .contains(dom) + .then_some(dom) + .or_else(|| this.enclosing_loop_header[dom]); + } } // The coverage graph's entry-point node (bcb0) always starts with bb0, @@ -173,8 +201,13 @@ impl CoverageGraph { } #[inline(always)] + fn dominators(&self) -> &Dominators<BasicCoverageBlock> { + self.dominators.as_ref().unwrap() + } + + #[inline(always)] pub(crate) fn dominates(&self, dom: BasicCoverageBlock, node: BasicCoverageBlock) -> bool { - self.dominators.as_ref().unwrap().dominates(dom, node) + self.dominators().dominates(dom, node) } #[inline(always)] @@ -214,6 +247,36 @@ impl CoverageGraph { None } } + + /// For each loop that contains the given node, yields the "loop header" + /// node representing that loop, from innermost to outermost. If the given + /// node is itself a loop header, it is yielded first. + pub(crate) fn loop_headers_containing( + &self, + bcb: BasicCoverageBlock, + ) -> impl Iterator<Item = BasicCoverageBlock> + Captures<'_> { + let self_if_loop_header = self.is_loop_header.contains(bcb).then_some(bcb).into_iter(); + + let mut curr = Some(bcb); + let strictly_enclosing = iter::from_fn(move || { + let enclosing = self.enclosing_loop_header[curr?]; + curr = enclosing; + enclosing + }); + + self_if_loop_header.chain(strictly_enclosing) + } + + /// For the given node, yields the subset of its predecessor nodes that + /// it dominates. If that subset is non-empty, the node is a "loop header", + /// and each of those predecessors represents an in-edge that jumps back to + /// the top of its loop. + pub(crate) fn reloop_predecessors( + &self, + to_bcb: BasicCoverageBlock, + ) -> impl Iterator<Item = BasicCoverageBlock> + Captures<'_> { + self.predecessors[to_bcb].iter().copied().filter(move |&pred| self.dominates(to_bcb, pred)) + } } impl Index<BasicCoverageBlock> for CoverageGraph { @@ -439,15 +502,12 @@ struct TraversalContext { pub(crate) struct TraverseCoverageGraphWithLoops<'a> { basic_coverage_blocks: &'a CoverageGraph, - backedges: IndexVec<BasicCoverageBlock, Vec<BasicCoverageBlock>>, context_stack: Vec<TraversalContext>, visited: BitSet<BasicCoverageBlock>, } impl<'a> TraverseCoverageGraphWithLoops<'a> { pub(crate) fn new(basic_coverage_blocks: &'a CoverageGraph) -> Self { - let backedges = find_loop_backedges(basic_coverage_blocks); - let worklist = VecDeque::from([basic_coverage_blocks.start_node()]); let context_stack = vec![TraversalContext { loop_header: None, worklist }]; @@ -456,17 +516,7 @@ impl<'a> TraverseCoverageGraphWithLoops<'a> { // of the stack as loops are entered, and popped off of the stack when a loop's worklist is // exhausted. let visited = BitSet::new_empty(basic_coverage_blocks.num_nodes()); - Self { basic_coverage_blocks, backedges, context_stack, visited } - } - - /// For each loop on the loop context stack (top-down), yields a list of BCBs - /// within that loop that have an outgoing edge back to the loop header. - pub(crate) fn reloop_bcbs_per_loop(&self) -> impl Iterator<Item = &[BasicCoverageBlock]> { - self.context_stack - .iter() - .rev() - .filter_map(|context| context.loop_header) - .map(|header_bcb| self.backedges[header_bcb].as_slice()) + Self { basic_coverage_blocks, context_stack, visited } } pub(crate) fn next(&mut self) -> Option<BasicCoverageBlock> { @@ -488,7 +538,7 @@ impl<'a> TraverseCoverageGraphWithLoops<'a> { } debug!("Visiting {bcb:?}"); - if self.backedges[bcb].len() > 0 { + if self.basic_coverage_blocks.is_loop_header.contains(bcb) { debug!("{bcb:?} is a loop header! Start a new TraversalContext..."); self.context_stack .push(TraversalContext { loop_header: Some(bcb), worklist: VecDeque::new() }); @@ -566,29 +616,6 @@ impl<'a> TraverseCoverageGraphWithLoops<'a> { } } -fn find_loop_backedges( - basic_coverage_blocks: &CoverageGraph, -) -> IndexVec<BasicCoverageBlock, Vec<BasicCoverageBlock>> { - let num_bcbs = basic_coverage_blocks.num_nodes(); - let mut backedges = IndexVec::from_elem_n(Vec::<BasicCoverageBlock>::new(), num_bcbs); - - // Identify loops by their backedges. - for (bcb, _) in basic_coverage_blocks.iter_enumerated() { - for &successor in &basic_coverage_blocks.successors[bcb] { - if basic_coverage_blocks.dominates(successor, bcb) { - let loop_header = successor; - let backedge_from_bcb = bcb; - debug!( - "Found BCB backedge: {:?} -> loop_header: {:?}", - backedge_from_bcb, loop_header - ); - backedges[loop_header].push(backedge_from_bcb); - } - } - } - backedges -} - fn short_circuit_preorder<'a, 'tcx, F, Iter>( body: &'a mir::Body<'tcx>, filtered_successors: F, diff --git a/compiler/rustc_mir_transform/src/dataflow_const_prop.rs b/compiler/rustc_mir_transform/src/dataflow_const_prop.rs index 002216f50f2..07263460733 100644 --- a/compiler/rustc_mir_transform/src/dataflow_const_prop.rs +++ b/compiler/rustc_mir_transform/src/dataflow_const_prop.rs @@ -59,7 +59,7 @@ impl<'tcx> crate::MirPass<'tcx> for DataflowConstProp { // Perform the actual dataflow analysis. let analysis = ConstAnalysis::new(tcx, body, map); let mut results = debug_span!("analyze") - .in_scope(|| analysis.wrap().into_engine(tcx, body).iterate_to_fixpoint()); + .in_scope(|| analysis.wrap().iterate_to_fixpoint(tcx, body, None)); // Collect results and patch the body afterwards. let mut visitor = Collector::new(tcx, &body.local_decls); diff --git a/compiler/rustc_mir_transform/src/dead_store_elimination.rs b/compiler/rustc_mir_transform/src/dead_store_elimination.rs index edffe6ce78f..2898f82e25c 100644 --- a/compiler/rustc_mir_transform/src/dead_store_elimination.rs +++ b/compiler/rustc_mir_transform/src/dead_store_elimination.rs @@ -37,8 +37,7 @@ fn eliminate<'tcx>(tcx: TyCtxt<'tcx>, body: &mut Body<'tcx>) { always_live.union(&borrowed_locals); let mut live = MaybeTransitiveLiveLocals::new(&always_live) - .into_engine(tcx, body) - .iterate_to_fixpoint() + .iterate_to_fixpoint(tcx, body, None) .into_results_cursor(body); // For blocks with a call terminator, if an argument copy can be turned into a move, diff --git a/compiler/rustc_mir_transform/src/dest_prop.rs b/compiler/rustc_mir_transform/src/dest_prop.rs index ad83c0295ba..beeab0d4a66 100644 --- a/compiler/rustc_mir_transform/src/dest_prop.rs +++ b/compiler/rustc_mir_transform/src/dest_prop.rs @@ -169,10 +169,7 @@ impl<'tcx> crate::MirPass<'tcx> for DestinationPropagation { let borrowed = rustc_mir_dataflow::impls::borrowed_locals(body); - let live = MaybeLiveLocals - .into_engine(tcx, body) - .pass_name("MaybeLiveLocals-DestinationPropagation") - .iterate_to_fixpoint(); + let live = MaybeLiveLocals.iterate_to_fixpoint(tcx, body, Some("MaybeLiveLocals-DestProp")); let points = DenseLocationMap::new(body); let mut live = save_as_intervals(&points, body, live); diff --git a/compiler/rustc_mir_transform/src/elaborate_drops.rs b/compiler/rustc_mir_transform/src/elaborate_drops.rs index 30e1ac05e03..58e1db19438 100644 --- a/compiler/rustc_mir_transform/src/elaborate_drops.rs +++ b/compiler/rustc_mir_transform/src/elaborate_drops.rs @@ -64,18 +64,14 @@ impl<'tcx> crate::MirPass<'tcx> for ElaborateDrops { let mut inits = MaybeInitializedPlaces::new(tcx, body, &env.move_data) .skipping_unreachable_unwind() - .into_engine(tcx, body) - .pass_name("elaborate_drops") - .iterate_to_fixpoint() + .iterate_to_fixpoint(tcx, body, Some("elaborate_drops")) .into_results_cursor(body); let dead_unwinds = compute_dead_unwinds(body, &mut inits); let uninits = MaybeUninitializedPlaces::new(tcx, body, &env.move_data) .mark_inactive_variants_as_uninit() .skipping_unreachable_unwind(dead_unwinds) - .into_engine(tcx, body) - .pass_name("elaborate_drops") - .iterate_to_fixpoint() + .iterate_to_fixpoint(tcx, body, Some("elaborate_drops")) .into_results_cursor(body); let drop_flags = IndexVec::from_elem(None, &env.move_data.move_paths); diff --git a/compiler/rustc_mir_transform/src/lint.rs b/compiler/rustc_mir_transform/src/lint.rs index 23733994a8b..d8ff1cfc90b 100644 --- a/compiler/rustc_mir_transform/src/lint.rs +++ b/compiler/rustc_mir_transform/src/lint.rs @@ -17,13 +17,11 @@ pub(super) fn lint_body<'tcx>(tcx: TyCtxt<'tcx>, body: &Body<'tcx>, when: String let always_live_locals = &always_storage_live_locals(body); let maybe_storage_live = MaybeStorageLive::new(Cow::Borrowed(always_live_locals)) - .into_engine(tcx, body) - .iterate_to_fixpoint() + .iterate_to_fixpoint(tcx, body, None) .into_results_cursor(body); let maybe_storage_dead = MaybeStorageDead::new(Cow::Borrowed(always_live_locals)) - .into_engine(tcx, body) - .iterate_to_fixpoint() + .iterate_to_fixpoint(tcx, body, None) .into_results_cursor(body); let mut lint = Lint { diff --git a/compiler/rustc_mir_transform/src/ref_prop.rs b/compiler/rustc_mir_transform/src/ref_prop.rs index 53e53d9d5ba..b11b503e8d4 100644 --- a/compiler/rustc_mir_transform/src/ref_prop.rs +++ b/compiler/rustc_mir_transform/src/ref_prop.rs @@ -126,8 +126,7 @@ fn compute_replacement<'tcx>( // Compute `MaybeStorageDead` dataflow to check that we only replace when the pointee is // definitely live. let mut maybe_dead = MaybeStorageDead::new(Cow::Owned(always_live_locals)) - .into_engine(tcx, body) - .iterate_to_fixpoint() + .iterate_to_fixpoint(tcx, body, None) .into_results_cursor(body); // Map for each local to the pointee. diff --git a/compiler/rustc_mir_transform/src/remove_uninit_drops.rs b/compiler/rustc_mir_transform/src/remove_uninit_drops.rs index 09969a4c7cc..55dd96100b0 100644 --- a/compiler/rustc_mir_transform/src/remove_uninit_drops.rs +++ b/compiler/rustc_mir_transform/src/remove_uninit_drops.rs @@ -22,9 +22,7 @@ impl<'tcx> crate::MirPass<'tcx> for RemoveUninitDrops { let move_data = MoveData::gather_moves(body, tcx, |ty| ty.needs_drop(tcx, param_env)); let mut maybe_inits = MaybeInitializedPlaces::new(tcx, body, &move_data) - .into_engine(tcx, body) - .pass_name("remove_uninit_drops") - .iterate_to_fixpoint() + .iterate_to_fixpoint(tcx, body, Some("remove_uninit_drops")) .into_results_cursor(body); let mut to_remove = vec![]; diff --git a/compiler/rustc_mir_transform/src/unreachable_enum_branching.rs b/compiler/rustc_mir_transform/src/unreachable_enum_branching.rs index 5612e779d6b..3011af4d9d7 100644 --- a/compiler/rustc_mir_transform/src/unreachable_enum_branching.rs +++ b/compiler/rustc_mir_transform/src/unreachable_enum_branching.rs @@ -1,5 +1,6 @@ //! A pass that eliminates branches on uninhabited or unreachable enum variants. +use rustc_abi::Variants; use rustc_data_structures::fx::FxHashSet; use rustc_middle::bug; use rustc_middle::mir::patch::MirPatch; @@ -9,7 +10,6 @@ use rustc_middle::mir::{ }; use rustc_middle::ty::layout::TyAndLayout; use rustc_middle::ty::{Ty, TyCtxt}; -use rustc_target::abi::{Abi, Variants}; use tracing::trace; pub(super) struct UnreachableEnumBranching; @@ -65,7 +65,7 @@ fn variant_discriminants<'tcx>( Variants::Multiple { variants, .. } => variants .iter_enumerated() .filter_map(|(idx, layout)| { - (layout.abi != Abi::Uninhabited) + (!layout.is_uninhabited()) .then(|| ty.discriminant_for_variant(tcx, idx).unwrap().val) }) .collect(), diff --git a/compiler/rustc_mir_transform/src/validate.rs b/compiler/rustc_mir_transform/src/validate.rs index 25e68f44456..77356723c46 100644 --- a/compiler/rustc_mir_transform/src/validate.rs +++ b/compiler/rustc_mir_transform/src/validate.rs @@ -12,7 +12,7 @@ use rustc_middle::mir::*; use rustc_middle::ty::adjustment::PointerCoercion; use rustc_middle::ty::{ self, CoroutineArgsExt, InstanceKind, ParamEnv, ScalarInt, Ty, TyCtxt, TypeVisitableExt, - Variance, + TypingMode, Variance, }; use rustc_middle::{bug, span_bug}; use rustc_target::abi::{FIRST_VARIANT, Size}; @@ -606,7 +606,7 @@ impl<'a, 'tcx> TypeChecker<'a, 'tcx> { return true; } - let infcx = self.tcx.infer_ctxt().build(); + let infcx = self.tcx.infer_ctxt().build(TypingMode::from_param_env(self.param_env)); let ocx = ObligationCtxt::new(&infcx); ocx.register_obligation(Obligation::new( self.tcx, diff --git a/compiler/rustc_next_trait_solver/src/delegate.rs b/compiler/rustc_next_trait_solver/src/delegate.rs index 4da1e7fa711..f7fbfed5b8e 100644 --- a/compiler/rustc_next_trait_solver/src/delegate.rs +++ b/compiler/rustc_next_trait_solver/src/delegate.rs @@ -1,7 +1,7 @@ use std::ops::Deref; use rustc_type_ir::fold::TypeFoldable; -use rustc_type_ir::solve::{Certainty, Goal, NoSolution, SolverMode}; +use rustc_type_ir::solve::{Certainty, Goal, NoSolution}; use rustc_type_ir::{self as ty, InferCtxtLike, Interner}; pub trait SolverDelegate: Deref<Target = <Self as SolverDelegate>::Infcx> + Sized { @@ -15,7 +15,6 @@ pub trait SolverDelegate: Deref<Target = <Self as SolverDelegate>::Infcx> + Size fn build_with_canonical<V>( cx: Self::Interner, - solver_mode: SolverMode, canonical: &ty::CanonicalQueryInput<Self::Interner, V>, ) -> (Self, V, ty::CanonicalVarValues<Self::Interner>) where @@ -93,7 +92,6 @@ pub trait SolverDelegate: Deref<Target = <Self as SolverDelegate>::Infcx> + Size fn fetch_eligible_assoc_item( &self, - param_env: <Self::Interner as Interner>::ParamEnv, goal_trait_ref: ty::TraitRef<Self::Interner>, trait_assoc_def_id: <Self::Interner as Interner>::DefId, impl_def_id: <Self::Interner as Interner>::DefId, diff --git a/compiler/rustc_next_trait_solver/src/solve/assembly/mod.rs b/compiler/rustc_next_trait_solver/src/solve/assembly/mod.rs index f6a5f20a639..ebf7372926f 100644 --- a/compiler/rustc_next_trait_solver/src/solve/assembly/mod.rs +++ b/compiler/rustc_next_trait_solver/src/solve/assembly/mod.rs @@ -8,14 +8,14 @@ use rustc_type_ir::inherent::*; use rustc_type_ir::lang_items::TraitSolverLangItem; use rustc_type_ir::solve::inspect; use rustc_type_ir::visit::TypeVisitableExt as _; -use rustc_type_ir::{self as ty, Interner, Upcast as _, elaborate}; +use rustc_type_ir::{self as ty, Interner, TypingMode, Upcast as _, elaborate}; use tracing::{debug, instrument}; use crate::delegate::SolverDelegate; use crate::solve::inspect::ProbeKind; use crate::solve::{ BuiltinImplSource, CandidateSource, CanonicalResponse, Certainty, EvalCtxt, Goal, GoalSource, - MaybeCause, NoSolution, QueryResult, SolverMode, + MaybeCause, NoSolution, QueryResult, }; /// A candidate is a possible way to prove a goal. @@ -328,11 +328,12 @@ where let mut candidates = vec![]; - if self.solver_mode() == SolverMode::Coherence { + if let TypingMode::Coherence = self.typing_mode(goal.param_env) { if let Ok(candidate) = self.consider_coherence_unknowable_candidate(goal) { return vec![candidate]; } } + self.assemble_impl_candidates(goal, &mut candidates); self.assemble_builtin_impl_candidates(goal, &mut candidates); @@ -343,8 +344,11 @@ where self.assemble_param_env_candidates(goal, &mut candidates); - if self.solver_mode() == SolverMode::Normal { - self.discard_impls_shadowed_by_env(goal, &mut candidates); + match self.typing_mode(goal.param_env) { + TypingMode::Coherence => {} + TypingMode::Analysis { .. } | TypingMode::PostAnalysis => { + self.discard_impls_shadowed_by_env(goal, &mut candidates); + } } candidates diff --git a/compiler/rustc_next_trait_solver/src/solve/eval_ctxt/canonical.rs b/compiler/rustc_next_trait_solver/src/solve/eval_ctxt/canonical.rs index e2fd0dd2a25..2f50070d438 100644 --- a/compiler/rustc_next_trait_solver/src/solve/eval_ctxt/canonical.rs +++ b/compiler/rustc_next_trait_solver/src/solve/eval_ctxt/canonical.rs @@ -55,6 +55,7 @@ where &self, goal: Goal<I, T>, ) -> (Vec<I::GenericArg>, CanonicalInput<I, T>) { + let param_env_for_debug_assertion = goal.param_env; let opaque_types = self.delegate.clone_opaque_types_for_query_response(); let (goal, opaque_types) = (goal, opaque_types).fold_with(&mut EagerResolver::new(self.delegate)); @@ -73,7 +74,7 @@ where ); let query_input = ty::CanonicalQueryInput { canonical, - defining_opaque_types: self.delegate.defining_opaque_types(), + typing_mode: self.typing_mode(param_env_for_debug_assertion), }; (orig_values, query_input) } diff --git a/compiler/rustc_next_trait_solver/src/solve/eval_ctxt/mod.rs b/compiler/rustc_next_trait_solver/src/solve/eval_ctxt/mod.rs index 7608253882a..8685896715e 100644 --- a/compiler/rustc_next_trait_solver/src/solve/eval_ctxt/mod.rs +++ b/compiler/rustc_next_trait_solver/src/solve/eval_ctxt/mod.rs @@ -10,7 +10,7 @@ use rustc_type_ir::inherent::*; use rustc_type_ir::relate::Relate; use rustc_type_ir::relate::solver_relating::RelateExt; use rustc_type_ir::visit::{TypeSuperVisitable, TypeVisitable, TypeVisitableExt, TypeVisitor}; -use rustc_type_ir::{self as ty, CanonicalVarValues, InferCtxtLike, Interner}; +use rustc_type_ir::{self as ty, CanonicalVarValues, InferCtxtLike, Interner, TypingMode}; use rustc_type_ir_macros::{Lift_Generic, TypeFoldable_Generic, TypeVisitable_Generic}; use tracing::{instrument, trace}; @@ -21,7 +21,6 @@ use crate::solve::search_graph::SearchGraph; use crate::solve::{ CanonicalInput, Certainty, FIXPOINT_STEP_LIMIT, Goal, GoalEvaluationKind, GoalSource, HasChanged, NestedNormalizationGoals, NoSolution, PredefinedOpaquesData, QueryResult, - SolverMode, }; pub(super) mod canonical; @@ -215,8 +214,8 @@ where D: SolverDelegate<Interner = I>, I: Interner, { - pub(super) fn solver_mode(&self) -> SolverMode { - self.search_graph.solver_mode() + pub(super) fn typing_mode(&self, param_env_for_debug_assertion: I::ParamEnv) -> TypingMode<I> { + self.delegate.typing_mode(param_env_for_debug_assertion) } pub(super) fn set_is_normalizes_to_goal(&mut self) { @@ -232,7 +231,7 @@ where generate_proof_tree: GenerateProofTree, f: impl FnOnce(&mut EvalCtxt<'_, D>) -> R, ) -> (R, Option<inspect::GoalEvaluation<I>>) { - let mut search_graph = SearchGraph::new(delegate.solver_mode(), root_depth); + let mut search_graph = SearchGraph::new(root_depth); let mut ecx = EvalCtxt { delegate, @@ -279,7 +278,7 @@ where f: impl FnOnce(&mut EvalCtxt<'_, D>, Goal<I, I::Predicate>) -> R, ) -> R { let (ref delegate, input, var_values) = - SolverDelegate::build_with_canonical(cx, search_graph.solver_mode(), &canonical_input); + SolverDelegate::build_with_canonical(cx, &canonical_input); let mut ecx = EvalCtxt { delegate, @@ -942,21 +941,11 @@ where pub(super) fn fetch_eligible_assoc_item( &self, - param_env: I::ParamEnv, goal_trait_ref: ty::TraitRef<I>, trait_assoc_def_id: I::DefId, impl_def_id: I::DefId, ) -> Result<Option<I::DefId>, NoSolution> { - self.delegate.fetch_eligible_assoc_item( - param_env, - goal_trait_ref, - trait_assoc_def_id, - impl_def_id, - ) - } - - pub(super) fn can_define_opaque_ty(&self, def_id: I::LocalDefId) -> bool { - self.delegate.defining_opaque_types().contains(&def_id) + self.delegate.fetch_eligible_assoc_item(goal_trait_ref, trait_assoc_def_id, impl_def_id) } pub(super) fn insert_hidden_type( diff --git a/compiler/rustc_next_trait_solver/src/solve/normalizes_to/mod.rs b/compiler/rustc_next_trait_solver/src/solve/normalizes_to/mod.rs index 7287cdf74bf..129744b4db7 100644 --- a/compiler/rustc_next_trait_solver/src/solve/normalizes_to/mod.rs +++ b/compiler/rustc_next_trait_solver/src/solve/normalizes_to/mod.rs @@ -6,7 +6,7 @@ mod weak_types; use rustc_type_ir::fast_reject::DeepRejectCtxt; use rustc_type_ir::inherent::*; use rustc_type_ir::lang_items::TraitSolverLangItem; -use rustc_type_ir::{self as ty, Interner, NormalizesTo, Upcast as _}; +use rustc_type_ir::{self as ty, Interner, NormalizesTo, TypingMode, Upcast as _}; use tracing::instrument; use crate::delegate::SolverDelegate; @@ -15,7 +15,7 @@ use crate::solve::assembly::{self, Candidate}; use crate::solve::inspect::ProbeKind; use crate::solve::{ BuiltinImplSource, CandidateSource, Certainty, EvalCtxt, Goal, GoalSource, MaybeCause, - NoSolution, QueryResult, Reveal, + NoSolution, QueryResult, }; impl<D, I> EvalCtxt<'_, D> @@ -71,21 +71,21 @@ where Ok(()) } ty::AliasTermKind::OpaqueTy => { - match param_env.reveal() { - // In user-facing mode, paques are only rigid if we may not define it. - Reveal::UserFacing => { + match self.typing_mode(param_env) { + // Opaques are never rigid outside of analysis mode. + TypingMode::Coherence | TypingMode::PostAnalysis => Err(NoSolution), + // During analysis, opaques are only rigid if we may not define it. + TypingMode::Analysis { defining_opaque_types } => { if rigid_alias .def_id .as_local() - .is_some_and(|def_id| self.can_define_opaque_ty(def_id)) + .is_some_and(|def_id| defining_opaque_types.contains(&def_id)) { Err(NoSolution) } else { Ok(()) } } - // Opaques are never rigid in reveal-all mode. - Reveal::All => Err(NoSolution), } } // FIXME(generic_const_exprs): we would need to support generic consts here @@ -252,7 +252,6 @@ where // return ambiguity this would otherwise be incomplete, resulting in // unsoundness during coherence (#105782). let Some(target_item_def_id) = ecx.fetch_eligible_assoc_item( - goal.param_env, goal_trait_ref, goal.predicate.def_id(), impl_def_id, diff --git a/compiler/rustc_next_trait_solver/src/solve/normalizes_to/opaque_types.rs b/compiler/rustc_next_trait_solver/src/solve/normalizes_to/opaque_types.rs index f8d51f304f3..d1d701695ab 100644 --- a/compiler/rustc_next_trait_solver/src/solve/normalizes_to/opaque_types.rs +++ b/compiler/rustc_next_trait_solver/src/solve/normalizes_to/opaque_types.rs @@ -4,12 +4,10 @@ use rustc_index::bit_set::GrowableBitSet; use rustc_type_ir::inherent::*; -use rustc_type_ir::{self as ty, Interner}; +use rustc_type_ir::{self as ty, Interner, TypingMode}; use crate::delegate::SolverDelegate; -use crate::solve::{ - Certainty, EvalCtxt, Goal, NoSolution, QueryResult, Reveal, SolverMode, inspect, -}; +use crate::solve::{Certainty, EvalCtxt, Goal, NoSolution, QueryResult, inspect}; impl<D, I> EvalCtxt<'_, D> where @@ -24,17 +22,27 @@ where let opaque_ty = goal.predicate.alias; let expected = goal.predicate.term.as_type().expect("no such thing as an opaque const"); - match (goal.param_env.reveal(), self.solver_mode()) { - (Reveal::UserFacing, SolverMode::Normal) => { - let Some(opaque_ty_def_id) = opaque_ty.def_id.as_local() else { + match self.typing_mode(goal.param_env) { + TypingMode::Coherence => { + // An impossible opaque type bound is the only way this goal will fail + // e.g. assigning `impl Copy := NotCopy` + self.add_item_bounds_for_hidden_type( + opaque_ty.def_id, + opaque_ty.args, + goal.param_env, + expected, + ); + self.evaluate_added_goals_and_make_canonical_response(Certainty::AMBIGUOUS) + } + TypingMode::Analysis { defining_opaque_types } => { + let Some(def_id) = opaque_ty.def_id.as_local() else { return Err(NoSolution); }; - // FIXME: at some point we should call queries without defining - // new opaque types but having the existing opaque type definitions. - // This will require moving this below "Prefer opaques registered already". - if !self.can_define_opaque_ty(opaque_ty_def_id) { + + if !defining_opaque_types.contains(&def_id) { return Err(NoSolution); } + // FIXME: This may have issues when the args contain aliases... match uses_unique_placeholders_ignoring_regions(self.cx(), opaque_ty.args) { Err(NotUniqueParam::NotParam(param)) if param.is_non_region_infer() => { @@ -48,8 +56,7 @@ where Ok(()) => {} } // Prefer opaques registered already. - let opaque_type_key = - ty::OpaqueTypeKey { def_id: opaque_ty_def_id, args: opaque_ty.args }; + let opaque_type_key = ty::OpaqueTypeKey { def_id, args: opaque_ty.args }; // FIXME: This also unifies the previous hidden type with the expected. // // If that fails, we insert `expected` as a new hidden type instead of @@ -69,7 +76,7 @@ where } ecx.eq(goal.param_env, candidate_ty, expected)?; ecx.add_item_bounds_for_hidden_type( - candidate_key.def_id.into(), + def_id.into(), candidate_key.args, goal.param_env, candidate_ty, @@ -82,25 +89,14 @@ where // FIXME: should we use `inject_hidden_type_unchecked` here? self.insert_hidden_type(opaque_type_key, goal.param_env, expected)?; self.add_item_bounds_for_hidden_type( - opaque_ty.def_id, + def_id.into(), opaque_ty.args, goal.param_env, expected, ); self.evaluate_added_goals_and_make_canonical_response(Certainty::Yes) } - (Reveal::UserFacing, SolverMode::Coherence) => { - // An impossible opaque type bound is the only way this goal will fail - // e.g. assigning `impl Copy := NotCopy` - self.add_item_bounds_for_hidden_type( - opaque_ty.def_id, - opaque_ty.args, - goal.param_env, - expected, - ); - self.evaluate_added_goals_and_make_canonical_response(Certainty::AMBIGUOUS) - } - (Reveal::All, _) => { + TypingMode::PostAnalysis => { // FIXME: Add an assertion that opaque type storage is empty. let actual = cx.type_of(opaque_ty.def_id).instantiate(cx, opaque_ty.args); self.eq(goal.param_env, expected, actual)?; diff --git a/compiler/rustc_next_trait_solver/src/solve/trait_goals.rs b/compiler/rustc_next_trait_solver/src/solve/trait_goals.rs index 08cc89d950e..e23e475a2a6 100644 --- a/compiler/rustc_next_trait_solver/src/solve/trait_goals.rs +++ b/compiler/rustc_next_trait_solver/src/solve/trait_goals.rs @@ -6,7 +6,7 @@ use rustc_type_ir::fast_reject::DeepRejectCtxt; use rustc_type_ir::inherent::*; use rustc_type_ir::lang_items::TraitSolverLangItem; use rustc_type_ir::visit::TypeVisitableExt as _; -use rustc_type_ir::{self as ty, Interner, TraitPredicate, Upcast as _, elaborate}; +use rustc_type_ir::{self as ty, Interner, TraitPredicate, TypingMode, Upcast as _, elaborate}; use tracing::{instrument, trace}; use crate::delegate::SolverDelegate; @@ -15,7 +15,7 @@ use crate::solve::assembly::{self, Candidate}; use crate::solve::inspect::ProbeKind; use crate::solve::{ BuiltinImplSource, CandidateSource, Certainty, EvalCtxt, Goal, GoalSource, MaybeCause, - NoSolution, QueryResult, Reveal, SolverMode, + NoSolution, QueryResult, }; impl<D, I> assembly::GoalKind<D> for TraitPredicate<I> @@ -67,9 +67,9 @@ where let maximal_certainty = match (impl_polarity, goal.predicate.polarity) { // In intercrate mode, this is ambiguous. But outside of intercrate, // it's not a real impl. - (ty::ImplPolarity::Reservation, _) => match ecx.solver_mode() { - SolverMode::Coherence => Certainty::AMBIGUOUS, - SolverMode::Normal => return Err(NoSolution), + (ty::ImplPolarity::Reservation, _) => match ecx.typing_mode(goal.param_env) { + TypingMode::Coherence => Certainty::AMBIGUOUS, + TypingMode::Analysis { .. } | TypingMode::PostAnalysis => return Err(NoSolution), }, // Impl matches polarity @@ -167,30 +167,26 @@ where return result; } - // Don't call `type_of` on a local TAIT that's in the defining scope, - // since that may require calling `typeck` on the same item we're + // We only look into opaque types during analysis for opaque types + // outside of their defining scope. Doing so for opaques in the + // defining scope may require calling `typeck` on the same item we're // currently type checking, which will result in a fatal cycle that // ideally we want to avoid, since we can make progress on this goal // via an alias bound or a locally-inferred hidden type instead. - // - // Also, don't call `type_of` on a TAIT in `Reveal::All` mode, since - // we already normalize the self type in - // `assemble_candidates_after_normalizing_self_ty`, and we'd - // just be registering an identical candidate here. - // - // We always return `Err(NoSolution)` here in `SolverMode::Coherence` - // since we'll always register an ambiguous candidate in - // `assemble_candidates_after_normalizing_self_ty` due to normalizing - // the TAIT. if let ty::Alias(ty::Opaque, opaque_ty) = goal.predicate.self_ty().kind() { - if matches!(goal.param_env.reveal(), Reveal::All) - || matches!(ecx.solver_mode(), SolverMode::Coherence) - || opaque_ty - .def_id - .as_local() - .is_some_and(|def_id| ecx.can_define_opaque_ty(def_id)) - { - return Err(NoSolution); + match ecx.typing_mode(goal.param_env) { + TypingMode::Coherence | TypingMode::PostAnalysis => { + unreachable!("rigid opaque outside of analysis: {goal:?}"); + } + TypingMode::Analysis { defining_opaque_types } => { + if opaque_ty + .def_id + .as_local() + .is_some_and(|def_id| defining_opaque_types.contains(&def_id)) + { + return Err(NoSolution); + } + } } } diff --git a/compiler/rustc_parse/src/parser/diagnostics.rs b/compiler/rustc_parse/src/parser/diagnostics.rs index a9384501547..a1fe5508970 100644 --- a/compiler/rustc_parse/src/parser/diagnostics.rs +++ b/compiler/rustc_parse/src/parser/diagnostics.rs @@ -14,6 +14,7 @@ use rustc_ast::{ }; use rustc_ast_pretty::pprust; use rustc_data_structures::fx::FxHashSet; +use rustc_data_structures::sync::Lrc; use rustc_errors::{ Applicability, Diag, DiagCtxtHandle, ErrorGuaranteed, FatalError, PErr, PResult, Subdiagnostic, Suggestions, pluralize, @@ -2437,7 +2438,7 @@ impl<'a> Parser<'a> { let mut labels = vec![]; while let TokenKind::Interpolated(nt) = &tok.kind { let tokens = nt.tokens(); - labels.push(nt.clone()); + labels.push(Lrc::clone(nt)); if let Some(tokens) = tokens && let tokens = tokens.to_attr_token_stream() && let tokens = tokens.0.deref() diff --git a/compiler/rustc_parse/src/parser/mod.rs b/compiler/rustc_parse/src/parser/mod.rs index 77ad4fdeeb1..50a8b6542df 100644 --- a/compiler/rustc_parse/src/parser/mod.rs +++ b/compiler/rustc_parse/src/parser/mod.rs @@ -424,7 +424,7 @@ impl TokenDescription { } } -pub(super) fn token_descr(token: &Token) -> String { +pub fn token_descr(token: &Token) -> String { let name = pprust::token_to_string(token).to_string(); let kind = match (TokenDescription::from_token(token), &token.kind) { diff --git a/compiler/rustc_passes/Cargo.toml b/compiler/rustc_passes/Cargo.toml index b45a8dae277..ed5991459ac 100644 --- a/compiler/rustc_passes/Cargo.toml +++ b/compiler/rustc_passes/Cargo.toml @@ -5,6 +5,7 @@ edition = "2021" [dependencies] # tidy-alphabetical-start +rustc_abi = { path = "../rustc_abi" } rustc_ast = { path = "../rustc_ast" } rustc_ast_pretty = { path = "../rustc_ast_pretty" } rustc_attr = { path = "../rustc_attr" } diff --git a/compiler/rustc_passes/messages.ftl b/compiler/rustc_passes/messages.ftl index f8ef423a9b0..e5e70ba2033 100644 --- a/compiler/rustc_passes/messages.ftl +++ b/compiler/rustc_passes/messages.ftl @@ -622,6 +622,10 @@ passes_remove_fields = passes_repr_align_function = `repr(align)` attributes on functions are unstable +passes_repr_align_greater_than_target_max = + alignment must not be greater than `isize::MAX` bytes + .note = `isize::MAX` is {$size} for the current target + passes_repr_conflicting = conflicting representation hints diff --git a/compiler/rustc_passes/src/check_attr.rs b/compiler/rustc_passes/src/check_attr.rs index ed0d7ed8acc..0a2926c0404 100644 --- a/compiler/rustc_passes/src/check_attr.rs +++ b/compiler/rustc_passes/src/check_attr.rs @@ -25,7 +25,7 @@ use rustc_middle::middle::resolve_bound_vars::ObjectLifetimeDefault; use rustc_middle::query::Providers; use rustc_middle::traits::ObligationCause; use rustc_middle::ty::error::{ExpectedFound, TypeError}; -use rustc_middle::ty::{self, TyCtxt}; +use rustc_middle::ty::{self, TyCtxt, TypingMode}; use rustc_middle::{bug, span_bug}; use rustc_session::lint::builtin::{ CONFLICTING_REPR_HINTS, INVALID_DOC_ATTRIBUTES, INVALID_MACRO_EXPORT_ARGUMENTS, @@ -34,6 +34,7 @@ use rustc_session::lint::builtin::{ use rustc_session::parse::feature_err; use rustc_span::symbol::{Symbol, kw, sym}; use rustc_span::{BytePos, DUMMY_SP, Span}; +use rustc_target::abi::Size; use rustc_target::spec::abi::Abi; use rustc_trait_selection::error_reporting::InferCtxtErrorExt; use rustc_trait_selection::infer::{TyCtxtInferExt, ValuePairs}; @@ -262,7 +263,7 @@ impl<'tcx> CheckAttrVisitor<'tcx> { | sym::cfg_attr // need to be fixed | sym::cfi_encoding // FIXME(cfi_encoding) - | sym::pointee // FIXME(derive_smart_pointer) + | sym::pointee // FIXME(derive_coerce_pointee) | sym::omit_gdb_pretty_printer_section // FIXME(omit_gdb_pretty_printer_section) | sym::used // handled elsewhere to restrict to static items | sym::repr // handled elsewhere to restrict to type decls items @@ -1785,7 +1786,7 @@ impl<'tcx> CheckAttrVisitor<'tcx> { | Target::Union | Target::Enum | Target::Fn - | Target::Method(_) => continue, + | Target::Method(_) => {} _ => { self.dcx().emit_err( errors::AttrApplication::StructEnumFunctionMethodUnion { @@ -1795,6 +1796,8 @@ impl<'tcx> CheckAttrVisitor<'tcx> { ); } } + + self.check_align_value(hint); } sym::packed => { if target != Target::Struct && target != Target::Union { @@ -1892,6 +1895,45 @@ impl<'tcx> CheckAttrVisitor<'tcx> { } } + fn check_align_value(&self, item: &MetaItemInner) { + match item.singleton_lit_list() { + Some(( + _, + MetaItemLit { + kind: ast::LitKind::Int(literal, ast::LitIntType::Unsuffixed), .. + }, + )) => { + let val = literal.get() as u64; + if val > 2_u64.pow(29) { + // for values greater than 2^29, a different error will be emitted, make sure that happens + self.dcx().span_delayed_bug( + item.span(), + "alignment greater than 2^29 should be errored on elsewhere", + ); + } else { + // only do this check when <= 2^29 to prevent duplicate errors: + // alignment greater than 2^29 not supported + // alignment is too large for the current target + + let max = + Size::from_bits(self.tcx.sess.target.pointer_width).signed_int_max() as u64; + if val > max { + self.dcx().emit_err(errors::InvalidReprAlignForTarget { + span: item.span(), + size: max, + }); + } + } + } + + // if the attribute is malformed, singleton_lit_list may not be of the expected type or may be None + // but an error will have already been emitted, so this code should just skip such attributes + Some((_, _)) | None => { + self.dcx().span_delayed_bug(item.span(), "malformed repr(align(N))"); + } + } + } + fn check_used(&self, attrs: &[Attribute], target: Target, target_span: Span) { let mut used_linker_span = None; let mut used_compiler_span = None; @@ -2225,7 +2267,7 @@ impl<'tcx> CheckAttrVisitor<'tcx> { let def_id = hir_id.expect_owner().def_id; let param_env = ty::ParamEnv::empty(); - let infcx = tcx.infer_ctxt().build(); + let infcx = tcx.infer_ctxt().build(TypingMode::non_body_analysis()); let ocx = ObligationCtxt::new_with_diagnostics(&infcx); let span = tcx.def_span(def_id); diff --git a/compiler/rustc_passes/src/dead.rs b/compiler/rustc_passes/src/dead.rs index af17fbf7e4d..b1db66fa52d 100644 --- a/compiler/rustc_passes/src/dead.rs +++ b/compiler/rustc_passes/src/dead.rs @@ -7,6 +7,7 @@ use std::mem; use hir::ItemKind; use hir::def_id::{LocalDefIdMap, LocalDefIdSet}; +use rustc_abi::FieldIdx; use rustc_data_structures::unord::UnordSet; use rustc_errors::MultiSpan; use rustc_hir as hir; @@ -22,7 +23,6 @@ use rustc_middle::{bug, span_bug}; use rustc_session::lint; use rustc_session::lint::builtin::DEAD_CODE; use rustc_span::symbol::{Symbol, sym}; -use rustc_target::abi::FieldIdx; use crate::errors::{ ChangeFields, IgnoredDerivedImpls, MultipleDeadCodes, ParentInfo, UselessAssignment, diff --git a/compiler/rustc_passes/src/errors.rs b/compiler/rustc_passes/src/errors.rs index b5f1eac1cba..8bd767c1243 100644 --- a/compiler/rustc_passes/src/errors.rs +++ b/compiler/rustc_passes/src/errors.rs @@ -567,6 +567,15 @@ pub(crate) struct ReprConflicting { pub hint_spans: Vec<Span>, } +#[derive(Diagnostic)] +#[diag(passes_repr_align_greater_than_target_max, code = E0589)] +#[note] +pub(crate) struct InvalidReprAlignForTarget { + #[primary_span] + pub span: Span, + pub size: u64, +} + #[derive(LintDiagnostic)] #[diag(passes_repr_conflicting, code = E0566)] pub(crate) struct ReprConflictingLint; diff --git a/compiler/rustc_passes/src/layout_test.rs b/compiler/rustc_passes/src/layout_test.rs index 93729a7f6df..921a915d05b 100644 --- a/compiler/rustc_passes/src/layout_test.rs +++ b/compiler/rustc_passes/src/layout_test.rs @@ -1,13 +1,14 @@ +use rustc_abi::{HasDataLayout, TargetDataLayout}; use rustc_ast::Attribute; use rustc_hir::def::DefKind; use rustc_hir::def_id::LocalDefId; +use rustc_middle::infer::canonical::ir::TypingMode; use rustc_middle::span_bug; use rustc_middle::ty::layout::{HasParamEnv, HasTyCtxt, LayoutError, LayoutOfHelpers}; use rustc_middle::ty::{self, ParamEnv, Ty, TyCtxt}; use rustc_span::Span; use rustc_span::source_map::Spanned; use rustc_span::symbol::sym; -use rustc_target::abi::{HasDataLayout, TargetDataLayout}; use rustc_trait_selection::error_reporting::InferCtxtErrorExt; use rustc_trait_selection::infer::TyCtxtInferExt; use rustc_trait_selection::traits; @@ -54,7 +55,7 @@ pub fn ensure_wf<'tcx>( param_env, pred, ); - let infcx = tcx.infer_ctxt().build(); + let infcx = tcx.infer_ctxt().build(TypingMode::from_param_env(param_env)); let ocx = traits::ObligationCtxt::new_with_diagnostics(&infcx); ocx.register_obligation(obligation); let errors = ocx.select_all_or_error(); diff --git a/compiler/rustc_passes/src/stability.rs b/compiler/rustc_passes/src/stability.rs index 466ea32735b..f69cc74fba2 100644 --- a/compiler/rustc_passes/src/stability.rs +++ b/compiler/rustc_passes/src/stability.rs @@ -189,9 +189,6 @@ impl<'a, 'tcx> Annotator<'a, 'tcx> { && let Some(fn_sig) = fn_sig && const_stab.is_const_stable() && !stab.is_some_and(|(s, _)| s.is_stable()) - // FIXME: we skip this check targets until - // <https://github.com/rust-lang/stdarch/pull/1654> propagates. - && false { self.tcx .dcx() diff --git a/compiler/rustc_pattern_analysis/Cargo.toml b/compiler/rustc_pattern_analysis/Cargo.toml index 34fb1bdf6fa..f98e4243375 100644 --- a/compiler/rustc_pattern_analysis/Cargo.toml +++ b/compiler/rustc_pattern_analysis/Cargo.toml @@ -6,6 +6,8 @@ edition = "2021" [dependencies] # tidy-alphabetical-start rustc-hash = "2.0.0" + +rustc_abi = { path = "../rustc_abi", optional = true } rustc_apfloat = "0.2.0" rustc_arena = { path = "../rustc_arena", optional = true } rustc_data_structures = { path = "../rustc_data_structures", optional = true } @@ -29,6 +31,7 @@ tracing-tree = "0.3.0" [features] default = ["rustc"] rustc = [ + "dep:rustc_abi", "dep:rustc_arena", "dep:rustc_data_structures", "dep:rustc_errors", diff --git a/compiler/rustc_pattern_analysis/src/rustc.rs b/compiler/rustc_pattern_analysis/src/rustc.rs index 0e132b27fb4..9ea5023064c 100644 --- a/compiler/rustc_pattern_analysis/src/rustc.rs +++ b/compiler/rustc_pattern_analysis/src/rustc.rs @@ -1,6 +1,7 @@ use std::fmt; use std::iter::once; +use rustc_abi::{FIRST_VARIANT, FieldIdx, Integer, VariantIdx}; use rustc_arena::DroplessArena; use rustc_hir::HirId; use rustc_hir::def_id::DefId; @@ -15,7 +16,6 @@ use rustc_middle::ty::{ use rustc_middle::{bug, span_bug}; use rustc_session::lint; use rustc_span::{DUMMY_SP, ErrorGuaranteed, Span}; -use rustc_target::abi::{FIRST_VARIANT, FieldIdx, Integer, VariantIdx}; use crate::constructor::Constructor::*; use crate::constructor::{ diff --git a/compiler/rustc_pattern_analysis/src/rustc/print.rs b/compiler/rustc_pattern_analysis/src/rustc/print.rs index 17e389df17e..7649f72f868 100644 --- a/compiler/rustc_pattern_analysis/src/rustc/print.rs +++ b/compiler/rustc_pattern_analysis/src/rustc/print.rs @@ -11,10 +11,10 @@ use std::fmt; +use rustc_abi::{FieldIdx, VariantIdx}; use rustc_middle::bug; use rustc_middle::ty::{self, AdtDef, Ty, TyCtxt}; use rustc_span::sym; -use rustc_target::abi::{FieldIdx, VariantIdx}; #[derive(Clone, Debug)] pub(crate) struct FieldPat { diff --git a/compiler/rustc_query_system/src/dep_graph/graph.rs b/compiler/rustc_query_system/src/dep_graph/graph.rs index cd7725d2d70..5e30f17d626 100644 --- a/compiler/rustc_query_system/src/dep_graph/graph.rs +++ b/compiler/rustc_query_system/src/dep_graph/graph.rs @@ -134,7 +134,7 @@ impl<D: Deps> DepGraph<D> { encoder, record_graph, record_stats, - prev_graph.clone(), + Arc::clone(&prev_graph), ); let colors = DepNodeColorMap::new(prev_graph_node_count); diff --git a/compiler/rustc_query_system/src/query/job.rs b/compiler/rustc_query_system/src/query/job.rs index ca3efc11201..5af41b9e687 100644 --- a/compiler/rustc_query_system/src/query/job.rs +++ b/compiler/rustc_query_system/src/query/job.rs @@ -237,7 +237,7 @@ impl QueryLatch { // the `wait` call below, by 1) the `set` method or 2) by deadlock detection. // Both of these will remove it from the `waiters` list before resuming // this thread. - info.waiters.push(waiter.clone()); + info.waiters.push(Arc::clone(waiter)); // If this detects a deadlock and the deadlock handler wants to resume this thread // we have to be in the `wait` call. This is ensured by the deadlock handler diff --git a/compiler/rustc_resolve/src/build_reduced_graph.rs b/compiler/rustc_resolve/src/build_reduced_graph.rs index 031ffaed808..bdf940a04b5 100644 --- a/compiler/rustc_resolve/src/build_reduced_graph.rs +++ b/compiler/rustc_resolve/src/build_reduced_graph.rs @@ -177,7 +177,9 @@ impl<'ra, 'tcx> Resolver<'ra, 'tcx> { let loaded_macro = self.cstore().load_macro_untracked(def_id, self.tcx); let macro_data = match loaded_macro { - LoadedMacro::MacroDef(item, edition) => self.compile_macro(&item, edition), + LoadedMacro::MacroDef { def, ident, attrs, span, edition } => { + self.compile_macro(&def, ident, &attrs, span, ast::DUMMY_NODE_ID, edition) + } LoadedMacro::ProcMacro(ext) => MacroData::new(Lrc::new(ext)), }; diff --git a/compiler/rustc_resolve/src/def_collector.rs b/compiler/rustc_resolve/src/def_collector.rs index 0047f2c4b51..a825458dc89 100644 --- a/compiler/rustc_resolve/src/def_collector.rs +++ b/compiler/rustc_resolve/src/def_collector.rs @@ -199,8 +199,10 @@ impl<'a, 'ra, 'tcx> visit::Visitor<'a> for DefCollector<'a, 'ra, 'tcx> { }, ItemKind::Const(..) => DefKind::Const, ItemKind::Fn(..) | ItemKind::Delegation(..) => DefKind::Fn, - ItemKind::MacroDef(..) => { - let macro_data = self.resolver.compile_macro(i, self.resolver.tcx.sess.edition()); + ItemKind::MacroDef(def) => { + let edition = self.resolver.tcx.sess.edition(); + let macro_data = + self.resolver.compile_macro(def, i.ident, &i.attrs, i.span, i.id, edition); let macro_kind = macro_data.ext.macro_kind(); opt_macro_data = Some(macro_data); DefKind::Macro(macro_kind) diff --git a/compiler/rustc_resolve/src/late.rs b/compiler/rustc_resolve/src/late.rs index adb0ba7c820..f4a85c358e3 100644 --- a/compiler/rustc_resolve/src/late.rs +++ b/compiler/rustc_resolve/src/late.rs @@ -841,10 +841,9 @@ impl<'ra: 'ast, 'ast, 'tcx> Visitor<'ast> for LateResolutionVisitor<'_, 'ast, 'r self.r.record_partial_res(ty.id, PartialRes::new(res)); visit::walk_ty(self, ty) } - TyKind::ImplTrait(node_id, _) => { + TyKind::ImplTrait(..) => { let candidates = self.lifetime_elision_candidates.take(); visit::walk_ty(self, ty); - self.record_lifetime_params_for_impl_trait(*node_id); self.lifetime_elision_candidates = candidates; } TyKind::TraitObject(bounds, ..) => { @@ -977,14 +976,6 @@ impl<'ra: 'ast, 'ast, 'tcx> Visitor<'ast> for LateResolutionVisitor<'_, 'ast, 'r sig.decl.inputs.iter().map(|Param { ty, .. }| (None, &**ty)), &sig.decl.output, ); - - if let Some((coro_node_id, _)) = sig - .header - .coroutine_kind - .map(|coroutine_kind| coroutine_kind.return_id()) - { - this.record_lifetime_params_for_impl_trait(coro_node_id); - } }, ); return; @@ -1026,10 +1017,6 @@ impl<'ra: 'ast, 'ast, 'tcx> Visitor<'ast> for LateResolutionVisitor<'_, 'ast, 'r .map(|Param { pat, ty, .. }| (Some(&**pat), &**ty)), &declaration.output, ); - - if let Some((async_node_id, _)) = coro_node_id { - this.record_lifetime_params_for_impl_trait(async_node_id); - } }, ); @@ -1220,7 +1207,6 @@ impl<'ra: 'ast, 'ast, 'tcx> Visitor<'ast> for LateResolutionVisitor<'_, 'ast, 'r } }, AssocItemConstraintKind::Bound { ref bounds } => { - self.record_lifetime_params_for_impl_trait(constraint.id); walk_list!(self, visit_param_bound, bounds, BoundKind::Bound); } } @@ -4795,30 +4781,6 @@ impl<'a, 'ast, 'ra: 'ast, 'tcx> LateResolutionVisitor<'a, 'ast, 'ra, 'tcx> { ) } - /// Construct the list of in-scope lifetime parameters for impl trait lowering. - /// We include all lifetime parameters, either named or "Fresh". - /// The order of those parameters does not matter, as long as it is - /// deterministic. - fn record_lifetime_params_for_impl_trait(&mut self, impl_trait_node_id: NodeId) { - let mut extra_lifetime_params = vec![]; - - for rib in self.lifetime_ribs.iter().rev() { - extra_lifetime_params - .extend(rib.bindings.iter().map(|(&ident, &(node_id, res))| (ident, node_id, res))); - match rib.kind { - LifetimeRibKind::Item => break, - LifetimeRibKind::AnonymousCreateParameter { binder, .. } => { - if let Some(earlier_fresh) = self.r.extra_lifetime_params_map.get(&binder) { - extra_lifetime_params.extend(earlier_fresh); - } - } - _ => {} - } - } - - self.r.extra_lifetime_params_map.insert(impl_trait_node_id, extra_lifetime_params); - } - fn resolve_and_cache_rustdoc_path(&mut self, path_str: &str, ns: Namespace) -> Option<Res> { // FIXME: This caching may be incorrect in case of multiple `macro_rules` // items with the same name in the same module. diff --git a/compiler/rustc_resolve/src/lib.rs b/compiler/rustc_resolve/src/lib.rs index 35d491cfc18..9abb3180388 100644 --- a/compiler/rustc_resolve/src/lib.rs +++ b/compiler/rustc_resolve/src/lib.rs @@ -1694,9 +1694,9 @@ impl<'ra, 'tcx> Resolver<'ra, 'tcx> { fn dummy_ext(&self, macro_kind: MacroKind) -> Lrc<SyntaxExtension> { match macro_kind { - MacroKind::Bang => self.dummy_ext_bang.clone(), - MacroKind::Derive => self.dummy_ext_derive.clone(), - MacroKind::Attr => self.non_macro_attr.ext.clone(), + MacroKind::Bang => Lrc::clone(&self.dummy_ext_bang), + MacroKind::Derive => Lrc::clone(&self.dummy_ext_derive), + MacroKind::Attr => Lrc::clone(&self.non_macro_attr.ext), } } diff --git a/compiler/rustc_resolve/src/macros.rs b/compiler/rustc_resolve/src/macros.rs index a9ebffea8a1..0b4d0e04c29 100644 --- a/compiler/rustc_resolve/src/macros.rs +++ b/compiler/rustc_resolve/src/macros.rs @@ -826,7 +826,7 @@ impl<'ra, 'tcx> Resolver<'ra, 'tcx> { } _ => None, }, - None => self.get_macro(res).map(|macro_data| macro_data.ext.clone()), + None => self.get_macro(res).map(|macro_data| Lrc::clone(¯o_data.ext)), }; Ok((ext, res)) } @@ -1122,9 +1122,25 @@ impl<'ra, 'tcx> Resolver<'ra, 'tcx> { /// Compile the macro into a `SyntaxExtension` and its rule spans. /// /// Possibly replace its expander to a pre-defined one for built-in macros. - pub(crate) fn compile_macro(&mut self, item: &ast::Item, edition: Edition) -> MacroData { - let (mut ext, mut rule_spans) = - compile_declarative_macro(self.tcx.sess, self.tcx.features(), item, edition); + pub(crate) fn compile_macro( + &mut self, + macro_def: &ast::MacroDef, + ident: Ident, + attrs: &[ast::Attribute], + span: Span, + node_id: NodeId, + edition: Edition, + ) -> MacroData { + let (mut ext, mut rule_spans) = compile_declarative_macro( + self.tcx.sess, + self.tcx.features(), + macro_def, + ident, + attrs, + span, + node_id, + edition, + ); if let Some(builtin_name) = ext.builtin_name { // The macro was marked with `#[rustc_builtin_macro]`. @@ -1132,28 +1148,22 @@ impl<'ra, 'tcx> Resolver<'ra, 'tcx> { // The macro is a built-in, replace its expander function // while still taking everything else from the source code. // If we already loaded this builtin macro, give a better error message than 'no such builtin macro'. - match mem::replace(builtin_macro, BuiltinMacroState::AlreadySeen(item.span)) { + match mem::replace(builtin_macro, BuiltinMacroState::AlreadySeen(span)) { BuiltinMacroState::NotYetSeen(builtin_ext) => { ext.kind = builtin_ext; rule_spans = Vec::new(); } - BuiltinMacroState::AlreadySeen(span) => { - self.dcx().emit_err(errors::AttemptToDefineBuiltinMacroTwice { - span: item.span, - note_span: span, - }); + BuiltinMacroState::AlreadySeen(note_span) => { + self.dcx() + .emit_err(errors::AttemptToDefineBuiltinMacroTwice { span, note_span }); } } } else { - self.dcx().emit_err(errors::CannotFindBuiltinMacroWithName { - span: item.span, - ident: item.ident, - }); + self.dcx().emit_err(errors::CannotFindBuiltinMacroWithName { span, ident }); } } - let ItemKind::MacroDef(def) = &item.kind else { unreachable!() }; - MacroData { ext: Lrc::new(ext), rule_spans, macro_rules: def.macro_rules } + MacroData { ext: Lrc::new(ext), rule_spans, macro_rules: macro_def.macro_rules } } fn path_accessible( diff --git a/compiler/rustc_session/Cargo.toml b/compiler/rustc_session/Cargo.toml index 75cc8f18a54..e9983699609 100644 --- a/compiler/rustc_session/Cargo.toml +++ b/compiler/rustc_session/Cargo.toml @@ -7,6 +7,7 @@ edition = "2021" # tidy-alphabetical-start bitflags = "2.4.1" getopts = "0.2" +rustc_abi = { path = "../rustc_abi" } rustc_ast = { path = "../rustc_ast" } rustc_data_structures = { path = "../rustc_data_structures" } rustc_errors = { path = "../rustc_errors" } diff --git a/compiler/rustc_session/src/code_stats.rs b/compiler/rustc_session/src/code_stats.rs index 7a32c0c2655..f3c21992784 100644 --- a/compiler/rustc_session/src/code_stats.rs +++ b/compiler/rustc_session/src/code_stats.rs @@ -1,10 +1,10 @@ use std::cmp; +use rustc_abi::{Align, Size}; use rustc_data_structures::fx::{FxHashMap, FxHashSet}; use rustc_data_structures::sync::Lock; use rustc_span::Symbol; use rustc_span::def_id::DefId; -use rustc_target::abi::{Align, Size}; #[derive(Clone, PartialEq, Eq, Hash, Debug)] pub struct VariantInfo { diff --git a/compiler/rustc_session/src/config/cfg.rs b/compiler/rustc_session/src/config/cfg.rs index ccc01728958..31ef2bda4f1 100644 --- a/compiler/rustc_session/src/config/cfg.rs +++ b/compiler/rustc_session/src/config/cfg.rs @@ -23,12 +23,12 @@ use std::hash::Hash; use std::iter; +use rustc_abi::Align; use rustc_ast::ast; use rustc_data_structures::fx::{FxHashMap, FxHashSet, FxIndexSet}; use rustc_lint_defs::BuiltinLintDiag; use rustc_lint_defs::builtin::EXPLICIT_BUILTIN_CFGS_IN_FLAGS; use rustc_span::symbol::{Symbol, sym}; -use rustc_target::abi::Align; use rustc_target::spec::{PanicStrategy, RelocModel, SanitizerSet, TARGETS, Target, TargetTriple}; use crate::Session; diff --git a/compiler/rustc_session/src/filesearch.rs b/compiler/rustc_session/src/filesearch.rs index 4aae2649843..b3e3381d986 100644 --- a/compiler/rustc_session/src/filesearch.rs +++ b/compiler/rustc_session/src/filesearch.rs @@ -84,7 +84,7 @@ fn current_dll_path() -> Result<PathBuf, String> { loop { if libc::loadquery( libc::L_GETINFO, - buffer.as_mut_ptr() as *mut i8, + buffer.as_mut_ptr() as *mut u8, (std::mem::size_of::<libc::ld_info>() * buffer.len()) as u32, ) >= 0 { diff --git a/compiler/rustc_session/src/parse.rs b/compiler/rustc_session/src/parse.rs index 3d44810e7dd..f20ae85b8e8 100644 --- a/compiler/rustc_session/src/parse.rs +++ b/compiler/rustc_session/src/parse.rs @@ -241,7 +241,7 @@ impl ParseSess { let sm = Lrc::new(SourceMap::new(FilePathMapping::empty())); let emitter = Box::new( HumanEmitter::new(stderr_destination(ColorConfig::Auto), fallback_bundle) - .sm(Some(sm.clone())), + .sm(Some(Lrc::clone(&sm))), ); let dcx = DiagCtxt::new(emitter); ParseSess::with_dcx(dcx, sm) @@ -278,7 +278,7 @@ impl ParseSess { let sm = Lrc::new(SourceMap::new(FilePathMapping::empty())); let emitter = Box::new(HumanEmitter::new( stderr_destination(ColorConfig::Auto), - fallback_bundle.clone(), + Lrc::clone(&fallback_bundle), )); let fatal_dcx = DiagCtxt::new(emitter); let dcx = DiagCtxt::new(Box::new(SilentEmitter { @@ -297,7 +297,7 @@ impl ParseSess { } pub fn clone_source_map(&self) -> Lrc<SourceMap> { - self.source_map.clone() + Lrc::clone(&self.source_map) } pub fn buffer_lint( diff --git a/compiler/rustc_session/src/session.rs b/compiler/rustc_session/src/session.rs index 1963cf4eb7c..45434534c75 100644 --- a/compiler/rustc_session/src/session.rs +++ b/compiler/rustc_session/src/session.rs @@ -1036,7 +1036,8 @@ pub fn build_session( sopts.unstable_opts.translate_directionality_markers, ); let source_map = rustc_span::source_map::get_source_map().unwrap(); - let emitter = default_emitter(&sopts, registry, source_map.clone(), bundle, fallback_bundle); + let emitter = + default_emitter(&sopts, registry, Lrc::clone(&source_map), bundle, fallback_bundle); let mut dcx = DiagCtxt::new(emitter).with_flags(sopts.unstable_opts.dcx_flags(can_emit_warnings)); @@ -1079,7 +1080,7 @@ pub fn build_session( let target_tlib_path = if host_triple == target_triple { // Use the same `SearchPath` if host and target triple are identical to avoid unnecessary // rescanning of the target lib path and an unnecessary allocation. - host_tlib_path.clone() + Lrc::clone(&host_tlib_path) } else { Lrc::new(SearchPath::from_sysroot_and_triple(&sysroot, target_triple)) }; diff --git a/compiler/rustc_smir/src/rustc_internal/mod.rs b/compiler/rustc_smir/src/rustc_internal/mod.rs index 55b47817f9a..a326e8583ea 100644 --- a/compiler/rustc_smir/src/rustc_internal/mod.rs +++ b/compiler/rustc_smir/src/rustc_internal/mod.rs @@ -170,7 +170,7 @@ impl<'tcx> Tables<'tcx> { stable_mir::mir::mono::StaticDef(self.create_def_id(did)) } - pub(crate) fn layout_id(&mut self, layout: rustc_target::abi::Layout<'tcx>) -> Layout { + pub(crate) fn layout_id(&mut self, layout: rustc_abi::Layout<'tcx>) -> Layout { self.layouts.create_or_fetch(layout) } } diff --git a/compiler/rustc_smir/src/rustc_smir/alloc.rs b/compiler/rustc_smir/src/rustc_smir/alloc.rs index 0d8740ae31f..5c09879f60e 100644 --- a/compiler/rustc_smir/src/rustc_smir/alloc.rs +++ b/compiler/rustc_smir/src/rustc_smir/alloc.rs @@ -1,3 +1,4 @@ +use rustc_abi::{Align, Size}; use rustc_middle::mir::ConstValue; use rustc_middle::mir::interpret::{AllocRange, Pointer, alloc_range}; use stable_mir::Error; @@ -7,7 +8,7 @@ use stable_mir::ty::{Allocation, ProvenanceMap}; use crate::rustc_smir::{Stable, Tables}; /// Creates new empty `Allocation` from given `Align`. -fn new_empty_allocation(align: rustc_target::abi::Align) -> Allocation { +fn new_empty_allocation(align: Align) -> Allocation { Allocation { bytes: Vec::new(), provenance: ProvenanceMap { ptrs: Vec::new() }, @@ -45,7 +46,7 @@ pub(crate) fn try_new_allocation<'tcx>( .align; let mut allocation = rustc_middle::mir::interpret::Allocation::uninit(size, align.abi); allocation - .write_scalar(&tables.tcx, alloc_range(rustc_target::abi::Size::ZERO, size), scalar) + .write_scalar(&tables.tcx, alloc_range(Size::ZERO, size), scalar) .map_err(|e| e.stable(tables))?; allocation.stable(tables) } @@ -59,7 +60,7 @@ pub(crate) fn try_new_allocation<'tcx>( } ConstValue::Slice { data, meta } => { let alloc_id = tables.tcx.reserve_and_set_memory_alloc(data); - let ptr = Pointer::new(alloc_id.into(), rustc_target::abi::Size::ZERO); + let ptr = Pointer::new(alloc_id.into(), Size::ZERO); let scalar_ptr = rustc_middle::mir::interpret::Scalar::from_pointer(ptr, &tables.tcx); let scalar_meta = rustc_middle::mir::interpret::Scalar::from_target_usize(meta, &tables.tcx); @@ -72,7 +73,7 @@ pub(crate) fn try_new_allocation<'tcx>( allocation .write_scalar( &tables.tcx, - alloc_range(rustc_target::abi::Size::ZERO, tables.tcx.data_layout.pointer_size), + alloc_range(Size::ZERO, tables.tcx.data_layout.pointer_size), scalar_ptr, ) .map_err(|e| e.stable(tables))?; @@ -112,10 +113,7 @@ pub(super) fn allocation_filter<'tcx>( .map(Some) .collect(); for (i, b) in bytes.iter_mut().enumerate() { - if !alloc - .init_mask() - .get(rustc_target::abi::Size::from_bytes(i + alloc_range.start.bytes_usize())) - { + if !alloc.init_mask().get(Size::from_bytes(i + alloc_range.start.bytes_usize())) { *b = None; } } diff --git a/compiler/rustc_smir/src/rustc_smir/convert/abi.rs b/compiler/rustc_smir/src/rustc_smir/convert/abi.rs index 06f01aebf9b..410bf0f40f4 100644 --- a/compiler/rustc_smir/src/rustc_smir/convert/abi.rs +++ b/compiler/rustc_smir/src/rustc_smir/convert/abi.rs @@ -1,9 +1,9 @@ -//! Conversion of internal Rust compiler `rustc_target::abi` and `rustc_abi` items to stable ones. +//! Conversion of internal Rust compiler `rustc_target` and `rustc_abi` items to stable ones. #![allow(rustc::usage_of_qualified_ty)] use rustc_middle::ty; -use rustc_target::abi::call::Conv; +use rustc_target::callconv::{self, Conv}; use stable_mir::abi::{ AddressSpace, ArgAbi, CallConvention, FieldsShape, FloatLength, FnAbi, IntegerLength, Layout, LayoutShape, PassMode, Primitive, Scalar, TagEncoding, TyAndLayout, ValueAbi, VariantsShape, @@ -15,7 +15,7 @@ use stable_mir::ty::{Align, IndexedVal, VariantIdx}; use crate::rustc_smir::{Stable, Tables}; -impl<'tcx> Stable<'tcx> for rustc_target::abi::VariantIdx { +impl<'tcx> Stable<'tcx> for rustc_abi::VariantIdx { type T = VariantIdx; fn stable(&self, _: &mut Tables<'_>) -> Self::T { VariantIdx::to_val(self.as_usize()) @@ -33,7 +33,7 @@ impl<'tcx> Stable<'tcx> for rustc_abi::Endian { } } -impl<'tcx> Stable<'tcx> for rustc_target::abi::TyAndLayout<'tcx, ty::Ty<'tcx>> { +impl<'tcx> Stable<'tcx> for rustc_abi::TyAndLayout<'tcx, ty::Ty<'tcx>> { type T = TyAndLayout; fn stable(&self, tables: &mut Tables<'_>) -> Self::T { @@ -41,7 +41,7 @@ impl<'tcx> Stable<'tcx> for rustc_target::abi::TyAndLayout<'tcx, ty::Ty<'tcx>> { } } -impl<'tcx> Stable<'tcx> for rustc_target::abi::Layout<'tcx> { +impl<'tcx> Stable<'tcx> for rustc_abi::Layout<'tcx> { type T = Layout; fn stable(&self, tables: &mut Tables<'_>) -> Self::T { @@ -49,9 +49,7 @@ impl<'tcx> Stable<'tcx> for rustc_target::abi::Layout<'tcx> { } } -impl<'tcx> Stable<'tcx> - for rustc_abi::LayoutS<rustc_target::abi::FieldIdx, rustc_target::abi::VariantIdx> -{ +impl<'tcx> Stable<'tcx> for rustc_abi::LayoutData<rustc_abi::FieldIdx, rustc_abi::VariantIdx> { type T = LayoutShape; fn stable(&self, tables: &mut Tables<'_>) -> Self::T { @@ -65,7 +63,7 @@ impl<'tcx> Stable<'tcx> } } -impl<'tcx> Stable<'tcx> for rustc_target::abi::call::FnAbi<'tcx, ty::Ty<'tcx>> { +impl<'tcx> Stable<'tcx> for callconv::FnAbi<'tcx, ty::Ty<'tcx>> { type T = FnAbi; fn stable(&self, tables: &mut Tables<'_>) -> Self::T { @@ -81,7 +79,7 @@ impl<'tcx> Stable<'tcx> for rustc_target::abi::call::FnAbi<'tcx, ty::Ty<'tcx>> { } } -impl<'tcx> Stable<'tcx> for rustc_target::abi::call::ArgAbi<'tcx, ty::Ty<'tcx>> { +impl<'tcx> Stable<'tcx> for callconv::ArgAbi<'tcx, ty::Ty<'tcx>> { type T = ArgAbi; fn stable(&self, tables: &mut Tables<'_>) -> Self::T { @@ -93,7 +91,7 @@ impl<'tcx> Stable<'tcx> for rustc_target::abi::call::ArgAbi<'tcx, ty::Ty<'tcx>> } } -impl<'tcx> Stable<'tcx> for rustc_target::abi::call::Conv { +impl<'tcx> Stable<'tcx> for callconv::Conv { type T = CallConvention; fn stable(&self, _tables: &mut Tables<'_>) -> Self::T { @@ -122,31 +120,29 @@ impl<'tcx> Stable<'tcx> for rustc_target::abi::call::Conv { } } -impl<'tcx> Stable<'tcx> for rustc_target::abi::call::PassMode { +impl<'tcx> Stable<'tcx> for callconv::PassMode { type T = PassMode; fn stable(&self, _tables: &mut Tables<'_>) -> Self::T { match self { - rustc_target::abi::call::PassMode::Ignore => PassMode::Ignore, - rustc_target::abi::call::PassMode::Direct(attr) => PassMode::Direct(opaque(attr)), - rustc_target::abi::call::PassMode::Pair(first, second) => { + callconv::PassMode::Ignore => PassMode::Ignore, + callconv::PassMode::Direct(attr) => PassMode::Direct(opaque(attr)), + callconv::PassMode::Pair(first, second) => { PassMode::Pair(opaque(first), opaque(second)) } - rustc_target::abi::call::PassMode::Cast { pad_i32, cast } => { + callconv::PassMode::Cast { pad_i32, cast } => { PassMode::Cast { pad_i32: *pad_i32, cast: opaque(cast) } } - rustc_target::abi::call::PassMode::Indirect { attrs, meta_attrs, on_stack } => { - PassMode::Indirect { - attrs: opaque(attrs), - meta_attrs: opaque(meta_attrs), - on_stack: *on_stack, - } - } + callconv::PassMode::Indirect { attrs, meta_attrs, on_stack } => PassMode::Indirect { + attrs: opaque(attrs), + meta_attrs: opaque(meta_attrs), + on_stack: *on_stack, + }, } } } -impl<'tcx> Stable<'tcx> for rustc_abi::FieldsShape<rustc_target::abi::FieldIdx> { +impl<'tcx> Stable<'tcx> for rustc_abi::FieldsShape<rustc_abi::FieldIdx> { type T = FieldsShape; fn stable(&self, tables: &mut Tables<'_>) -> Self::T { @@ -163,9 +159,7 @@ impl<'tcx> Stable<'tcx> for rustc_abi::FieldsShape<rustc_target::abi::FieldIdx> } } -impl<'tcx> Stable<'tcx> - for rustc_abi::Variants<rustc_target::abi::FieldIdx, rustc_target::abi::VariantIdx> -{ +impl<'tcx> Stable<'tcx> for rustc_abi::Variants<rustc_abi::FieldIdx, rustc_abi::VariantIdx> { type T = VariantsShape; fn stable(&self, tables: &mut Tables<'_>) -> Self::T { @@ -185,7 +179,7 @@ impl<'tcx> Stable<'tcx> } } -impl<'tcx> Stable<'tcx> for rustc_abi::TagEncoding<rustc_target::abi::VariantIdx> { +impl<'tcx> Stable<'tcx> for rustc_abi::TagEncoding<rustc_abi::VariantIdx> { type T = TagEncoding; fn stable(&self, tables: &mut Tables<'_>) -> Self::T { diff --git a/compiler/rustc_smir/src/rustc_smir/convert/mir.rs b/compiler/rustc_smir/src/rustc_smir/convert/mir.rs index dbae4b7e719..820d8a6be25 100644 --- a/compiler/rustc_smir/src/rustc_smir/convert/mir.rs +++ b/compiler/rustc_smir/src/rustc_smir/convert/mir.rs @@ -691,11 +691,7 @@ impl<'tcx> Stable<'tcx> for mir::interpret::Allocation { type T = stable_mir::ty::Allocation; fn stable(&self, tables: &mut Tables<'_>) -> Self::T { - alloc::allocation_filter( - self, - alloc_range(rustc_target::abi::Size::ZERO, self.size()), - tables, - ) + alloc::allocation_filter(self, alloc_range(rustc_abi::Size::ZERO, self.size()), tables) } } diff --git a/compiler/rustc_smir/src/rustc_smir/mod.rs b/compiler/rustc_smir/src/rustc_smir/mod.rs index 9b27b94fb5a..9032156b257 100644 --- a/compiler/rustc_smir/src/rustc_smir/mod.rs +++ b/compiler/rustc_smir/src/rustc_smir/mod.rs @@ -36,7 +36,7 @@ pub struct Tables<'tcx> { pub(crate) instances: IndexMap<ty::Instance<'tcx>, InstanceDef>, pub(crate) ty_consts: IndexMap<ty::Const<'tcx>, TyConstId>, pub(crate) mir_consts: IndexMap<mir::Const<'tcx>, MirConstId>, - pub(crate) layouts: IndexMap<rustc_target::abi::Layout<'tcx>, Layout>, + pub(crate) layouts: IndexMap<rustc_abi::Layout<'tcx>, Layout>, } impl<'tcx> Tables<'tcx> { diff --git a/compiler/rustc_span/src/caching_source_map_view.rs b/compiler/rustc_span/src/caching_source_map_view.rs index 26aa782e5d7..9f977b98b82 100644 --- a/compiler/rustc_span/src/caching_source_map_view.rs +++ b/compiler/rustc_span/src/caching_source_map_view.rs @@ -63,7 +63,7 @@ pub struct CachingSourceMapView<'sm> { impl<'sm> CachingSourceMapView<'sm> { pub fn new(source_map: &'sm SourceMap) -> CachingSourceMapView<'sm> { let files = source_map.files(); - let first_file = files[0].clone(); + let first_file = Lrc::clone(&files[0]); let entry = CacheEntry { time_stamp: 0, line_number: 0, @@ -92,7 +92,7 @@ impl<'sm> CachingSourceMapView<'sm> { cache_entry.touch(self.time_stamp); let col = RelativeBytePos(pos.to_u32() - cache_entry.line.start.to_u32()); - return Some((cache_entry.file.clone(), cache_entry.line_number, col)); + return Some((Lrc::clone(&cache_entry.file), cache_entry.line_number, col)); } // No cache hit ... @@ -109,7 +109,7 @@ impl<'sm> CachingSourceMapView<'sm> { cache_entry.update(new_file_and_idx, pos, self.time_stamp); let col = RelativeBytePos(pos.to_u32() - cache_entry.line.start.to_u32()); - Some((cache_entry.file.clone(), cache_entry.line_number, col)) + Some((Lrc::clone(&cache_entry.file), cache_entry.line_number, col)) } pub fn span_data_to_lines_and_cols( @@ -133,7 +133,7 @@ impl<'sm> CachingSourceMapView<'sm> { } ( - lo.file.clone(), + Lrc::clone(&lo.file), lo.line_number, span_data.lo - lo.line.start, hi.line_number, @@ -181,7 +181,7 @@ impl<'sm> CachingSourceMapView<'sm> { lo.update(new_file_and_idx, span_data.lo, self.time_stamp); if !lo.line.contains(&span_data.hi) { - let new_file_and_idx = Some((lo.file.clone(), lo.file_index)); + let new_file_and_idx = Some((Lrc::clone(&lo.file), lo.file_index)); let next_oldest = self.oldest_cache_entry_index_avoid(oldest); let hi = &mut self.line_cache[next_oldest]; hi.update(new_file_and_idx, span_data.hi, self.time_stamp); @@ -227,7 +227,7 @@ impl<'sm> CachingSourceMapView<'sm> { assert_eq!(lo.file_index, hi.file_index); Some(( - lo.file.clone(), + Lrc::clone(&lo.file), lo.line_number, span_data.lo - lo.line.start, hi.line_number, @@ -277,7 +277,7 @@ impl<'sm> CachingSourceMapView<'sm> { let file = &self.source_map.files()[file_idx]; if file_contains(file, pos) { - return Some((file.clone(), file_idx)); + return Some((Lrc::clone(file), file_idx)); } } diff --git a/compiler/rustc_span/src/source_map.rs b/compiler/rustc_span/src/source_map.rs index 8a023305937..f36bb38623e 100644 --- a/compiler/rustc_span/src/source_map.rs +++ b/compiler/rustc_span/src/source_map.rs @@ -286,8 +286,8 @@ impl SourceMap { }); let file = Lrc::new(file); - files.source_files.push(file.clone()); - files.stable_id_to_source_file.insert(file_id, file.clone()); + files.source_files.push(Lrc::clone(&file)); + files.stable_id_to_source_file.insert(file_id, Lrc::clone(&file)); Ok(file) } @@ -386,7 +386,7 @@ impl SourceMap { /// Return the SourceFile that contains the given `BytePos` pub fn lookup_source_file(&self, pos: BytePos) -> Lrc<SourceFile> { let idx = self.lookup_source_file_idx(pos); - (*self.files.borrow().source_files)[idx].clone() + Lrc::clone(&(*self.files.borrow().source_files)[idx]) } /// Looks up source information about a `BytePos`. @@ -468,7 +468,7 @@ impl SourceMap { if lo != hi { return true; } - let f = (*self.files.borrow().source_files)[lo].clone(); + let f = Lrc::clone(&(*self.files.borrow().source_files)[lo]); let lo = f.relative_position(sp.lo()); let hi = f.relative_position(sp.hi()); f.lookup_line(lo) != f.lookup_line(hi) @@ -994,7 +994,7 @@ impl SourceMap { let filename = self.path_mapping().map_filename_prefix(filename).0; for sf in self.files.borrow().source_files.iter() { if filename == sf.name { - return Some(sf.clone()); + return Some(Lrc::clone(&sf)); } } None @@ -1003,7 +1003,7 @@ impl SourceMap { /// For a global `BytePos`, computes the local offset within the containing `SourceFile`. pub fn lookup_byte_offset(&self, bpos: BytePos) -> SourceFileAndBytePos { let idx = self.lookup_source_file_idx(bpos); - let sf = (*self.files.borrow().source_files)[idx].clone(); + let sf = Lrc::clone(&(*self.files.borrow().source_files)[idx]); let offset = bpos - sf.start_pos; SourceFileAndBytePos { sf, pos: offset } } diff --git a/compiler/rustc_span/src/symbol.rs b/compiler/rustc_span/src/symbol.rs index 134a1a1db30..890c4fdafef 100644 --- a/compiler/rustc_span/src/symbol.rs +++ b/compiler/rustc_span/src/symbol.rs @@ -171,9 +171,11 @@ symbols! { CallOnceFuture, CallRefFuture, Capture, + Cell, Center, Cleanup, Clone, + CoercePointee, CoerceUnsized, Command, ConstParamTy, @@ -307,7 +309,6 @@ symbols! { Sized, SliceIndex, SliceIter, - SmartPointer, Some, SpanCtxt, String, @@ -409,6 +410,7 @@ symbols! { arm, arm_target_feature, array, + as_mut_ptr, as_ptr, as_ref, as_str, @@ -732,6 +734,7 @@ symbols! { deref_pure, deref_target, derive, + derive_coerce_pointee, derive_const, derive_default_enum, derive_smart_pointer, diff --git a/compiler/rustc_symbol_mangling/Cargo.toml b/compiler/rustc_symbol_mangling/Cargo.toml index 65aa9e40c8b..644e710d1db 100644 --- a/compiler/rustc_symbol_mangling/Cargo.toml +++ b/compiler/rustc_symbol_mangling/Cargo.toml @@ -7,6 +7,8 @@ edition = "2021" # tidy-alphabetical-start punycode = "0.4.0" rustc-demangle = "0.1.21" + +rustc_abi = { path = "../rustc_abi" } rustc_data_structures = { path = "../rustc_data_structures" } rustc_errors = { path = "../rustc_errors" } rustc_hir = { path = "../rustc_hir" } diff --git a/compiler/rustc_symbol_mangling/src/v0.rs b/compiler/rustc_symbol_mangling/src/v0.rs index d092fa8f082..868345c7594 100644 --- a/compiler/rustc_symbol_mangling/src/v0.rs +++ b/compiler/rustc_symbol_mangling/src/v0.rs @@ -2,6 +2,7 @@ use std::fmt::Write; use std::iter; use std::ops::Range; +use rustc_abi::Integer; use rustc_data_structures::base_n::ToBaseN; use rustc_data_structures::fx::FxHashMap; use rustc_data_structures::intern::Interned; @@ -17,7 +18,6 @@ use rustc_middle::ty::{ TyCtxt, TypeVisitable, TypeVisitableExt, UintTy, }; use rustc_span::symbol::kw; -use rustc_target::abi::Integer; use rustc_target::spec::abi::Abi; pub(super) fn mangle<'tcx>( diff --git a/compiler/rustc_target/src/target_features.rs b/compiler/rustc_target/src/target_features.rs index 910cafbdf3b..3df8f0590a3 100644 --- a/compiler/rustc_target/src/target_features.rs +++ b/compiler/rustc_target/src/target_features.rs @@ -167,6 +167,8 @@ const AARCH64_ALLOWED_FEATURES: &[(&str, Stability, ImpliedFeatures)] = &[ ("pacg", Stable, &[]), // FEAT_PAN ("pan", Stable, &[]), + // FEAT_PAuth_LR + ("pauth-lr", Unstable(sym::aarch64_unstable_target_feature), &[]), // FEAT_PMUv3 ("pmuv3", Stable, &[]), // FEAT_RNG diff --git a/compiler/rustc_trait_selection/src/error_reporting/infer/mod.rs b/compiler/rustc_trait_selection/src/error_reporting/infer/mod.rs index b9a569d25e3..574cf1e88b1 100644 --- a/compiler/rustc_trait_selection/src/error_reporting/infer/mod.rs +++ b/compiler/rustc_trait_selection/src/error_reporting/infer/mod.rs @@ -392,7 +392,7 @@ impl<'a, 'tcx> TypeErrCtxt<'a, 'tcx> { Some(ty) if expected == ty => { let source_map = self.tcx.sess.source_map(); err.span_suggestion( - source_map.end_point(cause.span()), + source_map.end_point(cause.span), "try removing this `?`", "", Applicability::MachineApplicable, @@ -412,6 +412,7 @@ impl<'a, 'tcx> TypeErrCtxt<'a, 'tcx> { source, ref prior_non_diverging_arms, scrut_span, + expr_span, .. }) => match source { hir::MatchSource::TryDesugar(scrut_hir_id) => { @@ -430,7 +431,7 @@ impl<'a, 'tcx> TypeErrCtxt<'a, 'tcx> { Some(ty) if expected == ty => { let source_map = self.tcx.sess.source_map(); err.span_suggestion( - source_map.end_point(cause.span()), + source_map.end_point(cause.span), "try removing this `?`", "", Applicability::MachineApplicable, @@ -460,12 +461,12 @@ impl<'a, 'tcx> TypeErrCtxt<'a, 'tcx> { format!("this and all prior arms are found to be of type `{t}`"), ); } - let outer = if any_multiline_arm || !source_map.is_multiline(cause.span) { + let outer = if any_multiline_arm || !source_map.is_multiline(expr_span) { // Cover just `match` and the scrutinee expression, not // the entire match body, to reduce diagram noise. - cause.span.shrink_to_lo().to(scrut_span) + expr_span.shrink_to_lo().to(scrut_span) } else { - cause.span + expr_span }; let msg = "`match` arms have incompatible types"; err.span_label(outer, msg); @@ -1148,7 +1149,7 @@ impl<'a, 'tcx> TypeErrCtxt<'a, 'tcx> { terr: TypeError<'tcx>, prefer_label: bool, ) { - let span = cause.span(); + let span = cause.span; // For some types of errors, expected-found does not make // sense, so just ignore the values we were given. @@ -1642,7 +1643,7 @@ impl<'a, 'tcx> TypeErrCtxt<'a, 'tcx> { terr: TypeError<'tcx>, ) -> Vec<TypeErrorAdditionalDiags> { let mut suggestions = Vec::new(); - let span = trace.cause.span(); + let span = trace.cause.span; let values = self.resolve_vars_if_possible(trace.values); if let Some((expected, found)) = values.ty() { match (expected.kind(), found.kind()) { @@ -1792,7 +1793,7 @@ impl<'a, 'tcx> TypeErrCtxt<'a, 'tcx> { ) -> Diag<'a> { debug!("report_and_explain_type_error(trace={:?}, terr={:?})", trace, terr); - let span = trace.cause.span(); + let span = trace.cause.span; let failure_code = trace.cause.as_failure_code_diag( terr, span, diff --git a/compiler/rustc_trait_selection/src/error_reporting/infer/nice_region_error/placeholder_error.rs b/compiler/rustc_trait_selection/src/error_reporting/infer/nice_region_error/placeholder_error.rs index 14c2bf19a9c..4398af76ab2 100644 --- a/compiler/rustc_trait_selection/src/error_reporting/infer/nice_region_error/placeholder_error.rs +++ b/compiler/rustc_trait_selection/src/error_reporting/infer/nice_region_error/placeholder_error.rs @@ -237,7 +237,7 @@ impl<'tcx> NiceRegionError<'_, 'tcx> { expected_args: GenericArgsRef<'tcx>, actual_args: GenericArgsRef<'tcx>, ) -> Diag<'tcx> { - let span = cause.span(); + let span = cause.span; let (leading_ellipsis, satisfy_span, where_span, dup_span, def_id) = if let ObligationCauseCode::WhereClause(def_id, span) diff --git a/compiler/rustc_trait_selection/src/error_reporting/infer/nice_region_error/static_impl_trait.rs b/compiler/rustc_trait_selection/src/error_reporting/infer/nice_region_error/static_impl_trait.rs index 8541621b23b..2b19db2c14e 100644 --- a/compiler/rustc_trait_selection/src/error_reporting/infer/nice_region_error/static_impl_trait.rs +++ b/compiler/rustc_trait_selection/src/error_reporting/infer/nice_region_error/static_impl_trait.rs @@ -284,7 +284,7 @@ pub fn suggest_new_region_bound( } match fn_return.kind { // FIXME(precise_captures): Suggest adding to `use<...>` list instead. - TyKind::OpaqueDef(opaque, _) => { + TyKind::OpaqueDef(opaque) => { // Get the identity type for this RPIT let did = opaque.def_id.to_def_id(); let ty = Ty::new_opaque(tcx, did, ty::GenericArgs::identity_for_item(tcx, did)); diff --git a/compiler/rustc_trait_selection/src/error_reporting/infer/region.rs b/compiler/rustc_trait_selection/src/error_reporting/infer/region.rs index 833358b2e14..438639e72f9 100644 --- a/compiler/rustc_trait_selection/src/error_reporting/infer/region.rs +++ b/compiler/rustc_trait_selection/src/error_reporting/infer/region.rs @@ -862,22 +862,6 @@ impl<'a, 'tcx> TypeErrCtxt<'a, 'tcx> { self.add_lt_suggs.push(lt.suggestion(self.new_lt)); } } - - fn visit_ty(&mut self, ty: &'hir hir::Ty<'hir>) { - let hir::TyKind::OpaqueDef(opaque_ty, _) = ty.kind else { - return hir::intravisit::walk_ty(self, ty); - }; - if let Some(&(_, b)) = - opaque_ty.lifetime_mapping.iter().find(|&(a, _)| a.res == self.needle) - { - let prev_needle = - std::mem::replace(&mut self.needle, hir::LifetimeName::Param(b)); - for bound in opaque_ty.bounds { - self.visit_param_bound(bound); - } - self.needle = prev_needle; - } - } } let (lifetime_def_id, lifetime_scope) = diff --git a/compiler/rustc_trait_selection/src/error_reporting/traits/fulfillment_errors.rs b/compiler/rustc_trait_selection/src/error_reporting/traits/fulfillment_errors.rs index b7e2ed391cd..6014ed555b6 100644 --- a/compiler/rustc_trait_selection/src/error_reporting/traits/fulfillment_errors.rs +++ b/compiler/rustc_trait_selection/src/error_reporting/traits/fulfillment_errors.rs @@ -1835,6 +1835,7 @@ impl<'a, 'tcx> TypeErrCtxt<'a, 'tcx> { if impl_trait_ref.references_error() { return false; } + let self_ty = impl_trait_ref.self_ty().to_string(); err.highlighted_help(vec![ StringPart::normal(format!( "the trait `{}` ", @@ -1842,16 +1843,24 @@ impl<'a, 'tcx> TypeErrCtxt<'a, 'tcx> { )), StringPart::highlighted("is"), StringPart::normal(" implemented for `"), - StringPart::highlighted(impl_trait_ref.self_ty().to_string()), + if let [TypeError::Sorts(_)] = &terrs[..] { + StringPart::normal(self_ty) + } else { + StringPart::highlighted(self_ty) + }, StringPart::normal("`"), ]); if let [TypeError::Sorts(exp_found)] = &terrs[..] { let exp_found = self.resolve_vars_if_possible(*exp_found); - err.help(format!( - "for that trait implementation, expected `{}`, found `{}`", - exp_found.expected, exp_found.found - )); + err.highlighted_help(vec![ + StringPart::normal("for that trait implementation, "), + StringPart::normal("expected `"), + StringPart::highlighted(exp_found.expected.to_string()), + StringPart::normal("`, found `"), + StringPart::highlighted(exp_found.found.to_string()), + StringPart::normal("`"), + ]); } true @@ -2160,6 +2169,7 @@ impl<'a, 'tcx> TypeErrCtxt<'a, 'tcx> { // First, attempt to add note to this error with an async-await-specific // message, and fall back to regular note otherwise. if !self.maybe_note_obligation_cause_for_async_await(err, obligation) { + let mut long_ty_file = None; self.note_obligation_cause_code( obligation.cause.body_id, err, @@ -2168,7 +2178,15 @@ impl<'a, 'tcx> TypeErrCtxt<'a, 'tcx> { obligation.cause.code(), &mut vec![], &mut Default::default(), + &mut long_ty_file, ); + if let Some(file) = long_ty_file { + err.note(format!( + "the full name for the type has been written to '{}'", + file.display(), + )); + err.note("consider using `--verbose` to print the full type name to the console"); + } self.suggest_unsized_bound_if_applicable(err, obligation); if let Some(span) = err.span.primary_span() && let Some(mut diag) = diff --git a/compiler/rustc_trait_selection/src/error_reporting/traits/mod.rs b/compiler/rustc_trait_selection/src/error_reporting/traits/mod.rs index ca23f776581..b108a9352a5 100644 --- a/compiler/rustc_trait_selection/src/error_reporting/traits/mod.rs +++ b/compiler/rustc_trait_selection/src/error_reporting/traits/mod.rs @@ -305,6 +305,7 @@ impl<'a, 'tcx> TypeErrCtxt<'a, 'tcx> { if let ObligationCauseCode::WhereClause(..) | ObligationCauseCode::WhereClauseInExpr(..) = code { + let mut long_ty_file = None; self.note_obligation_cause_code( error.obligation.cause.body_id, &mut diag, @@ -313,7 +314,17 @@ impl<'a, 'tcx> TypeErrCtxt<'a, 'tcx> { code, &mut vec![], &mut Default::default(), + &mut long_ty_file, ); + if let Some(file) = long_ty_file { + diag.note(format!( + "the full name for the type has been written to '{}'", + file.display(), + )); + diag.note( + "consider using `--verbose` to print the full type name to the console", + ); + } } diag.emit() } diff --git a/compiler/rustc_trait_selection/src/error_reporting/traits/overflow.rs b/compiler/rustc_trait_selection/src/error_reporting/traits/overflow.rs index f4c5733d4a6..c47c2169691 100644 --- a/compiler/rustc_trait_selection/src/error_reporting/traits/overflow.rs +++ b/compiler/rustc_trait_selection/src/error_reporting/traits/overflow.rs @@ -144,6 +144,7 @@ impl<'a, 'tcx> TypeErrCtxt<'a, 'tcx> { obligation.cause.span, suggest_increasing_limit, |err| { + let mut long_ty_file = None; self.note_obligation_cause_code( obligation.cause.body_id, err, @@ -152,7 +153,17 @@ impl<'a, 'tcx> TypeErrCtxt<'a, 'tcx> { obligation.cause.code(), &mut vec![], &mut Default::default(), + &mut long_ty_file, ); + if let Some(file) = long_ty_file { + err.note(format!( + "the full name for the type has been written to '{}'", + file.display(), + )); + err.note( + "consider using `--verbose` to print the full type name to the console", + ); + } }, ); } diff --git a/compiler/rustc_trait_selection/src/error_reporting/traits/suggestions.rs b/compiler/rustc_trait_selection/src/error_reporting/traits/suggestions.rs index 1fe93cb017a..19f5d609272 100644 --- a/compiler/rustc_trait_selection/src/error_reporting/traits/suggestions.rs +++ b/compiler/rustc_trait_selection/src/error_reporting/traits/suggestions.rs @@ -3,6 +3,7 @@ use std::assert_matches::debug_assert_matches; use std::borrow::Cow; use std::iter; +use std::path::PathBuf; use itertools::{EitherOrBoth, Itertools}; use rustc_data_structures::fx::FxHashSet; @@ -360,7 +361,6 @@ impl<'a, 'tcx> TypeErrCtxt<'a, 'tcx> { }) | hir::Node::TraitItem(hir::TraitItem { generics, .. }) | hir::Node::ImplItem(hir::ImplItem { generics, .. }) - | hir::Node::OpaqueTy(hir::OpaqueTy { generics, .. }) if param_ty => { // We skip the 0'th arg (self) because we do not want @@ -423,10 +423,7 @@ impl<'a, 'tcx> TypeErrCtxt<'a, 'tcx> { | hir::ItemKind::Const(_, generics, _) | hir::ItemKind::TraitAlias(generics, _), .. - }) - | hir::Node::OpaqueTy(hir::OpaqueTy { generics, .. }) - if !param_ty => - { + }) if !param_ty => { // Missing generic type parameter bound. if suggest_arbitrary_trait_bound( self.tcx, @@ -2703,6 +2700,7 @@ impl<'a, 'tcx> TypeErrCtxt<'a, 'tcx> { // Add a note for the item obligation that remains - normally a note pointing to the // bound that introduced the obligation (e.g. `T: Send`). debug!(?next_code); + let mut long_ty_file = None; self.note_obligation_cause_code( obligation.cause.body_id, err, @@ -2711,6 +2709,7 @@ impl<'a, 'tcx> TypeErrCtxt<'a, 'tcx> { next_code.unwrap(), &mut Vec::new(), &mut Default::default(), + &mut long_ty_file, ); } @@ -2723,11 +2722,10 @@ impl<'a, 'tcx> TypeErrCtxt<'a, 'tcx> { cause_code: &ObligationCauseCode<'tcx>, obligated_types: &mut Vec<Ty<'tcx>>, seen_requirements: &mut FxHashSet<DefId>, + long_ty_file: &mut Option<PathBuf>, ) where T: Upcast<TyCtxt<'tcx>, ty::Predicate<'tcx>>, { - let mut long_ty_file = None; - let tcx = self.tcx; let predicate = predicate.upcast(tcx); let suggest_remove_deref = |err: &mut Diag<'_, G>, expr: &hir::Expr<'_>| { @@ -2957,9 +2955,9 @@ impl<'a, 'tcx> TypeErrCtxt<'a, 'tcx> { } ObligationCauseCode::Coercion { source, target } => { let source = - tcx.short_ty_string(self.resolve_vars_if_possible(source), &mut long_ty_file); + tcx.short_ty_string(self.resolve_vars_if_possible(source), long_ty_file); let target = - tcx.short_ty_string(self.resolve_vars_if_possible(target), &mut long_ty_file); + tcx.short_ty_string(self.resolve_vars_if_possible(target), long_ty_file); err.note(with_forced_trimmed_paths!(format!( "required for the cast from `{source}` to `{target}`", ))); @@ -3249,7 +3247,7 @@ impl<'a, 'tcx> TypeErrCtxt<'a, 'tcx> { }; if !is_upvar_tys_infer_tuple { - let ty_str = tcx.short_ty_string(ty, &mut long_ty_file); + let ty_str = tcx.short_ty_string(ty, long_ty_file); let msg = format!("required because it appears within the type `{ty_str}`"); match ty.kind() { ty::Adt(def, _) => match tcx.opt_item_ident(def.did()) { @@ -3327,6 +3325,7 @@ impl<'a, 'tcx> TypeErrCtxt<'a, 'tcx> { &data.parent_code, obligated_types, seen_requirements, + long_ty_file, ) }); } else { @@ -3339,6 +3338,7 @@ impl<'a, 'tcx> TypeErrCtxt<'a, 'tcx> { cause_code.peel_derives(), obligated_types, seen_requirements, + long_ty_file, ) }); } @@ -3347,8 +3347,8 @@ impl<'a, 'tcx> TypeErrCtxt<'a, 'tcx> { let mut parent_trait_pred = self.resolve_vars_if_possible(data.derived.parent_trait_pred); let parent_def_id = parent_trait_pred.def_id(); - let self_ty_str = tcx - .short_ty_string(parent_trait_pred.skip_binder().self_ty(), &mut long_ty_file); + let self_ty_str = + tcx.short_ty_string(parent_trait_pred.skip_binder().self_ty(), long_ty_file); let trait_name = parent_trait_pred.print_modifiers_and_trait_path().to_string(); let msg = format!("required for `{self_ty_str}` to implement `{trait_name}`"); let mut is_auto_trait = false; @@ -3444,10 +3444,8 @@ impl<'a, 'tcx> TypeErrCtxt<'a, 'tcx> { count, pluralize!(count) )); - let self_ty = tcx.short_ty_string( - parent_trait_pred.skip_binder().self_ty(), - &mut long_ty_file, - ); + let self_ty = tcx + .short_ty_string(parent_trait_pred.skip_binder().self_ty(), long_ty_file); err.note(format!( "required for `{self_ty}` to implement `{}`", parent_trait_pred.print_modifiers_and_trait_path() @@ -3463,6 +3461,7 @@ impl<'a, 'tcx> TypeErrCtxt<'a, 'tcx> { &data.parent_code, obligated_types, seen_requirements, + long_ty_file, ) }); } @@ -3479,6 +3478,7 @@ impl<'a, 'tcx> TypeErrCtxt<'a, 'tcx> { &data.parent_code, obligated_types, seen_requirements, + long_ty_file, ) }); } @@ -3493,6 +3493,7 @@ impl<'a, 'tcx> TypeErrCtxt<'a, 'tcx> { nested, obligated_types, seen_requirements, + long_ty_file, ) }); let mut multispan = MultiSpan::from(span); @@ -3523,6 +3524,7 @@ impl<'a, 'tcx> TypeErrCtxt<'a, 'tcx> { parent_code, obligated_types, seen_requirements, + long_ty_file, ) }); } @@ -3562,7 +3564,7 @@ impl<'a, 'tcx> TypeErrCtxt<'a, 'tcx> { } ObligationCauseCode::OpaqueReturnType(expr_info) => { if let Some((expr_ty, hir_id)) = expr_info { - let expr_ty = self.tcx.short_ty_string(expr_ty, &mut long_ty_file); + let expr_ty = self.tcx.short_ty_string(expr_ty, long_ty_file); let expr = self.infcx.tcx.hir().expect_expr(hir_id); err.span_label( expr.span, @@ -3574,14 +3576,6 @@ impl<'a, 'tcx> TypeErrCtxt<'a, 'tcx> { } } } - - if let Some(file) = long_ty_file { - err.note(format!( - "the full name for the type has been written to '{}'", - file.display(), - )); - err.note("consider using `--verbose` to print the full type name to the console"); - } } #[instrument( @@ -5107,24 +5101,13 @@ pub(super) fn get_explanation_based_on_obligation<'tcx>( _ => None, }; - let pred = obligation.predicate; - let (_, base) = obligation.cause.code().peel_derives_with_predicate(); - let post = if let ty::PredicateKind::Clause(clause) = pred.kind().skip_binder() - && let ty::ClauseKind::Trait(pred) = clause - && let Some(base) = base - && base.skip_binder() != pred - { - format!(", which is required by `{base}`") - } else { - String::new() - }; let desc = match ty_desc { Some(desc) => format!(" {desc}"), None => String::new(), }; if let ty::PredicatePolarity::Positive = trait_predicate.polarity() { format!( - "{pre_message}the trait `{}` is not implemented for{desc} `{}`{post}", + "{pre_message}the trait `{}` is not implemented for{desc} `{}`", trait_predicate.print_modifiers_and_trait_path(), tcx.short_ty_string(trait_predicate.self_ty().skip_binder(), &mut None), ) @@ -5132,7 +5115,7 @@ pub(super) fn get_explanation_based_on_obligation<'tcx>( // "the trait bound `T: !Send` is not satisfied" reads better than "`!Send` is // not implemented for `T`". // FIXME: add note explaining explicit negative trait bounds. - format!("{pre_message}the trait bound `{trait_predicate}` is not satisfied{post}") + format!("{pre_message}the trait bound `{trait_predicate}` is not satisfied") } } } diff --git a/compiler/rustc_trait_selection/src/solve/delegate.rs b/compiler/rustc_trait_selection/src/solve/delegate.rs index 5793ac2fc31..c53689b211d 100644 --- a/compiler/rustc_trait_selection/src/solve/delegate.rs +++ b/compiler/rustc_trait_selection/src/solve/delegate.rs @@ -7,13 +7,13 @@ use rustc_infer::infer::canonical::{ Canonical, CanonicalExt as _, CanonicalQueryInput, CanonicalVarInfo, CanonicalVarValues, }; use rustc_infer::infer::{InferCtxt, RegionVariableOrigin, TyCtxtInferExt}; +use rustc_infer::traits::ObligationCause; use rustc_infer::traits::solve::Goal; -use rustc_infer::traits::{ObligationCause, Reveal}; use rustc_middle::ty::fold::TypeFoldable; use rustc_middle::ty::{self, Ty, TyCtxt, TypeVisitableExt as _}; use rustc_span::{DUMMY_SP, ErrorGuaranteed, Span}; -use rustc_type_ir::solve::{Certainty, NoSolution, SolverMode}; -use tracing::trace; +use rustc_type_ir::TypingMode; +use rustc_type_ir::solve::{Certainty, NoSolution}; use crate::traits::specialization_graph; @@ -47,7 +47,6 @@ impl<'tcx> rustc_next_trait_solver::delegate::SolverDelegate for SolverDelegate< fn build_with_canonical<V>( interner: TyCtxt<'tcx>, - solver_mode: SolverMode, canonical: &CanonicalQueryInput<'tcx, V>, ) -> (Self, V, CanonicalVarValues<'tcx>) where @@ -56,10 +55,6 @@ impl<'tcx> rustc_next_trait_solver::delegate::SolverDelegate for SolverDelegate< let (infcx, value, vars) = interner .infer_ctxt() .with_next_trait_solver(true) - .intercrate(match solver_mode { - SolverMode::Normal => false, - SolverMode::Coherence => true, - }) .build_with_canonical(DUMMY_SP, canonical); (SolverDelegate(infcx), value, vars) } @@ -195,7 +190,6 @@ impl<'tcx> rustc_next_trait_solver::delegate::SolverDelegate for SolverDelegate< fn fetch_eligible_assoc_item( &self, - param_env: ty::ParamEnv<'tcx>, goal_trait_ref: ty::TraitRef<'tcx>, trait_assoc_def_id: DefId, impl_def_id: DefId, @@ -211,12 +205,12 @@ impl<'tcx> rustc_next_trait_solver::delegate::SolverDelegate for SolverDelegate< // and the obligation is monomorphic, otherwise passes such as // transmute checking and polymorphic MIR optimizations could // get a result which isn't correct for all monomorphizations. - if param_env.reveal() == Reveal::All { - let poly_trait_ref = self.resolve_vars_if_possible(goal_trait_ref); - !poly_trait_ref.still_further_specializable() - } else { - trace!(?node_item.item.def_id, "not eligible due to default"); - false + match self.typing_mode_unchecked() { + TypingMode::Coherence | TypingMode::Analysis { .. } => false, + TypingMode::PostAnalysis => { + let poly_trait_ref = self.resolve_vars_if_possible(goal_trait_ref); + !poly_trait_ref.still_further_specializable() + } } }; diff --git a/compiler/rustc_trait_selection/src/traits/auto_trait.rs b/compiler/rustc_trait_selection/src/traits/auto_trait.rs index 934fe9ec47c..52ba5621d31 100644 --- a/compiler/rustc_trait_selection/src/traits/auto_trait.rs +++ b/compiler/rustc_trait_selection/src/traits/auto_trait.rs @@ -10,6 +10,7 @@ use rustc_infer::infer::DefineOpaqueTypes; use rustc_middle::mir::interpret::ErrorHandled; use rustc_middle::ty::{Region, RegionVid}; use tracing::debug; +use ty::TypingMode; use super::*; use crate::errors::UnableToConstructConstantValue; @@ -79,7 +80,7 @@ impl<'tcx> AutoTraitFinder<'tcx> { let trait_ref = ty::TraitRef::new(tcx, trait_did, [ty]); - let infcx = tcx.infer_ctxt().build(); + let infcx = tcx.infer_ctxt().build(TypingMode::non_body_analysis()); let mut selcx = SelectionContext::new(&infcx); for polarity in [ty::PredicatePolarity::Positive, ty::PredicatePolarity::Negative] { let result = selcx.select(&Obligation::new( @@ -99,7 +100,7 @@ impl<'tcx> AutoTraitFinder<'tcx> { } } - let infcx = tcx.infer_ctxt().build(); + let infcx = tcx.infer_ctxt().build(TypingMode::non_body_analysis()); let mut fresh_preds = FxIndexSet::default(); // Due to the way projections are handled by SelectionContext, we need to run diff --git a/compiler/rustc_trait_selection/src/traits/coherence.rs b/compiler/rustc_trait_selection/src/traits/coherence.rs index f8fb297e36c..3cd11d7c8e8 100644 --- a/compiler/rustc_trait_selection/src/traits/coherence.rs +++ b/compiler/rustc_trait_selection/src/traits/coherence.rs @@ -18,7 +18,7 @@ use rustc_middle::traits::solve::{CandidateSource, Certainty, Goal}; use rustc_middle::traits::specialization_graph::OverlapMode; use rustc_middle::ty::fast_reject::DeepRejectCtxt; use rustc_middle::ty::visit::{TypeSuperVisitable, TypeVisitable, TypeVisitableExt, TypeVisitor}; -use rustc_middle::ty::{self, Ty, TyCtxt}; +use rustc_middle::ty::{self, Ty, TyCtxt, TypingMode}; pub use rustc_next_trait_solver::coherence::*; use rustc_next_trait_solver::solve::SolverDelegateEvalExt; use rustc_span::symbol::sym; @@ -195,9 +195,8 @@ fn overlap<'tcx>( let infcx = tcx .infer_ctxt() .skip_leak_check(skip_leak_check.is_yes()) - .intercrate(true) .with_next_trait_solver(tcx.next_trait_solver_in_coherence()) - .build(); + .build(TypingMode::Coherence); let selcx = &mut SelectionContext::new(&infcx); if track_ambiguity_causes.is_yes() { selcx.enable_tracking_intercrate_ambiguity_causes(); @@ -419,7 +418,7 @@ fn impl_intersection_has_negative_obligation( // N.B. We need to unify impl headers *with* intercrate mode, even if proving negative predicates // do not need intercrate mode enabled. - let ref infcx = tcx.infer_ctxt().intercrate(true).with_next_trait_solver(true).build(); + let ref infcx = tcx.infer_ctxt().with_next_trait_solver(true).build(TypingMode::Coherence); let root_universe = infcx.universe(); assert_eq!(root_universe, ty::UniverseIndex::ROOT); @@ -570,7 +569,9 @@ fn try_prove_negated_where_clause<'tcx>( // the *existence* of a negative goal, not the non-existence of a positive goal. // Without this, we over-eagerly register coherence ambiguity candidates when // impl candidates do exist. - let ref infcx = root_infcx.fork_with_intercrate(false); + // FIXME(#132279): `TypingMode::non_body_analysis` is a bit questionable here as it + // would cause us to reveal opaque types to leak their auto traits. + let ref infcx = root_infcx.fork_with_typing_mode(TypingMode::non_body_analysis()); let ocx = ObligationCtxt::new(infcx); ocx.register_obligation(Obligation::new( infcx.tcx, @@ -714,7 +715,10 @@ impl<'a, 'tcx> ProofTreeVisitor<'tcx> for AmbiguityCausesVisitor<'a, 'tcx> { // It is only relevant that a goal is unknowable if it would have otherwise // failed. - let non_intercrate_infcx = infcx.fork_with_intercrate(false); + // FIXME(#132279): Forking with `TypingMode::non_body_analysis` is a bit questionable + // as it would allow us to reveal opaque types, potentially causing unexpected + // cycles. + let non_intercrate_infcx = infcx.fork_with_typing_mode(TypingMode::non_body_analysis()); if non_intercrate_infcx.predicate_may_hold(&Obligation::new( infcx.tcx, ObligationCause::dummy(), diff --git a/compiler/rustc_trait_selection/src/traits/dyn_compatibility.rs b/compiler/rustc_trait_selection/src/traits/dyn_compatibility.rs index a068f25fe35..bd4e3dd7d8d 100644 --- a/compiler/rustc_trait_selection/src/traits/dyn_compatibility.rs +++ b/compiler/rustc_trait_selection/src/traits/dyn_compatibility.rs @@ -14,7 +14,7 @@ use rustc_middle::query::Providers; use rustc_middle::ty::{ self, EarlyBinder, ExistentialPredicateStableCmpExt as _, GenericArgs, Ty, TyCtxt, TypeFoldable, TypeFolder, TypeSuperFoldable, TypeSuperVisitable, TypeVisitable, - TypeVisitableExt, TypeVisitor, Upcast, + TypeVisitableExt, TypeVisitor, TypingMode, Upcast, }; use rustc_span::Span; use rustc_span::symbol::Symbol; @@ -718,7 +718,7 @@ fn receiver_is_dispatchable<'tcx>( Obligation::new(tcx, ObligationCause::dummy(), param_env, predicate) }; - let infcx = tcx.infer_ctxt().build(); + let infcx = tcx.infer_ctxt().build(TypingMode::non_body_analysis()); // the receiver is dispatchable iff the obligation holds infcx.predicate_must_hold_modulo_regions(&obligation) } diff --git a/compiler/rustc_trait_selection/src/traits/effects.rs b/compiler/rustc_trait_selection/src/traits/effects.rs new file mode 100644 index 00000000000..60b3357810a --- /dev/null +++ b/compiler/rustc_trait_selection/src/traits/effects.rs @@ -0,0 +1,153 @@ +use rustc_hir as hir; +use rustc_infer::infer::{BoundRegionConversionTime, DefineOpaqueTypes, InferCtxt}; +use rustc_infer::traits::{ImplSource, Obligation, PredicateObligation}; +use rustc_middle::span_bug; +use rustc_middle::ty::fast_reject::DeepRejectCtxt; +use rustc_middle::ty::{self, TypingMode}; +use rustc_type_ir::solve::NoSolution; +use thin_vec::ThinVec; + +use super::SelectionContext; + +pub type HostEffectObligation<'tcx> = Obligation<'tcx, ty::HostEffectPredicate<'tcx>>; + +pub enum EvaluationFailure { + Ambiguous, + NoSolution, +} + +pub fn evaluate_host_effect_obligation<'tcx>( + selcx: &mut SelectionContext<'_, 'tcx>, + obligation: &HostEffectObligation<'tcx>, +) -> Result<ThinVec<PredicateObligation<'tcx>>, EvaluationFailure> { + if matches!(selcx.infcx.typing_mode(obligation.param_env), TypingMode::Coherence) { + span_bug!( + obligation.cause.span, + "should not select host obligation in old solver in intercrate mode" + ); + } + + match evaluate_host_effect_from_bounds(selcx, obligation) { + Ok(result) => return Ok(result), + Err(EvaluationFailure::Ambiguous) => return Err(EvaluationFailure::Ambiguous), + Err(EvaluationFailure::NoSolution) => {} + } + + match evaluate_host_effect_from_selection_candiate(selcx, obligation) { + Ok(result) => return Ok(result), + Err(EvaluationFailure::Ambiguous) => return Err(EvaluationFailure::Ambiguous), + Err(EvaluationFailure::NoSolution) => {} + } + + Err(EvaluationFailure::NoSolution) +} + +fn match_candidate<'tcx>( + infcx: &InferCtxt<'tcx>, + obligation: &HostEffectObligation<'tcx>, + candidate: ty::Binder<'tcx, ty::HostEffectPredicate<'tcx>>, +) -> Result<ThinVec<PredicateObligation<'tcx>>, NoSolution> { + if !candidate.skip_binder().host.satisfies(obligation.predicate.host) { + return Err(NoSolution); + } + + let candidate = infcx.instantiate_binder_with_fresh_vars( + obligation.cause.span, + BoundRegionConversionTime::HigherRankedType, + candidate, + ); + + let mut nested = infcx + .at(&obligation.cause, obligation.param_env) + .eq(DefineOpaqueTypes::Yes, obligation.predicate.trait_ref, candidate.trait_ref)? + .into_obligations(); + + for nested in &mut nested { + nested.set_depth_from_parent(obligation.recursion_depth); + } + + Ok(nested) +} + +fn evaluate_host_effect_from_bounds<'tcx>( + selcx: &mut SelectionContext<'_, 'tcx>, + obligation: &HostEffectObligation<'tcx>, +) -> Result<ThinVec<PredicateObligation<'tcx>>, EvaluationFailure> { + let infcx = selcx.infcx; + let drcx = DeepRejectCtxt::relate_rigid_rigid(selcx.tcx()); + let mut candidate = None; + + for predicate in obligation.param_env.caller_bounds() { + let bound_predicate = predicate.kind(); + if let ty::ClauseKind::HostEffect(data) = predicate.kind().skip_binder() { + let data = bound_predicate.rebind(data); + if data.skip_binder().trait_ref.def_id != obligation.predicate.trait_ref.def_id { + continue; + } + + if !drcx.args_may_unify( + obligation.predicate.trait_ref.args, + data.skip_binder().trait_ref.args, + ) { + continue; + } + + let is_match = infcx.probe(|_| match_candidate(infcx, obligation, data).is_ok()); + + if is_match { + if candidate.is_some() { + return Err(EvaluationFailure::Ambiguous); + } else { + candidate = Some(data); + } + } + } + } + + if let Some(data) = candidate { + Ok(match_candidate(infcx, obligation, data) + .expect("candidate matched before, so it should match again")) + } else { + Err(EvaluationFailure::NoSolution) + } +} + +fn evaluate_host_effect_from_selection_candiate<'tcx>( + selcx: &mut SelectionContext<'_, 'tcx>, + obligation: &HostEffectObligation<'tcx>, +) -> Result<ThinVec<PredicateObligation<'tcx>>, EvaluationFailure> { + let tcx = selcx.tcx(); + selcx.infcx.commit_if_ok(|_| { + match selcx.select(&obligation.with(tcx, obligation.predicate.trait_ref)) { + Ok(None) => Err(EvaluationFailure::Ambiguous), + Err(_) => Err(EvaluationFailure::NoSolution), + Ok(Some(source)) => match source { + ImplSource::UserDefined(impl_) => { + if tcx.constness(impl_.impl_def_id) != hir::Constness::Const { + return Err(EvaluationFailure::NoSolution); + } + + let mut nested = impl_.nested; + nested.extend( + tcx.const_conditions(impl_.impl_def_id) + .instantiate(tcx, impl_.args) + .into_iter() + .map(|(trait_ref, _)| { + obligation.with( + tcx, + trait_ref.to_host_effect_clause(tcx, obligation.predicate.host), + ) + }), + ); + + for nested in &mut nested { + nested.set_depth_from_parent(obligation.recursion_depth); + } + + Ok(nested) + } + _ => Err(EvaluationFailure::NoSolution), + }, + } + }) +} diff --git a/compiler/rustc_trait_selection/src/traits/fulfill.rs b/compiler/rustc_trait_selection/src/traits/fulfill.rs index 1754418156d..29e60e3c428 100644 --- a/compiler/rustc_trait_selection/src/traits/fulfill.rs +++ b/compiler/rustc_trait_selection/src/traits/fulfill.rs @@ -13,10 +13,11 @@ use rustc_middle::bug; use rustc_middle::mir::interpret::ErrorHandled; use rustc_middle::ty::abstract_const::NotConstEvaluatable; use rustc_middle::ty::error::{ExpectedFound, TypeError}; -use rustc_middle::ty::{self, Binder, Const, GenericArgsRef, TypeVisitableExt}; +use rustc_middle::ty::{self, Binder, Const, GenericArgsRef, TypeVisitableExt, TypingMode}; use thin_vec::ThinVec; use tracing::{debug, debug_span, instrument}; +use super::effects::{self, HostEffectObligation}; use super::project::{self, ProjectAndUnifyResult}; use super::select::SelectionContext; use super::{ @@ -402,8 +403,13 @@ impl<'a, 'tcx> ObligationProcessor for FulfillProcessor<'a, 'tcx> { ) } - ty::PredicateKind::Clause(ty::ClauseKind::HostEffect(..)) => { - ProcessResult::Changed(Default::default()) + ty::PredicateKind::Clause(ty::ClauseKind::HostEffect(data)) => { + let host_obligation = obligation.with(infcx.tcx, data); + + self.process_host_obligation( + host_obligation, + &mut pending_obligation.stalled_on, + ) } ty::PredicateKind::Clause(ty::ClauseKind::RegionOutlives(data)) => { @@ -754,7 +760,9 @@ impl<'a, 'tcx> FulfillProcessor<'a, 'tcx> { stalled_on: &mut Vec<TyOrConstInferVar>, ) -> ProcessResult<PendingPredicateObligation<'tcx>, FulfillmentErrorCode<'tcx>> { let infcx = self.selcx.infcx; - if obligation.predicate.is_global() && !self.selcx.is_intercrate() { + if obligation.predicate.is_global() + && !matches!(infcx.typing_mode(obligation.param_env), TypingMode::Coherence) + { // no type variables present, can use evaluation for better caching. // FIXME: consider caching errors too. if infcx.predicate_must_hold_considering_regions(obligation) { @@ -807,11 +815,13 @@ impl<'a, 'tcx> FulfillProcessor<'a, 'tcx> { stalled_on: &mut Vec<TyOrConstInferVar>, ) -> ProcessResult<PendingPredicateObligation<'tcx>, FulfillmentErrorCode<'tcx>> { let tcx = self.selcx.tcx(); - - if obligation.predicate.is_global() && !self.selcx.is_intercrate() { + let infcx = self.selcx.infcx; + if obligation.predicate.is_global() + && !matches!(infcx.typing_mode(obligation.param_env), TypingMode::Coherence) + { // no type variables present, can use evaluation for better caching. // FIXME: consider caching errors too. - if self.selcx.infcx.predicate_must_hold_considering_regions(obligation) { + if infcx.predicate_must_hold_considering_regions(obligation) { if let Some(key) = ProjectionCacheKey::from_poly_projection_obligation( &mut self.selcx, &project_obligation, @@ -819,8 +829,7 @@ impl<'a, 'tcx> FulfillProcessor<'a, 'tcx> { // If `predicate_must_hold_considering_regions` succeeds, then we've // evaluated all sub-obligations. We can therefore mark the 'root' // obligation as complete, and skip evaluating sub-obligations. - self.selcx - .infcx + infcx .inner .borrow_mut() .projection_cache() @@ -854,6 +863,27 @@ impl<'a, 'tcx> FulfillProcessor<'a, 'tcx> { } } } + + fn process_host_obligation( + &mut self, + host_obligation: HostEffectObligation<'tcx>, + stalled_on: &mut Vec<TyOrConstInferVar>, + ) -> ProcessResult<PendingPredicateObligation<'tcx>, FulfillmentErrorCode<'tcx>> { + match effects::evaluate_host_effect_obligation(&mut self.selcx, &host_obligation) { + Ok(nested) => ProcessResult::Changed(mk_pending(nested)), + Err(effects::EvaluationFailure::Ambiguous) => { + stalled_on.clear(); + stalled_on.extend(args_infer_vars( + &self.selcx, + ty::Binder::dummy(host_obligation.predicate.trait_ref.args), + )); + ProcessResult::Unchanged + } + Err(effects::EvaluationFailure::NoSolution) => { + ProcessResult::Error(FulfillmentErrorCode::Select(SelectionError::Unimplemented)) + } + } + } } /// Returns the set of inference variables contained in `args`. diff --git a/compiler/rustc_trait_selection/src/traits/misc.rs b/compiler/rustc_trait_selection/src/traits/misc.rs index 3e65194577e..3b17fa6b032 100644 --- a/compiler/rustc_trait_selection/src/traits/misc.rs +++ b/compiler/rustc_trait_selection/src/traits/misc.rs @@ -8,7 +8,7 @@ use rustc_data_structures::fx::FxIndexSet; use rustc_hir as hir; use rustc_infer::infer::outlives::env::OutlivesEnvironment; use rustc_infer::infer::{RegionResolutionError, TyCtxtInferExt}; -use rustc_middle::ty::{self, AdtDef, Ty, TyCtxt, TypeVisitableExt}; +use rustc_middle::ty::{self, AdtDef, Ty, TyCtxt, TypeVisitableExt, TypingMode}; use super::outlives_bounds::InferCtxtExt; use crate::regions::InferCtxtRegionExt; @@ -143,7 +143,7 @@ pub fn type_allowed_to_implement_const_param_ty<'tcx>( let mut infringing_inner_tys = vec![]; for inner_ty in inner_tys { // We use an ocx per inner ty for better diagnostics - let infcx = tcx.infer_ctxt().build(); + let infcx = tcx.infer_ctxt().build(TypingMode::non_body_analysis()); let ocx = traits::ObligationCtxt::new_with_diagnostics(&infcx); ocx.register_bound( @@ -200,7 +200,7 @@ pub fn all_fields_implement_trait<'tcx>( for variant in adt.variants() { for field in &variant.fields { // Do this per-field to get better error messages. - let infcx = tcx.infer_ctxt().build(); + let infcx = tcx.infer_ctxt().build(TypingMode::non_body_analysis()); let ocx = traits::ObligationCtxt::new_with_diagnostics(&infcx); let unnormalized_ty = field.ty(tcx, args); diff --git a/compiler/rustc_trait_selection/src/traits/mod.rs b/compiler/rustc_trait_selection/src/traits/mod.rs index cdf24887e76..1c84f2171bc 100644 --- a/compiler/rustc_trait_selection/src/traits/mod.rs +++ b/compiler/rustc_trait_selection/src/traits/mod.rs @@ -6,6 +6,7 @@ pub mod auto_trait; pub(crate) mod coherence; pub mod const_evaluatable; mod dyn_compatibility; +pub mod effects; mod engine; mod fulfill; pub mod misc; @@ -33,7 +34,8 @@ use rustc_middle::ty::error::{ExpectedFound, TypeError}; use rustc_middle::ty::fold::TypeFoldable; use rustc_middle::ty::visit::{TypeVisitable, TypeVisitableExt}; use rustc_middle::ty::{ - self, GenericArgs, GenericArgsRef, Ty, TyCtxt, TypeFolder, TypeSuperVisitable, Upcast, + self, GenericArgs, GenericArgsRef, Ty, TyCtxt, TypeFolder, TypeSuperVisitable, TypingMode, + Upcast, }; use rustc_span::Span; use rustc_span::def_id::DefId; @@ -273,7 +275,7 @@ fn do_normalize_predicates<'tcx>( // by wfcheck anyway, so I'm not sure we have to check // them here too, and we will remove this function when // we move over to lazy normalization *anyway*. - let infcx = tcx.infer_ctxt().ignoring_regions().build(); + let infcx = tcx.infer_ctxt().ignoring_regions().build(TypingMode::non_body_analysis()); let ocx = ObligationCtxt::new_with_diagnostics(&infcx); let predicates = ocx.normalize(&cause, elaborated_env, predicates); @@ -474,11 +476,11 @@ pub fn normalize_param_env_or_error<'tcx>( /// Normalizes the predicates and checks whether they hold in an empty environment. If this /// returns true, then either normalize encountered an error or one of the predicates did not -/// hold. Used when creating vtables to check for unsatisfiable methods. +/// hold. Used when creating vtables to check for unsatisfiable methods. This should not be +/// used during analysis. pub fn impossible_predicates<'tcx>(tcx: TyCtxt<'tcx>, predicates: Vec<ty::Clause<'tcx>>) -> bool { debug!("impossible_predicates(predicates={:?})", predicates); - - let infcx = tcx.infer_ctxt().build(); + let infcx = tcx.infer_ctxt().build(TypingMode::PostAnalysis); let param_env = ty::ParamEnv::reveal_all(); let ocx = ObligationCtxt::new(&infcx); let predicates = ocx.normalize(&ObligationCause::dummy(), param_env, predicates); @@ -567,8 +569,11 @@ fn is_impossible_associated_item( // since that method *may* have some substitutions where the predicates hold. // // This replicates the logic we use in coherence. - let infcx = - tcx.infer_ctxt().ignoring_regions().with_next_trait_solver(true).intercrate(true).build(); + let infcx = tcx + .infer_ctxt() + .ignoring_regions() + .with_next_trait_solver(true) + .build(TypingMode::Coherence); let param_env = ty::ParamEnv::empty(); let fresh_args = infcx.fresh_args_for_item(tcx.def_span(impl_def_id), impl_def_id); diff --git a/compiler/rustc_trait_selection/src/traits/project.rs b/compiler/rustc_trait_selection/src/traits/project.rs index 38722c0ff7c..a75c07c2e8c 100644 --- a/compiler/rustc_trait_selection/src/traits/project.rs +++ b/compiler/rustc_trait_selection/src/traits/project.rs @@ -334,11 +334,6 @@ pub(super) fn opt_normalize_projection_term<'a, 'b, 'tcx>( ) -> Result<Option<Term<'tcx>>, InProgress> { let infcx = selcx.infcx; debug_assert!(!selcx.infcx.next_trait_solver()); - // Don't use the projection cache in intercrate mode - - // the `infcx` may be re-used between intercrate in non-intercrate - // mode, which could lead to using incorrect cache results. - let use_cache = !selcx.is_intercrate(); - let projection_term = infcx.resolve_vars_if_possible(projection_term); let cache_key = ProjectionCacheKey::new(projection_term, param_env); @@ -349,13 +344,8 @@ pub(super) fn opt_normalize_projection_term<'a, 'b, 'tcx>( // would not benefit from caching when proving `T: Trait<U=Foo>` // bounds. It might be the case that we want two distinct caches, // or else another kind of cache entry. - - let cache_result = if use_cache { - infcx.inner.borrow_mut().projection_cache().try_start(cache_key) - } else { - Ok(()) - }; - match cache_result { + let cache_entry = infcx.inner.borrow_mut().projection_cache().try_start(cache_key); + match cache_entry { Ok(()) => debug!("no cache"), Err(ProjectionCacheEntry::Ambiguous) => { // If we found ambiguity the last time, that means we will continue @@ -378,10 +368,7 @@ pub(super) fn opt_normalize_projection_term<'a, 'b, 'tcx>( // Cache that normalizing this projection resulted in a cycle. This // should ensure that, unless this happens within a snapshot that's // rolled back, fulfillment or evaluation will notice the cycle. - - if use_cache { - infcx.inner.borrow_mut().projection_cache().recur(cache_key); - } + infcx.inner.borrow_mut().projection_cache().recur(cache_key); return Err(InProgress); } Err(ProjectionCacheEntry::Recur) => { @@ -445,26 +432,20 @@ pub(super) fn opt_normalize_projection_term<'a, 'b, 'tcx>( let mut deduped = SsoHashSet::with_capacity(result.obligations.len()); result.obligations.retain(|obligation| deduped.insert(obligation.clone())); - if use_cache { - infcx.inner.borrow_mut().projection_cache().insert_term(cache_key, result.clone()); - } + infcx.inner.borrow_mut().projection_cache().insert_term(cache_key, result.clone()); obligations.extend(result.obligations); Ok(Some(result.value)) } Ok(Projected::NoProgress(projected_ty)) => { let result = Normalized { value: projected_ty, obligations: PredicateObligations::new() }; - if use_cache { - infcx.inner.borrow_mut().projection_cache().insert_term(cache_key, result.clone()); - } + infcx.inner.borrow_mut().projection_cache().insert_term(cache_key, result.clone()); // No need to extend `obligations`. Ok(Some(result.value)) } Err(ProjectionError::TooManyCandidates) => { debug!("opt_normalize_projection_type: too many candidates"); - if use_cache { - infcx.inner.borrow_mut().projection_cache().ambiguous(cache_key); - } + infcx.inner.borrow_mut().projection_cache().ambiguous(cache_key); Ok(None) } Err(ProjectionError::TraitSelectionError(_)) => { @@ -473,10 +454,7 @@ pub(super) fn opt_normalize_projection_term<'a, 'b, 'tcx>( // just return `ty::err` but add the obligation `T : // Trait`, which when processed will cause the error to be // reported later - - if use_cache { - infcx.inner.borrow_mut().projection_cache().error(cache_key); - } + infcx.inner.borrow_mut().projection_cache().error(cache_key); let result = normalize_to_error(selcx, param_env, projection_term, cause, depth); obligations.extend(result.obligations); Ok(Some(result.value)) @@ -1180,7 +1158,7 @@ fn assemble_candidates_from_impls<'cx, 'tcx>( selcx.tcx(), selcx.tcx().require_lang_item( LangItem::Sized, - Some(obligation.cause.span()), + Some(obligation.cause.span), ), [self_ty], ), @@ -1600,7 +1578,7 @@ fn confirm_builtin_candidate<'cx, 'tcx>( // exist. Instead, `Pointee<Metadata = ()>` should be a supertrait of `Sized`. let sized_predicate = ty::TraitRef::new( tcx, - tcx.require_lang_item(LangItem::Sized, Some(obligation.cause.span())), + tcx.require_lang_item(LangItem::Sized, Some(obligation.cause.span)), [self_ty], ); obligations.push(obligation.with(tcx, sized_predicate)); diff --git a/compiler/rustc_trait_selection/src/traits/query/evaluate_obligation.rs b/compiler/rustc_trait_selection/src/traits/query/evaluate_obligation.rs index 76017299f2c..9e1a2a3e7d2 100644 --- a/compiler/rustc_trait_selection/src/traits/query/evaluate_obligation.rs +++ b/compiler/rustc_trait_selection/src/traits/query/evaluate_obligation.rs @@ -87,10 +87,9 @@ impl<'tcx> InferCtxt<'tcx> { Ok(result) }) } else { - assert!(!self.intercrate); let c_pred = self.canonicalize_query(param_env.and(obligation.predicate), &mut _orig_values); - self.tcx.at(obligation.cause.span()).evaluate_obligation(c_pred) + self.tcx.at(obligation.cause.span).evaluate_obligation(c_pred) } } diff --git a/compiler/rustc_trait_selection/src/traits/select/candidate_assembly.rs b/compiler/rustc_trait_selection/src/traits/select/candidate_assembly.rs index e027586563e..03fde1d1598 100644 --- a/compiler/rustc_trait_selection/src/traits/select/candidate_assembly.rs +++ b/compiler/rustc_trait_selection/src/traits/select/candidate_assembly.rs @@ -16,7 +16,7 @@ use rustc_infer::traits::{ Obligation, ObligationCause, PolyTraitObligation, PredicateObligations, SelectionError, }; use rustc_middle::ty::fast_reject::DeepRejectCtxt; -use rustc_middle::ty::{self, ToPolyTraitRef, Ty, TypeVisitableExt}; +use rustc_middle::ty::{self, ToPolyTraitRef, Ty, TypeVisitableExt, TypingMode}; use rustc_middle::{bug, span_bug}; use tracing::{debug, instrument, trace}; @@ -790,7 +790,9 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> { // // Note that this is only sound as projection candidates of opaque types // are always applicable for auto traits. - } else if self.infcx.intercrate { + } else if let TypingMode::Coherence = + self.infcx.typing_mode(obligation.param_env) + { // We do not emit auto trait candidates for opaque types in coherence. // Doing so can result in weird dependency cycles. candidates.ambiguous = true; @@ -930,7 +932,10 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> { ) -> Option<ty::PolyExistentialTraitRef<'tcx>> { // Don't drop any candidates in intercrate mode, as it's incomplete. // (Not that it matters, since `Unsize` is not a stable trait.) - if self.infcx.intercrate { + // + // FIXME(@lcnr): This should probably only trigger during analysis, + // disabling candidates during codegen is also questionable. + if let TypingMode::Coherence = self.infcx.typing_mode(param_env) { return None; } diff --git a/compiler/rustc_trait_selection/src/traits/select/mod.rs b/compiler/rustc_trait_selection/src/traits/select/mod.rs index ec4114fd9d7..b1e5e526315 100644 --- a/compiler/rustc_trait_selection/src/traits/select/mod.rs +++ b/compiler/rustc_trait_selection/src/traits/select/mod.rs @@ -2,6 +2,7 @@ //! //! [rustc dev guide]: https://rustc-dev-guide.rust-lang.org/traits/resolution.html#selection +use std::assert_matches::assert_matches; use std::cell::{Cell, RefCell}; use std::fmt::{self, Display}; use std::ops::ControlFlow; @@ -28,7 +29,7 @@ use rustc_middle::ty::error::TypeErrorToStringExt; use rustc_middle::ty::print::{PrintTraitRefExt as _, with_no_trimmed_paths}; use rustc_middle::ty::{ self, GenericArgsRef, PolyProjectionPredicate, Ty, TyCtxt, TypeFoldable, TypeVisitableExt, - Upcast, + TypingMode, Upcast, }; use rustc_span::Symbol; use rustc_span::symbol::sym; @@ -49,7 +50,7 @@ use crate::infer::{InferCtxt, InferOk, TypeFreshener}; use crate::solve::InferCtxtSelectExt as _; use crate::traits::normalize::{normalize_with_depth, normalize_with_depth_to}; use crate::traits::project::{ProjectAndUnifyResult, ProjectionCacheKeyExt}; -use crate::traits::{ProjectionCacheKey, Unimplemented}; +use crate::traits::{ProjectionCacheKey, Unimplemented, effects}; mod _match; mod candidate_assembly; @@ -222,7 +223,7 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> { /// Enables tracking of intercrate ambiguity causes. See /// the documentation of [`Self::intercrate_ambiguity_causes`] for more. pub fn enable_tracking_intercrate_ambiguity_causes(&mut self) { - assert!(self.is_intercrate()); + assert_matches!(self.infcx.typing_mode_unchecked(), TypingMode::Coherence); assert!(self.intercrate_ambiguity_causes.is_none()); self.intercrate_ambiguity_causes = Some(FxIndexSet::default()); debug!("selcx: enable_tracking_intercrate_ambiguity_causes"); @@ -234,7 +235,7 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> { pub fn take_intercrate_ambiguity_causes( &mut self, ) -> FxIndexSet<IntercrateAmbiguityCause<'tcx>> { - assert!(self.is_intercrate()); + assert_matches!(self.infcx.typing_mode_unchecked(), TypingMode::Coherence); self.intercrate_ambiguity_causes.take().unwrap_or_default() } @@ -242,10 +243,6 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> { self.infcx.tcx } - pub fn is_intercrate(&self) -> bool { - self.infcx.intercrate - } - /////////////////////////////////////////////////////////////////////////// // Selection // @@ -645,11 +642,19 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> { self.evaluate_trait_predicate_recursively(previous_stack, obligation) } - ty::PredicateKind::Clause(ty::ClauseKind::HostEffect(..)) => { - // FIXME(effects): It should be relatively straightforward to implement - // old trait solver support for `HostEffect` bounds; or at least basic - // support for them. - todo!() + ty::PredicateKind::Clause(ty::ClauseKind::HostEffect(data)) => { + self.infcx.enter_forall(bound_predicate.rebind(data), |data| { + match effects::evaluate_host_effect_obligation( + self, + &obligation.with(self.tcx(), data), + ) { + Ok(nested) => { + self.evaluate_predicates_recursively(previous_stack, nested) + } + Err(effects::EvaluationFailure::Ambiguous) => Ok(EvaluatedToAmbig), + Err(effects::EvaluationFailure::NoSolution) => Ok(EvaluatedToErr), + } + }) } ty::PredicateKind::Subtype(p) => { @@ -1021,7 +1026,7 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> { previous_stack: TraitObligationStackList<'o, 'tcx>, mut obligation: PolyTraitObligation<'tcx>, ) -> Result<EvaluationResult, OverflowError> { - if !self.is_intercrate() + if !matches!(self.infcx.typing_mode(obligation.param_env), TypingMode::Coherence) && obligation.is_global() && obligation.param_env.caller_bounds().iter().all(|bound| bound.has_param()) { @@ -1304,14 +1309,6 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> { param_env: ty::ParamEnv<'tcx>, trait_pred: ty::PolyTraitPredicate<'tcx>, ) -> Option<EvaluationResult> { - // Neither the global nor local cache is aware of intercrate - // mode, so don't do any caching. In particular, we might - // re-use the same `InferCtxt` with both an intercrate - // and non-intercrate `SelectionContext` - if self.is_intercrate() { - return None; - } - let tcx = self.tcx(); if self.can_use_global_caches(param_env) { if let Some(res) = tcx.evaluation_cache.get(&(param_env, trait_pred), tcx) { @@ -1334,14 +1331,6 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> { return; } - // Neither the global nor local cache is aware of intercrate - // mode, so don't do any caching. In particular, we might - // re-use the same `InferCtxt` with both an intercrate - // and non-intercrate `SelectionContext` - if self.is_intercrate() { - return; - } - if self.can_use_global_caches(param_env) && !trait_pred.has_infer() { debug!(?trait_pred, ?result, "insert_evaluation_cache global"); // This may overwrite the cache with the same value @@ -1468,13 +1457,14 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> { } fn is_knowable<'o>(&mut self, stack: &TraitObligationStack<'o, 'tcx>) -> Result<(), Conflict> { - debug!("is_knowable(intercrate={:?})", self.is_intercrate()); - - if !self.is_intercrate() { - return Ok(()); + let obligation = &stack.obligation; + match self.infcx.typing_mode(obligation.param_env) { + TypingMode::Coherence => {} + TypingMode::Analysis { .. } | TypingMode::PostAnalysis => return Ok(()), } - let obligation = &stack.obligation; + debug!("is_knowable()"); + let predicate = self.infcx.resolve_vars_if_possible(obligation.predicate); // Okay to skip binder because of the nature of the @@ -1494,25 +1484,24 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> { return false; } - // Avoid using the global cache during coherence and just rely - // on the local cache. This effectively disables caching - // during coherence. It is really just a simplification to - // avoid us having to fear that coherence results "pollute" - // the master cache. Since coherence executes pretty quickly, - // it's not worth going to more trouble to increase the - // hit-rate, I don't think. - if self.is_intercrate() { - return false; - } - - // Avoid using the global cache when we're defining opaque types - // as their hidden type may impact the result of candidate selection. - if !self.infcx.defining_opaque_types().is_empty() { - return false; + match self.infcx.typing_mode(param_env) { + // Avoid using the global cache during coherence and just rely + // on the local cache. It is really just a simplification to + // avoid us having to fear that coherence results "pollute" + // the master cache. Since coherence executes pretty quickly, + // it's not worth going to more trouble to increase the + // hit-rate, I don't think. + TypingMode::Coherence => false, + // Avoid using the global cache when we're defining opaque types + // as their hidden type may impact the result of candidate selection. + TypingMode::Analysis { defining_opaque_types } => defining_opaque_types.is_empty(), + // The global cache is only used if there are no opaque types in + // the defining scope or we're outside of analysis. + // + // FIXME(#132279): This is still incorrect as we treat opaque types + // and default associated items differently between these two modes. + TypingMode::PostAnalysis => true, } - - // Otherwise, we can use the global cache. - true } fn check_candidate_cache( @@ -1520,13 +1509,6 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> { param_env: ty::ParamEnv<'tcx>, cache_fresh_trait_pred: ty::PolyTraitPredicate<'tcx>, ) -> Option<SelectionResult<'tcx, SelectionCandidate<'tcx>>> { - // Neither the global nor local cache is aware of intercrate - // mode, so don't do any caching. In particular, we might - // re-use the same `InferCtxt` with both an intercrate - // and non-intercrate `SelectionContext` - if self.is_intercrate() { - return None; - } let tcx = self.tcx(); let pred = cache_fresh_trait_pred.skip_binder(); @@ -1558,13 +1540,6 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> { &self, result: &SelectionResult<'tcx, SelectionCandidate<'tcx>>, ) -> bool { - // Neither the global nor local cache is aware of intercrate - // mode, so don't do any caching. In particular, we might - // re-use the same `InferCtxt` with both an intercrate - // and non-intercrate `SelectionContext` - if self.is_intercrate() { - return false; - } match result { Ok(Some(SelectionCandidate::ParamCandidate(trait_ref))) => !trait_ref.has_infer(), _ => true, @@ -2533,7 +2508,9 @@ impl<'tcx> SelectionContext<'_, 'tcx> { })?; nested_obligations.extend(obligations); - if !self.is_intercrate() && impl_trait_header.polarity == ty::ImplPolarity::Reservation { + if impl_trait_header.polarity == ty::ImplPolarity::Reservation + && !matches!(self.infcx.typing_mode(obligation.param_env), TypingMode::Coherence) + { debug!("reservation impls only apply in intercrate mode"); return Err(()); } diff --git a/compiler/rustc_trait_selection/src/traits/specialize/mod.rs b/compiler/rustc_trait_selection/src/traits/specialize/mod.rs index 0e45f7a195f..5bf3dbcbc32 100644 --- a/compiler/rustc_trait_selection/src/traits/specialize/mod.rs +++ b/compiler/rustc_trait_selection/src/traits/specialize/mod.rs @@ -19,7 +19,9 @@ use rustc_infer::infer::DefineOpaqueTypes; use rustc_middle::bug; use rustc_middle::query::LocalCrate; use rustc_middle::ty::print::PrintTraitRefExt as _; -use rustc_middle::ty::{self, GenericArgsRef, ImplSubject, Ty, TyCtxt, TypeVisitableExt}; +use rustc_middle::ty::{ + self, GenericArgsRef, ImplSubject, Ty, TyCtxt, TypeVisitableExt, TypingMode, +}; use rustc_session::lint::builtin::{COHERENCE_LEAK_CHECK, ORDER_DEPENDENT_TRAIT_OBJECTS}; use rustc_span::{DUMMY_SP, ErrorGuaranteed, Span, sym}; use specialization_graph::GraphExt; @@ -184,7 +186,7 @@ pub(super) fn specializes(tcx: TyCtxt<'_>, (impl1_def_id, impl2_def_id): (DefId, let penv = tcx.param_env(impl1_def_id); // Create an infcx, taking the predicates of impl1 as assumptions: - let infcx = tcx.infer_ctxt().build(); + let infcx = tcx.infer_ctxt().build(TypingMode::non_body_analysis()); // Attempt to prove that impl2 applies, given all of the above. fulfill_implication( diff --git a/compiler/rustc_trait_selection/src/traits/vtable.rs b/compiler/rustc_trait_selection/src/traits/vtable.rs index ed221e2a183..bb56d6eaf54 100644 --- a/compiler/rustc_trait_selection/src/traits/vtable.rs +++ b/compiler/rustc_trait_selection/src/traits/vtable.rs @@ -9,7 +9,8 @@ use rustc_infer::traits::util::PredicateSet; use rustc_middle::bug; use rustc_middle::query::Providers; use rustc_middle::ty::{ - self, GenericArgs, GenericParamDefKind, Ty, TyCtxt, TypeVisitableExt, Upcast, VtblEntry, + self, GenericArgs, GenericParamDefKind, Ty, TyCtxt, TypeVisitableExt, TypingMode, Upcast, + VtblEntry, }; use rustc_span::{DUMMY_SP, Span, sym}; use smallvec::{SmallVec, smallvec}; @@ -439,7 +440,7 @@ fn trait_refs_are_compatible<'tcx>( return false; } - let infcx = tcx.infer_ctxt().build(); + let infcx = tcx.infer_ctxt().build(TypingMode::PostAnalysis); let param_env = ty::ParamEnv::reveal_all(); let ocx = ObligationCtxt::new(&infcx); let hr_source_principal = diff --git a/compiler/rustc_traits/src/codegen.rs b/compiler/rustc_traits/src/codegen.rs index 11182198246..d8c1c50d79a 100644 --- a/compiler/rustc_traits/src/codegen.rs +++ b/compiler/rustc_traits/src/codegen.rs @@ -6,7 +6,7 @@ use rustc_infer::infer::TyCtxtInferExt; use rustc_middle::bug; use rustc_middle::traits::CodegenObligationError; -use rustc_middle::ty::{self, TyCtxt, TypeVisitableExt}; +use rustc_middle::ty::{self, TyCtxt, TypeVisitableExt, TypingMode}; use rustc_trait_selection::error_reporting::InferCtxtErrorExt; use rustc_trait_selection::traits::{ ImplSource, Obligation, ObligationCause, ObligationCtxt, ScrubbedTraitError, SelectionContext, @@ -30,7 +30,7 @@ pub(crate) fn codegen_select_candidate<'tcx>( // Do the initial selection for the obligation. This yields the // shallow result we are looking for -- that is, what specific impl. - let infcx = tcx.infer_ctxt().ignoring_regions().build(); + let infcx = tcx.infer_ctxt().ignoring_regions().build(TypingMode::from_param_env(param_env)); let mut selcx = SelectionContext::new(&infcx); let obligation_cause = ObligationCause::dummy(); diff --git a/compiler/rustc_traits/src/normalize_erasing_regions.rs b/compiler/rustc_traits/src/normalize_erasing_regions.rs index 3e2794f6489..d79059a39a1 100644 --- a/compiler/rustc_traits/src/normalize_erasing_regions.rs +++ b/compiler/rustc_traits/src/normalize_erasing_regions.rs @@ -1,7 +1,7 @@ use rustc_infer::infer::TyCtxtInferExt; use rustc_middle::query::Providers; use rustc_middle::traits::query::NoSolution; -use rustc_middle::ty::{self, ParamEnvAnd, TyCtxt, TypeFoldable, TypeVisitableExt}; +use rustc_middle::ty::{self, ParamEnvAnd, TyCtxt, TypeFoldable, TypeVisitableExt, TypingMode}; use rustc_trait_selection::traits::query::normalize::QueryNormalizeExt; use rustc_trait_selection::traits::{Normalized, ObligationCause}; use tracing::debug; @@ -22,7 +22,7 @@ fn try_normalize_after_erasing_regions<'tcx, T: TypeFoldable<TyCtxt<'tcx>> + Par goal: ParamEnvAnd<'tcx, T>, ) -> Result<T, NoSolution> { let ParamEnvAnd { param_env, value } = goal; - let infcx = tcx.infer_ctxt().build(); + let infcx = tcx.infer_ctxt().build(TypingMode::from_param_env(param_env)); let cause = ObligationCause::dummy(); match infcx.at(&cause, param_env).query_normalize(value) { Ok(Normalized { value: normalized_value, obligations: normalized_obligations }) => { diff --git a/compiler/rustc_transmute/Cargo.toml b/compiler/rustc_transmute/Cargo.toml index 4732e968f6b..6a98be18503 100644 --- a/compiler/rustc_transmute/Cargo.toml +++ b/compiler/rustc_transmute/Cargo.toml @@ -5,6 +5,7 @@ edition = "2021" [dependencies] # tidy-alphabetical-start +rustc_abi = { path = "../rustc_abi", optional = true } rustc_ast_ir = { path = "../rustc_ast_ir", optional = true } rustc_data_structures = { path = "../rustc_data_structures" } rustc_hir = { path = "../rustc_hir", optional = true } @@ -12,19 +13,18 @@ rustc_infer = { path = "../rustc_infer", optional = true } rustc_macros = { path = "../rustc_macros", optional = true } rustc_middle = { path = "../rustc_middle", optional = true } rustc_span = { path = "../rustc_span", optional = true } -rustc_target = { path = "../rustc_target", optional = true } tracing = "0.1" # tidy-alphabetical-end [features] rustc = [ + "dep:rustc_abi", + "dep:rustc_ast_ir", "dep:rustc_hir", "dep:rustc_infer", "dep:rustc_macros", "dep:rustc_middle", "dep:rustc_span", - "dep:rustc_target", - "dep:rustc_ast_ir", ] [dev-dependencies] diff --git a/compiler/rustc_transmute/src/layout/mod.rs b/compiler/rustc_transmute/src/layout/mod.rs index a5c47c480e1..c4c01a8fac3 100644 --- a/compiler/rustc_transmute/src/layout/mod.rs +++ b/compiler/rustc_transmute/src/layout/mod.rs @@ -62,10 +62,10 @@ impl Ref for ! { pub mod rustc { use std::fmt::{self, Write}; + use rustc_abi::Layout; use rustc_middle::mir::Mutability; use rustc_middle::ty::layout::{HasTyCtxt, LayoutCx, LayoutError}; use rustc_middle::ty::{self, Ty}; - use rustc_target::abi::Layout; /// A reference in the layout. #[derive(Debug, Hash, Eq, PartialEq, Clone, Copy)] diff --git a/compiler/rustc_transmute/src/layout/tree.rs b/compiler/rustc_transmute/src/layout/tree.rs index 17eddbfcd7f..f19a567cd84 100644 --- a/compiler/rustc_transmute/src/layout/tree.rs +++ b/compiler/rustc_transmute/src/layout/tree.rs @@ -171,12 +171,12 @@ where #[cfg(feature = "rustc")] pub(crate) mod rustc { + use rustc_abi::{ + FieldIdx, FieldsShape, Layout, Size, TagEncoding, TyAndLayout, VariantIdx, Variants, + }; use rustc_middle::ty::layout::{HasTyCtxt, LayoutCx, LayoutError}; use rustc_middle::ty::{self, AdtDef, AdtKind, List, ScalarInt, Ty, TyCtxt, TypeVisitableExt}; use rustc_span::ErrorGuaranteed; - use rustc_target::abi::{ - FieldIdx, FieldsShape, Layout, Size, TagEncoding, TyAndLayout, VariantIdx, Variants, - }; use super::Tree; use crate::layout::rustc::{Def, Ref, layout_of}; @@ -206,7 +206,7 @@ pub(crate) mod rustc { impl<'tcx> Tree<Def<'tcx>, Ref<'tcx>> { pub(crate) fn from_ty(ty: Ty<'tcx>, cx: LayoutCx<'tcx>) -> Result<Self, Err> { - use rustc_target::abi::HasDataLayout; + use rustc_abi::HasDataLayout; let layout = layout_of(cx, ty)?; if let Err(e) = ty.error_reported() { @@ -339,9 +339,7 @@ pub(crate) mod rustc { // 2. enums that delegate their layout to a variant // 3. enums with multiple variants match layout.variants() { - Variants::Single { .. } - if layout.abi.is_uninhabited() && layout.size == Size::ZERO => - { + Variants::Single { .. } if layout.is_uninhabited() && layout.size == Size::ZERO => { // The layout representation of uninhabited, ZST enums is // defined to be like that of the `!` type, as opposed of a // typical enum. Consequently, they cannot be descended into @@ -446,7 +444,7 @@ pub(crate) mod rustc { /// Constructs a `Tree` representing the value of a enum tag. fn from_tag(tag: ScalarInt, tcx: TyCtxt<'tcx>) -> Self { - use rustc_target::abi::Endian; + use rustc_abi::Endian; let size = tag.size(); let bits = tag.to_bits(size); let bytes: [u8; 16]; diff --git a/compiler/rustc_ty_utils/src/assoc.rs b/compiler/rustc_ty_utils/src/assoc.rs index 16fd28201c2..f177b609485 100644 --- a/compiler/rustc_ty_utils/src/assoc.rs +++ b/compiler/rustc_ty_utils/src/assoc.rs @@ -190,7 +190,7 @@ fn associated_types_for_impl_traits_in_associated_fn( impl<'tcx> Visitor<'tcx> for RPITVisitor { fn visit_ty(&mut self, ty: &'tcx hir::Ty<'tcx>) { - if let hir::TyKind::OpaqueDef(opaq, _) = ty.kind + if let hir::TyKind::OpaqueDef(opaq) = ty.kind && self.rpits.insert(opaq.def_id) { for bound in opaq.bounds { diff --git a/compiler/rustc_ty_utils/src/common_traits.rs b/compiler/rustc_ty_utils/src/common_traits.rs index 51b908881eb..c26b41d8960 100644 --- a/compiler/rustc_ty_utils/src/common_traits.rs +++ b/compiler/rustc_ty_utils/src/common_traits.rs @@ -3,7 +3,7 @@ use rustc_hir::lang_items::LangItem; use rustc_infer::infer::TyCtxtInferExt; use rustc_middle::query::Providers; -use rustc_middle::ty::{self, Ty, TyCtxt}; +use rustc_middle::ty::{self, Ty, TyCtxt, TypingMode}; use rustc_trait_selection::traits; fn is_copy_raw<'tcx>(tcx: TyCtxt<'tcx>, query: ty::ParamEnvAnd<'tcx, Ty<'tcx>>) -> bool { @@ -29,7 +29,7 @@ fn is_item_raw<'tcx>( ) -> bool { let (param_env, ty) = query.into_parts(); let trait_def_id = tcx.require_lang_item(item, None); - let infcx = tcx.infer_ctxt().build(); + let infcx = tcx.infer_ctxt().build(TypingMode::from_param_env(param_env)); traits::type_known_to_meet_bound_modulo_regions(&infcx, param_env, ty, trait_def_id) } diff --git a/compiler/rustc_ty_utils/src/instance.rs b/compiler/rustc_ty_utils/src/instance.rs index 9b764133f2c..e258b6dae0b 100644 --- a/compiler/rustc_ty_utils/src/instance.rs +++ b/compiler/rustc_ty_utils/src/instance.rs @@ -6,7 +6,7 @@ use rustc_middle::bug; use rustc_middle::query::Providers; use rustc_middle::traits::{BuiltinImplSource, CodegenObligationError}; use rustc_middle::ty::util::AsyncDropGlueMorphology; -use rustc_middle::ty::{self, GenericArgsRef, Instance, TyCtxt, TypeVisitableExt}; +use rustc_middle::ty::{self, GenericArgsRef, Instance, TyCtxt, TypeVisitableExt, TypingMode}; use rustc_span::sym; use rustc_trait_selection::traits; use rustc_type_ir::ClosureKind; @@ -130,7 +130,7 @@ fn resolve_associated_item<'tcx>( .unwrap_or_else(|| { bug!("{:?} not found in {:?}", trait_item_id, impl_data.impl_def_id); }); - let infcx = tcx.infer_ctxt().build(); + let infcx = tcx.infer_ctxt().build(TypingMode::PostAnalysis); let param_env = param_env.with_reveal_all_normalized(tcx); let args = rcvr_args.rebase_onto(tcx, trait_def_id, impl_data.args); let args = translate_args( diff --git a/compiler/rustc_ty_utils/src/layout.rs b/compiler/rustc_ty_utils/src/layout.rs index e755e90aa65..94b80e2694d 100644 --- a/compiler/rustc_ty_utils/src/layout.rs +++ b/compiler/rustc_ty_utils/src/layout.rs @@ -6,7 +6,7 @@ use rustc_abi::Integer::{I8, I32}; use rustc_abi::Primitive::{self, Float, Int, Pointer}; use rustc_abi::{ Abi, AbiAndPrefAlign, AddressSpace, Align, FieldsShape, HasDataLayout, LayoutCalculatorError, - LayoutS, Niche, ReprOptions, Scalar, Size, StructKind, TagEncoding, Variants, WrappingRange, + LayoutData, Niche, ReprOptions, Scalar, Size, StructKind, TagEncoding, Variants, WrappingRange, }; use rustc_index::bit_set::BitSet; use rustc_index::{IndexSlice, IndexVec}; @@ -131,7 +131,7 @@ fn univariant_uninterned<'tcx>( fields: &IndexSlice<FieldIdx, TyAndLayout<'tcx>>, repr: &ReprOptions, kind: StructKind, -) -> Result<LayoutS<FieldIdx, VariantIdx>, &'tcx LayoutError<'tcx>> { +) -> Result<LayoutData<FieldIdx, VariantIdx>, &'tcx LayoutError<'tcx>> { let pack = repr.pack; if pack.is_some() && repr.align.is_some() { cx.tcx().dcx().bug("struct cannot be packed and aligned"); @@ -159,7 +159,7 @@ fn layout_of_uncached<'tcx>( assert!(size.bits() <= 128); Scalar::Initialized { value, valid_range: WrappingRange::full(size) } }; - let scalar = |value: Primitive| tcx.mk_layout(LayoutS::scalar(cx, scalar_unit(value))); + let scalar = |value: Primitive| tcx.mk_layout(LayoutData::scalar(cx, scalar_unit(value))); let univariant = |fields: &IndexSlice<FieldIdx, TyAndLayout<'tcx>>, repr: &ReprOptions, kind| { @@ -170,7 +170,7 @@ fn layout_of_uncached<'tcx>( Ok(match *ty.kind() { ty::Pat(ty, pat) => { let layout = cx.layout_of(ty)?.layout; - let mut layout = LayoutS::clone(&layout.0); + let mut layout = LayoutData::clone(&layout.0); match *pat { ty::PatternKind::Range { start, end, include_end } => { if let Abi::Scalar(scalar) | Abi::ScalarPair(scalar, _) = &mut layout.abi { @@ -206,11 +206,11 @@ fn layout_of_uncached<'tcx>( } // Basic scalars. - ty::Bool => tcx.mk_layout(LayoutS::scalar(cx, Scalar::Initialized { + ty::Bool => tcx.mk_layout(LayoutData::scalar(cx, Scalar::Initialized { value: Int(I8, false), valid_range: WrappingRange { start: 0, end: 1 }, })), - ty::Char => tcx.mk_layout(LayoutS::scalar(cx, Scalar::Initialized { + ty::Char => tcx.mk_layout(LayoutData::scalar(cx, Scalar::Initialized { value: Int(I32, false), valid_range: WrappingRange { start: 0, end: 0x10FFFF }, })), @@ -220,7 +220,7 @@ fn layout_of_uncached<'tcx>( ty::FnPtr(..) => { let mut ptr = scalar_unit(Pointer(dl.instruction_address_space)); ptr.valid_range_mut().start = 1; - tcx.mk_layout(LayoutS::scalar(cx, ptr)) + tcx.mk_layout(LayoutData::scalar(cx, ptr)) } // The never type. @@ -235,7 +235,7 @@ fn layout_of_uncached<'tcx>( let pointee = tcx.normalize_erasing_regions(param_env, pointee); if pointee.is_sized(tcx, param_env) { - return Ok(tcx.mk_layout(LayoutS::scalar(cx, data_ptr))); + return Ok(tcx.mk_layout(LayoutData::scalar(cx, data_ptr))); } let metadata = if let Some(metadata_def_id) = tcx.lang_items().metadata_type() @@ -272,7 +272,7 @@ fn layout_of_uncached<'tcx>( let metadata_layout = cx.layout_of(metadata_ty)?; // If the metadata is a 1-zst, then the pointer is thin. if metadata_layout.is_1zst() { - return Ok(tcx.mk_layout(LayoutS::scalar(cx, data_ptr))); + return Ok(tcx.mk_layout(LayoutData::scalar(cx, data_ptr))); } let Abi::Scalar(metadata) = metadata_layout.abi else { @@ -285,7 +285,7 @@ fn layout_of_uncached<'tcx>( match unsized_part.kind() { ty::Foreign(..) => { - return Ok(tcx.mk_layout(LayoutS::scalar(cx, data_ptr))); + return Ok(tcx.mk_layout(LayoutData::scalar(cx, data_ptr))); } ty::Slice(_) | ty::Str => scalar_unit(Int(dl.ptr_sized_integer(), false)), ty::Dynamic(..) => { @@ -337,7 +337,7 @@ fn layout_of_uncached<'tcx>( let largest_niche = if count != 0 { element.largest_niche } else { None }; - tcx.mk_layout(LayoutS { + tcx.mk_layout(LayoutData { variants: Variants::Single { index: FIRST_VARIANT }, fields: FieldsShape::Array { stride: element.size, count }, abi, @@ -350,7 +350,7 @@ fn layout_of_uncached<'tcx>( } ty::Slice(element) => { let element = cx.layout_of(element)?; - tcx.mk_layout(LayoutS { + tcx.mk_layout(LayoutData { variants: Variants::Single { index: FIRST_VARIANT }, fields: FieldsShape::Array { stride: element.size, count: 0 }, abi: Abi::Aggregate { sized: false }, @@ -361,7 +361,7 @@ fn layout_of_uncached<'tcx>( unadjusted_abi_align: element.align.abi, }) } - ty::Str => tcx.mk_layout(LayoutS { + ty::Str => tcx.mk_layout(LayoutData { variants: Variants::Single { index: FIRST_VARIANT }, fields: FieldsShape::Array { stride: Size::from_bytes(1), count: 0 }, abi: Abi::Aggregate { sized: false }, @@ -532,7 +532,7 @@ fn layout_of_uncached<'tcx>( FieldsShape::Array { stride: e_ly.size, count: e_len } }; - tcx.mk_layout(LayoutS { + tcx.mk_layout(LayoutData { variants: Variants::Single { index: FIRST_VARIANT }, fields, abi, @@ -835,7 +835,7 @@ fn coroutine_layout<'tcx>( }; let tag_layout = TyAndLayout { ty: discr_int.to_ty(tcx, /* signed = */ false), - layout: tcx.mk_layout(LayoutS::scalar(cx, tag)), + layout: tcx.mk_layout(LayoutData::scalar(cx, tag)), }; let promoted_layouts = ineligible_locals.iter().map(|local| { @@ -991,7 +991,7 @@ fn coroutine_layout<'tcx>( Abi::Aggregate { sized: true } }; - let layout = tcx.mk_layout(LayoutS { + let layout = tcx.mk_layout(LayoutData { variants: Variants::Multiple { tag, tag_encoding: TagEncoding::Direct, diff --git a/compiler/rustc_ty_utils/src/layout/invariant.rs b/compiler/rustc_ty_utils/src/layout/invariant.rs index 6cf114b74c1..3db5a4f1805 100644 --- a/compiler/rustc_ty_utils/src/layout/invariant.rs +++ b/compiler/rustc_ty_utils/src/layout/invariant.rs @@ -10,7 +10,7 @@ pub(super) fn partially_check_layout<'tcx>(cx: &LayoutCx<'tcx>, layout: &TyAndLa // Type-level uninhabitedness should always imply ABI uninhabitedness. if layout.ty.is_privately_uninhabited(tcx, cx.param_env) { - assert!(layout.abi.is_uninhabited()); + assert!(layout.is_uninhabited()); } if layout.size.bytes() % layout.align.abi.bytes() != 0 { @@ -262,9 +262,7 @@ pub(super) fn partially_check_layout<'tcx>(cx: &LayoutCx<'tcx>, layout: &TyAndLa ) } // Skip empty variants. - if variant.size == Size::ZERO - || variant.fields.count() == 0 - || variant.abi.is_uninhabited() + if variant.size == Size::ZERO || variant.fields.count() == 0 || variant.is_uninhabited() { // These are never actually accessed anyway, so we can skip the coherence check // for them. They also fail that check, since they have diff --git a/compiler/rustc_ty_utils/src/structural_match.rs b/compiler/rustc_ty_utils/src/structural_match.rs index 1ead7b731e7..0b4efab1d9c 100644 --- a/compiler/rustc_ty_utils/src/structural_match.rs +++ b/compiler/rustc_ty_utils/src/structural_match.rs @@ -1,7 +1,7 @@ use rustc_hir::lang_items::LangItem; use rustc_infer::infer::TyCtxtInferExt; use rustc_middle::query::Providers; -use rustc_middle::ty::{self, Ty, TyCtxt}; +use rustc_middle::ty::{self, Ty, TyCtxt, TypingMode}; use rustc_trait_selection::traits::{ObligationCause, ObligationCtxt}; /// This method returns true if and only if `adt_ty` itself has been marked as @@ -11,7 +11,7 @@ use rustc_trait_selection::traits::{ObligationCause, ObligationCtxt}; /// Note that this does *not* recursively check if the substructure of `adt_ty` /// implements the trait. fn has_structural_eq_impl<'tcx>(tcx: TyCtxt<'tcx>, adt_ty: Ty<'tcx>) -> bool { - let infcx = &tcx.infer_ctxt().build(); + let infcx = &tcx.infer_ctxt().build(TypingMode::non_body_analysis()); let cause = ObligationCause::dummy(); let ocx = ObligationCtxt::new(infcx); diff --git a/compiler/rustc_type_ir/src/canonical.rs b/compiler/rustc_type_ir/src/canonical.rs index 3fb7d87bcc4..24b2ebc1fbe 100644 --- a/compiler/rustc_type_ir/src/canonical.rs +++ b/compiler/rustc_type_ir/src/canonical.rs @@ -8,7 +8,7 @@ use rustc_macros::{HashStable_NoContext, TyDecodable, TyEncodable}; use rustc_type_ir_macros::{Lift_Generic, TypeFoldable_Generic, TypeVisitable_Generic}; use crate::inherent::*; -use crate::{self as ty, Interner, UniverseIndex}; +use crate::{self as ty, Interner, TypingMode, UniverseIndex}; #[derive_where(Clone; I: Interner, V: Clone)] #[derive_where(Hash; I: Interner, V: Hash)] @@ -19,7 +19,7 @@ use crate::{self as ty, Interner, UniverseIndex}; #[cfg_attr(feature = "nightly", derive(TyEncodable, TyDecodable, HashStable_NoContext))] pub struct CanonicalQueryInput<I: Interner, V> { pub canonical: Canonical<I, V>, - pub defining_opaque_types: I::DefiningOpaqueTypes, + pub typing_mode: TypingMode<I>, } /// A "canonicalized" type `V` is one where all free inference diff --git a/compiler/rustc_type_ir/src/infer_ctxt.rs b/compiler/rustc_type_ir/src/infer_ctxt.rs index 7c6a3c65ebf..22223e4a890 100644 --- a/compiler/rustc_type_ir/src/infer_ctxt.rs +++ b/compiler/rustc_type_ir/src/infer_ctxt.rs @@ -1,9 +1,68 @@ +use derive_where::derive_where; +#[cfg(feature = "nightly")] +use rustc_macros::{HashStable_NoContext, TyDecodable, TyEncodable}; + use crate::fold::TypeFoldable; +use crate::inherent::*; use crate::relate::RelateResult; use crate::relate::combine::PredicateEmittingRelation; -use crate::solve::SolverMode; +use crate::solve::Reveal; use crate::{self as ty, Interner}; +/// The current typing mode of an inference context. We unfortunately have some +/// slightly different typing rules depending on the current context. See the +/// doc comment for each variant for how and why they are used. +#[derive_where(Clone, Copy, Hash, PartialEq, Eq, Debug; I: Interner)] +#[cfg_attr(feature = "nightly", derive(TyEncodable, TyDecodable, HashStable_NoContext))] +pub enum TypingMode<I: Interner> { + /// When checking whether impls overlap, we check whether any obligations + /// are guaranteed to never hold when unifying the impls. This requires us + /// to be complete: we must never fail to prove something which may actually + /// hold. + /// + /// In this typing mode we bail with ambiguity in case its not knowable + /// whether a trait goal may hold, e.g. because the trait may get implemented + /// in a downstream or sibling crate. + /// + /// We also have to be careful when generalizing aliases inside of higher-ranked + /// types to not unnecessarily constrain any inference variables. + Coherence, + /// Analysis includes type inference, checking that items are well-formed, and + /// pretty much everything else which may emit proper type errors to the user. + /// + /// We only normalize opaque types which may get defined by the current body, + /// which are stored in `defining_opaque_types`. + Analysis { defining_opaque_types: I::DefiningOpaqueTypes }, + /// After analysis, mostly during codegen and MIR optimizations, we're able to + /// reveal all opaque types. + PostAnalysis, +} + +impl<I: Interner> TypingMode<I> { + /// Analysis outside of a body does not define any opaque types. + pub fn non_body_analysis() -> TypingMode<I> { + TypingMode::Analysis { defining_opaque_types: Default::default() } + } + + /// While typechecking a body, we need to be able to define the opaque + /// types defined by that body. + pub fn analysis_in_body(cx: I, body_def_id: I::LocalDefId) -> TypingMode<I> { + TypingMode::Analysis { defining_opaque_types: cx.opaque_types_defined_by(body_def_id) } + } + + /// FIXME(#132279): Using this function is questionable as the `param_env` + /// does not track `defining_opaque_types` and whether we're in coherence mode. + /// Many uses of this function should also use a not-yet implemented typing mode + /// which reveals already defined opaque types in the future. This function will + /// get completely removed at some point. + pub fn from_param_env(param_env: I::ParamEnv) -> TypingMode<I> { + match param_env.reveal() { + Reveal::UserFacing => TypingMode::non_body_analysis(), + Reveal::All => TypingMode::PostAnalysis, + } + } +} + pub trait InferCtxtLike: Sized { type Interner: Interner; fn cx(&self) -> Self::Interner; @@ -16,7 +75,10 @@ pub trait InferCtxtLike: Sized { true } - fn solver_mode(&self) -> SolverMode; + fn typing_mode( + &self, + param_env_for_debug_assertion: <Self::Interner as Interner>::ParamEnv, + ) -> TypingMode<Self::Interner>; fn universe(&self) -> ty::UniverseIndex; fn create_next_universe(&self) -> ty::UniverseIndex; @@ -43,8 +105,6 @@ pub trait InferCtxtLike: Sized { vid: ty::RegionVid, ) -> <Self::Interner as Interner>::Region; - fn defining_opaque_types(&self) -> <Self::Interner as Interner>::DefiningOpaqueTypes; - fn next_ty_infer(&self) -> <Self::Interner as Interner>::Ty; fn next_const_infer(&self) -> <Self::Interner as Interner>::Const; fn fresh_args_for_item( diff --git a/compiler/rustc_type_ir/src/interner.rs b/compiler/rustc_type_ir/src/interner.rs index 6a8113b38b7..36ddddccfa2 100644 --- a/compiler/rustc_type_ir/src/interner.rs +++ b/compiler/rustc_type_ir/src/interner.rs @@ -11,9 +11,7 @@ use crate::inherent::*; use crate::ir_print::IrPrint; use crate::lang_items::TraitSolverLangItem; use crate::relate::Relate; -use crate::solve::{ - CanonicalInput, ExternalConstraintsData, PredefinedOpaquesData, QueryResult, SolverMode, -}; +use crate::solve::{CanonicalInput, ExternalConstraintsData, PredefinedOpaquesData, QueryResult}; use crate::visit::{Flags, TypeSuperVisitable, TypeVisitable}; use crate::{self as ty, search_graph}; @@ -130,11 +128,7 @@ pub trait Interner: type Clause: Clause<Self>; type Clauses: Copy + Debug + Hash + Eq + TypeSuperVisitable<Self> + Flags; - fn with_global_cache<R>( - self, - mode: SolverMode, - f: impl FnOnce(&mut search_graph::GlobalCache<Self>) -> R, - ) -> R; + fn with_global_cache<R>(self, f: impl FnOnce(&mut search_graph::GlobalCache<Self>) -> R) -> R; fn evaluation_is_concurrent(&self) -> bool; @@ -298,6 +292,11 @@ pub trait Interner: self, binder: ty::Binder<Self, T>, ) -> ty::Binder<Self, T>; + + fn opaque_types_defined_by( + self, + defining_anchor: Self::LocalDefId, + ) -> Self::DefiningOpaqueTypes; } /// Imagine you have a function `F: FnOnce(&[T]) -> R`, plus an iterator `iter` @@ -414,12 +413,8 @@ impl<I: Interner> search_graph::Cx for I { fn with_cached_task<T>(self, task: impl FnOnce() -> T) -> (T, I::DepNodeIndex) { I::with_cached_task(self, task) } - fn with_global_cache<R>( - self, - mode: SolverMode, - f: impl FnOnce(&mut search_graph::GlobalCache<Self>) -> R, - ) -> R { - I::with_global_cache(self, mode, f) + fn with_global_cache<R>(self, f: impl FnOnce(&mut search_graph::GlobalCache<Self>) -> R) -> R { + I::with_global_cache(self, f) } fn evaluation_is_concurrent(&self) -> bool { self.evaluation_is_concurrent() diff --git a/compiler/rustc_type_ir/src/outlives.rs b/compiler/rustc_type_ir/src/outlives.rs index ac35215fbaa..0e94e989b97 100644 --- a/compiler/rustc_type_ir/src/outlives.rs +++ b/compiler/rustc_type_ir/src/outlives.rs @@ -110,6 +110,18 @@ impl<I: Interner> TypeVisitor<I> for OutlivesCollector<'_, I> { ty::Coroutine(_, args) => { args.as_coroutine().tupled_upvars_ty().visit_with(self); + // Coroutines may not outlive a region unless the resume + // ty outlives a region. This is because the resume ty may + // store data that lives shorter than this outlives region + // across yield points, which may subsequently be accessed + // after the coroutine is resumed again. + // + // Conceptually, you may think of the resume arg as an upvar + // of `&mut Option<ResumeArgTy>`, since it is kinda like + // storage shared between the callee of the coroutine and the + // coroutine body. + args.as_coroutine().resume_ty().visit_with(self); + // We ignore regions in the coroutine interior as we don't // want these to affect region inference } diff --git a/compiler/rustc_type_ir/src/relate/combine.rs b/compiler/rustc_type_ir/src/relate/combine.rs index 17a3912730f..53751f7711a 100644 --- a/compiler/rustc_type_ir/src/relate/combine.rs +++ b/compiler/rustc_type_ir/src/relate/combine.rs @@ -6,9 +6,9 @@ use super::{ }; use crate::error::TypeError; use crate::inherent::*; -use crate::solve::{Goal, SolverMode}; +use crate::solve::Goal; use crate::visit::TypeVisitableExt as _; -use crate::{self as ty, InferCtxtLike, Interner, Upcast}; +use crate::{self as ty, InferCtxtLike, Interner, TypingMode, Upcast}; pub trait PredicateEmittingRelation<Infcx, I = <Infcx as InferCtxtLike>::Interner>: TypeRelation<I> @@ -128,19 +128,19 @@ where } (ty::Alias(ty::Opaque, _), _) | (_, ty::Alias(ty::Opaque, _)) => { - match infcx.solver_mode() { - SolverMode::Normal => { - assert!(!infcx.next_trait_solver()); - structurally_relate_tys(relation, a, b) - } + assert!(!infcx.next_trait_solver()); + match infcx.typing_mode(relation.param_env()) { // During coherence, opaque types should be treated as *possibly* - // equal to any other type (except for possibly itinfcx). This is an + // equal to any other type. This is an // extremely heavy hammer, but can be relaxed in a forwards-compatible // way later. - SolverMode::Coherence => { + TypingMode::Coherence => { relation.register_predicates([ty::Binder::dummy(ty::PredicateKind::Ambiguous)]); Ok(a) } + TypingMode::Analysis { .. } | TypingMode::PostAnalysis => { + structurally_relate_tys(relation, a, b) + } } } diff --git a/compiler/rustc_type_ir/src/search_graph/mod.rs b/compiler/rustc_type_ir/src/search_graph/mod.rs index 3fd2bb61ba5..5010fc09adc 100644 --- a/compiler/rustc_type_ir/src/search_graph/mod.rs +++ b/compiler/rustc_type_ir/src/search_graph/mod.rs @@ -22,7 +22,6 @@ use rustc_index::{Idx, IndexVec}; use tracing::debug; use crate::data_structures::HashMap; -use crate::solve::SolverMode; mod global_cache; use global_cache::CacheData; @@ -48,11 +47,7 @@ pub trait Cx: Copy { fn get_tracked<T: Debug + Clone>(self, tracked: &Self::Tracked<T>) -> T; fn with_cached_task<T>(self, task: impl FnOnce() -> T) -> (T, Self::DepNodeIndex); - fn with_global_cache<R>( - self, - mode: SolverMode, - f: impl FnOnce(&mut GlobalCache<Self>) -> R, - ) -> R; + fn with_global_cache<R>(self, f: impl FnOnce(&mut GlobalCache<Self>) -> R) -> R; fn evaluation_is_concurrent(&self) -> bool; } @@ -358,7 +353,6 @@ struct ProvisionalCacheEntry<X: Cx> { } pub struct SearchGraph<D: Delegate<Cx = X>, X: Cx = <D as Delegate>::Cx> { - mode: SolverMode, root_depth: AvailableDepth, /// The stack of goals currently being computed. /// @@ -374,9 +368,8 @@ pub struct SearchGraph<D: Delegate<Cx = X>, X: Cx = <D as Delegate>::Cx> { } impl<D: Delegate<Cx = X>, X: Cx> SearchGraph<D> { - pub fn new(mode: SolverMode, root_depth: usize) -> SearchGraph<D> { + pub fn new(root_depth: usize) -> SearchGraph<D> { Self { - mode, root_depth: AvailableDepth(root_depth), stack: Default::default(), provisional_cache: Default::default(), @@ -384,10 +377,6 @@ impl<D: Delegate<Cx = X>, X: Cx> SearchGraph<D> { } } - pub fn solver_mode(&self) -> SolverMode { - self.mode - } - /// Lazily update the stack entry for the parent goal. /// This behavior is shared between actually evaluating goals /// and using existing global cache entries to make sure they @@ -829,7 +818,7 @@ impl<D: Delegate<Cx = X>, X: Cx> SearchGraph<D> { input: X::Input, available_depth: AvailableDepth, ) -> Option<X::Result> { - cx.with_global_cache(self.mode, |cache| { + cx.with_global_cache(|cache| { cache .get(cx, input, available_depth, |nested_goals| { Self::candidate_is_applicable( @@ -852,7 +841,7 @@ impl<D: Delegate<Cx = X>, X: Cx> SearchGraph<D> { input: X::Input, available_depth: AvailableDepth, ) -> Option<X::Result> { - cx.with_global_cache(self.mode, |cache| { + cx.with_global_cache(|cache| { let CacheData { result, additional_depth, encountered_overflow, nested_goals } = cache .get(cx, input, available_depth, |nested_goals| { Self::candidate_is_applicable( @@ -1041,7 +1030,7 @@ impl<D: Delegate<Cx = X>, X: Cx> SearchGraph<D> { ) { let additional_depth = final_entry.reached_depth.as_usize() - self.stack.len(); debug!(?final_entry, ?result, "insert global cache"); - cx.with_global_cache(self.mode, |cache| { + cx.with_global_cache(|cache| { cache.insert( cx, input, diff --git a/compiler/rustc_type_ir/src/solve/mod.rs b/compiler/rustc_type_ir/src/solve/mod.rs index b3f8390bbf0..fe455873051 100644 --- a/compiler/rustc_type_ir/src/solve/mod.rs +++ b/compiler/rustc_type_ir/src/solve/mod.rs @@ -58,19 +58,6 @@ pub enum Reveal { All, } -#[derive(Debug, Clone, Copy, PartialEq, Eq)] -pub enum SolverMode { - /// Ordinary trait solving, using everywhere except for coherence. - Normal, - /// Trait solving during coherence. There are a few notable differences - /// between coherence and ordinary trait solving. - /// - /// Most importantly, trait solving during coherence must not be incomplete, - /// i.e. return `Err(NoSolution)` for goals for which a solution exists. - /// This means that we must not make any guesses or arbitrary choices. - Coherence, -} - pub type CanonicalInput<I, T = <I as Interner>::Predicate> = ty::CanonicalQueryInput<I, QueryInput<I, T>>; pub type CanonicalResponse<I> = Canonical<I, Response<I>>; diff --git a/library/alloc/src/boxed.rs b/library/alloc/src/boxed.rs index bc354650a8e..e4956c7c53c 100644 --- a/library/alloc/src/boxed.rs +++ b/library/alloc/src/boxed.rs @@ -183,15 +183,14 @@ #![stable(feature = "rust1", since = "1.0.0")] -use core::any::Any; -use core::async_iter::AsyncIterator; +use core::borrow::{Borrow, BorrowMut}; #[cfg(not(no_global_oom_handling))] use core::clone::CloneToUninit; use core::cmp::Ordering; -use core::error::Error; +use core::error::{self, Error}; +use core::fmt; use core::future::Future; use core::hash::{Hash, Hasher}; -use core::iter::FusedIterator; use core::marker::{Tuple, Unsize}; use core::mem::{self, SizedTypeProperties}; use core::ops::{ @@ -201,27 +200,24 @@ use core::ops::{ use core::pin::{Pin, PinCoerceUnsized}; use core::ptr::{self, NonNull, Unique}; use core::task::{Context, Poll}; -use core::{borrow, fmt, slice}; - -#[unstable(feature = "thin_box", issue = "92791")] -pub use thin::ThinBox; #[cfg(not(no_global_oom_handling))] use crate::alloc::handle_alloc_error; use crate::alloc::{AllocError, Allocator, Global, Layout}; -#[cfg(not(no_global_oom_handling))] -use crate::borrow::Cow; use crate::raw_vec::RawVec; #[cfg(not(no_global_oom_handling))] use crate::str::from_boxed_utf8_unchecked; -#[cfg(not(no_global_oom_handling))] -use crate::string::String; -use crate::vec; -#[cfg(not(no_global_oom_handling))] -use crate::vec::Vec; +/// Conversion related impls for `Box<_>` (`From`, `downcast`, etc) +mod convert; +/// Iterator related impls for `Box<_>`. +mod iter; +/// [`ThinBox`] implementation. mod thin; +#[unstable(feature = "thin_box", issue = "92791")] +pub use thin::ThinBox; + /// A pointer type that uniquely owns a heap allocation of type `T`. /// /// See the [module-level documentation](../../std/boxed/index.html) for more. @@ -1768,6 +1764,41 @@ impl<T: Clone, A: Allocator + Clone> Clone for Box<T, A> { #[cfg(not(no_global_oom_handling))] #[stable(feature = "box_slice_clone", since = "1.3.0")] +impl<T: Clone, A: Allocator + Clone> Clone for Box<[T], A> { + fn clone(&self) -> Self { + let alloc = Box::allocator(self).clone(); + self.to_vec_in(alloc).into_boxed_slice() + } + + /// Copies `source`'s contents into `self` without creating a new allocation, + /// so long as the two are of the same length. + /// + /// # Examples + /// + /// ``` + /// let x = Box::new([5, 6, 7]); + /// let mut y = Box::new([8, 9, 10]); + /// let yp: *const [i32] = &*y; + /// + /// y.clone_from(&x); + /// + /// // The value is the same + /// assert_eq!(x, y); + /// + /// // And no allocation occurred + /// assert_eq!(yp, &*y); + /// ``` + fn clone_from(&mut self, source: &Self) { + if self.len() == source.len() { + self.clone_from_slice(&source); + } else { + *self = source.clone(); + } + } +} + +#[cfg(not(no_global_oom_handling))] +#[stable(feature = "box_slice_clone", since = "1.3.0")] impl Clone for Box<str> { fn clone(&self) -> Self { // this makes a copy of the data @@ -1787,6 +1818,7 @@ impl<T: ?Sized + PartialEq, A: Allocator> PartialEq for Box<T, A> { PartialEq::ne(&**self, &**other) } } + #[stable(feature = "rust1", since = "1.0.0")] impl<T: ?Sized + PartialOrd, A: Allocator> PartialOrd for Box<T, A> { #[inline] @@ -1810,6 +1842,7 @@ impl<T: ?Sized + PartialOrd, A: Allocator> PartialOrd for Box<T, A> { PartialOrd::gt(&**self, &**other) } } + #[stable(feature = "rust1", since = "1.0.0")] impl<T: ?Sized + Ord, A: Allocator> Ord for Box<T, A> { #[inline] @@ -1817,6 +1850,7 @@ impl<T: ?Sized + Ord, A: Allocator> Ord for Box<T, A> { Ord::cmp(&**self, &**other) } } + #[stable(feature = "rust1", since = "1.0.0")] impl<T: ?Sized + Eq, A: Allocator> Eq for Box<T, A> {} @@ -1879,462 +1913,6 @@ impl<T: ?Sized + Hasher, A: Allocator> Hasher for Box<T, A> { } } -#[cfg(not(no_global_oom_handling))] -#[stable(feature = "from_for_ptrs", since = "1.6.0")] -impl<T> From<T> for Box<T> { - /// Converts a `T` into a `Box<T>` - /// - /// The conversion allocates on the heap and moves `t` - /// from the stack into it. - /// - /// # Examples - /// - /// ```rust - /// let x = 5; - /// let boxed = Box::new(5); - /// - /// assert_eq!(Box::from(x), boxed); - /// ``` - fn from(t: T) -> Self { - Box::new(t) - } -} - -#[stable(feature = "pin", since = "1.33.0")] -impl<T: ?Sized, A: Allocator> From<Box<T, A>> for Pin<Box<T, A>> -where - A: 'static, -{ - /// Converts a `Box<T>` into a `Pin<Box<T>>`. If `T` does not implement [`Unpin`], then - /// `*boxed` will be pinned in memory and unable to be moved. - /// - /// This conversion does not allocate on the heap and happens in place. - /// - /// This is also available via [`Box::into_pin`]. - /// - /// Constructing and pinning a `Box` with <code><Pin<Box\<T>>>::from([Box::new]\(x))</code> - /// can also be written more concisely using <code>[Box::pin]\(x)</code>. - /// This `From` implementation is useful if you already have a `Box<T>`, or you are - /// constructing a (pinned) `Box` in a different way than with [`Box::new`]. - fn from(boxed: Box<T, A>) -> Self { - Box::into_pin(boxed) - } -} - -/// Specialization trait used for `From<&[T]>`. -#[cfg(not(no_global_oom_handling))] -trait BoxFromSlice<T> { - fn from_slice(slice: &[T]) -> Self; -} - -#[cfg(not(no_global_oom_handling))] -impl<T: Clone> BoxFromSlice<T> for Box<[T]> { - #[inline] - default fn from_slice(slice: &[T]) -> Self { - slice.to_vec().into_boxed_slice() - } -} - -#[cfg(not(no_global_oom_handling))] -impl<T: Copy> BoxFromSlice<T> for Box<[T]> { - #[inline] - fn from_slice(slice: &[T]) -> Self { - let len = slice.len(); - let buf = RawVec::with_capacity(len); - unsafe { - ptr::copy_nonoverlapping(slice.as_ptr(), buf.ptr(), len); - buf.into_box(slice.len()).assume_init() - } - } -} - -#[cfg(not(no_global_oom_handling))] -#[stable(feature = "box_from_slice", since = "1.17.0")] -impl<T: Clone> From<&[T]> for Box<[T]> { - /// Converts a `&[T]` into a `Box<[T]>` - /// - /// This conversion allocates on the heap - /// and performs a copy of `slice` and its contents. - /// - /// # Examples - /// ```rust - /// // create a &[u8] which will be used to create a Box<[u8]> - /// let slice: &[u8] = &[104, 101, 108, 108, 111]; - /// let boxed_slice: Box<[u8]> = Box::from(slice); - /// - /// println!("{boxed_slice:?}"); - /// ``` - #[inline] - fn from(slice: &[T]) -> Box<[T]> { - <Self as BoxFromSlice<T>>::from_slice(slice) - } -} - -#[cfg(not(no_global_oom_handling))] -#[stable(feature = "box_from_cow", since = "1.45.0")] -impl<T: Clone> From<Cow<'_, [T]>> for Box<[T]> { - /// Converts a `Cow<'_, [T]>` into a `Box<[T]>` - /// - /// When `cow` is the `Cow::Borrowed` variant, this - /// conversion allocates on the heap and copies the - /// underlying slice. Otherwise, it will try to reuse the owned - /// `Vec`'s allocation. - #[inline] - fn from(cow: Cow<'_, [T]>) -> Box<[T]> { - match cow { - Cow::Borrowed(slice) => Box::from(slice), - Cow::Owned(slice) => Box::from(slice), - } - } -} - -#[cfg(not(no_global_oom_handling))] -#[stable(feature = "box_from_slice", since = "1.17.0")] -impl From<&str> for Box<str> { - /// Converts a `&str` into a `Box<str>` - /// - /// This conversion allocates on the heap - /// and performs a copy of `s`. - /// - /// # Examples - /// - /// ```rust - /// let boxed: Box<str> = Box::from("hello"); - /// println!("{boxed}"); - /// ``` - #[inline] - fn from(s: &str) -> Box<str> { - unsafe { from_boxed_utf8_unchecked(Box::from(s.as_bytes())) } - } -} - -#[cfg(not(no_global_oom_handling))] -#[stable(feature = "box_from_cow", since = "1.45.0")] -impl From<Cow<'_, str>> for Box<str> { - /// Converts a `Cow<'_, str>` into a `Box<str>` - /// - /// When `cow` is the `Cow::Borrowed` variant, this - /// conversion allocates on the heap and copies the - /// underlying `str`. Otherwise, it will try to reuse the owned - /// `String`'s allocation. - /// - /// # Examples - /// - /// ```rust - /// use std::borrow::Cow; - /// - /// let unboxed = Cow::Borrowed("hello"); - /// let boxed: Box<str> = Box::from(unboxed); - /// println!("{boxed}"); - /// ``` - /// - /// ```rust - /// # use std::borrow::Cow; - /// let unboxed = Cow::Owned("hello".to_string()); - /// let boxed: Box<str> = Box::from(unboxed); - /// println!("{boxed}"); - /// ``` - #[inline] - fn from(cow: Cow<'_, str>) -> Box<str> { - match cow { - Cow::Borrowed(s) => Box::from(s), - Cow::Owned(s) => Box::from(s), - } - } -} - -#[stable(feature = "boxed_str_conv", since = "1.19.0")] -impl<A: Allocator> From<Box<str, A>> for Box<[u8], A> { - /// Converts a `Box<str>` into a `Box<[u8]>` - /// - /// This conversion does not allocate on the heap and happens in place. - /// - /// # Examples - /// ```rust - /// // create a Box<str> which will be used to create a Box<[u8]> - /// let boxed: Box<str> = Box::from("hello"); - /// let boxed_str: Box<[u8]> = Box::from(boxed); - /// - /// // create a &[u8] which will be used to create a Box<[u8]> - /// let slice: &[u8] = &[104, 101, 108, 108, 111]; - /// let boxed_slice = Box::from(slice); - /// - /// assert_eq!(boxed_slice, boxed_str); - /// ``` - #[inline] - fn from(s: Box<str, A>) -> Self { - let (raw, alloc) = Box::into_raw_with_allocator(s); - unsafe { Box::from_raw_in(raw as *mut [u8], alloc) } - } -} - -#[cfg(not(no_global_oom_handling))] -#[stable(feature = "box_from_array", since = "1.45.0")] -impl<T, const N: usize> From<[T; N]> for Box<[T]> { - /// Converts a `[T; N]` into a `Box<[T]>` - /// - /// This conversion moves the array to newly heap-allocated memory. - /// - /// # Examples - /// - /// ```rust - /// let boxed: Box<[u8]> = Box::from([4, 2]); - /// println!("{boxed:?}"); - /// ``` - fn from(array: [T; N]) -> Box<[T]> { - Box::new(array) - } -} - -/// Casts a boxed slice to a boxed array. -/// -/// # Safety -/// -/// `boxed_slice.len()` must be exactly `N`. -unsafe fn boxed_slice_as_array_unchecked<T, A: Allocator, const N: usize>( - boxed_slice: Box<[T], A>, -) -> Box<[T; N], A> { - debug_assert_eq!(boxed_slice.len(), N); - - let (ptr, alloc) = Box::into_raw_with_allocator(boxed_slice); - // SAFETY: Pointer and allocator came from an existing box, - // and our safety condition requires that the length is exactly `N` - unsafe { Box::from_raw_in(ptr as *mut [T; N], alloc) } -} - -#[stable(feature = "boxed_slice_try_from", since = "1.43.0")] -impl<T, const N: usize> TryFrom<Box<[T]>> for Box<[T; N]> { - type Error = Box<[T]>; - - /// Attempts to convert a `Box<[T]>` into a `Box<[T; N]>`. - /// - /// The conversion occurs in-place and does not require a - /// new memory allocation. - /// - /// # Errors - /// - /// Returns the old `Box<[T]>` in the `Err` variant if - /// `boxed_slice.len()` does not equal `N`. - fn try_from(boxed_slice: Box<[T]>) -> Result<Self, Self::Error> { - if boxed_slice.len() == N { - Ok(unsafe { boxed_slice_as_array_unchecked(boxed_slice) }) - } else { - Err(boxed_slice) - } - } -} - -#[cfg(not(no_global_oom_handling))] -#[stable(feature = "boxed_array_try_from_vec", since = "1.66.0")] -impl<T, const N: usize> TryFrom<Vec<T>> for Box<[T; N]> { - type Error = Vec<T>; - - /// Attempts to convert a `Vec<T>` into a `Box<[T; N]>`. - /// - /// Like [`Vec::into_boxed_slice`], this is in-place if `vec.capacity() == N`, - /// but will require a reallocation otherwise. - /// - /// # Errors - /// - /// Returns the original `Vec<T>` in the `Err` variant if - /// `boxed_slice.len()` does not equal `N`. - /// - /// # Examples - /// - /// This can be used with [`vec!`] to create an array on the heap: - /// - /// ``` - /// let state: Box<[f32; 100]> = vec![1.0; 100].try_into().unwrap(); - /// assert_eq!(state.len(), 100); - /// ``` - fn try_from(vec: Vec<T>) -> Result<Self, Self::Error> { - if vec.len() == N { - let boxed_slice = vec.into_boxed_slice(); - Ok(unsafe { boxed_slice_as_array_unchecked(boxed_slice) }) - } else { - Err(vec) - } - } -} - -impl<A: Allocator> Box<dyn Any, A> { - /// Attempts to downcast the box to a concrete type. - /// - /// # Examples - /// - /// ``` - /// use std::any::Any; - /// - /// fn print_if_string(value: Box<dyn Any>) { - /// if let Ok(string) = value.downcast::<String>() { - /// println!("String ({}): {}", string.len(), string); - /// } - /// } - /// - /// let my_string = "Hello World".to_string(); - /// print_if_string(Box::new(my_string)); - /// print_if_string(Box::new(0i8)); - /// ``` - #[inline] - #[stable(feature = "rust1", since = "1.0.0")] - pub fn downcast<T: Any>(self) -> Result<Box<T, A>, Self> { - if self.is::<T>() { unsafe { Ok(self.downcast_unchecked::<T>()) } } else { Err(self) } - } - - /// Downcasts the box to a concrete type. - /// - /// For a safe alternative see [`downcast`]. - /// - /// # Examples - /// - /// ``` - /// #![feature(downcast_unchecked)] - /// - /// use std::any::Any; - /// - /// let x: Box<dyn Any> = Box::new(1_usize); - /// - /// unsafe { - /// assert_eq!(*x.downcast_unchecked::<usize>(), 1); - /// } - /// ``` - /// - /// # Safety - /// - /// The contained value must be of type `T`. Calling this method - /// with the incorrect type is *undefined behavior*. - /// - /// [`downcast`]: Self::downcast - #[inline] - #[unstable(feature = "downcast_unchecked", issue = "90850")] - pub unsafe fn downcast_unchecked<T: Any>(self) -> Box<T, A> { - debug_assert!(self.is::<T>()); - unsafe { - let (raw, alloc): (*mut dyn Any, _) = Box::into_raw_with_allocator(self); - Box::from_raw_in(raw as *mut T, alloc) - } - } -} - -impl<A: Allocator> Box<dyn Any + Send, A> { - /// Attempts to downcast the box to a concrete type. - /// - /// # Examples - /// - /// ``` - /// use std::any::Any; - /// - /// fn print_if_string(value: Box<dyn Any + Send>) { - /// if let Ok(string) = value.downcast::<String>() { - /// println!("String ({}): {}", string.len(), string); - /// } - /// } - /// - /// let my_string = "Hello World".to_string(); - /// print_if_string(Box::new(my_string)); - /// print_if_string(Box::new(0i8)); - /// ``` - #[inline] - #[stable(feature = "rust1", since = "1.0.0")] - pub fn downcast<T: Any>(self) -> Result<Box<T, A>, Self> { - if self.is::<T>() { unsafe { Ok(self.downcast_unchecked::<T>()) } } else { Err(self) } - } - - /// Downcasts the box to a concrete type. - /// - /// For a safe alternative see [`downcast`]. - /// - /// # Examples - /// - /// ``` - /// #![feature(downcast_unchecked)] - /// - /// use std::any::Any; - /// - /// let x: Box<dyn Any + Send> = Box::new(1_usize); - /// - /// unsafe { - /// assert_eq!(*x.downcast_unchecked::<usize>(), 1); - /// } - /// ``` - /// - /// # Safety - /// - /// The contained value must be of type `T`. Calling this method - /// with the incorrect type is *undefined behavior*. - /// - /// [`downcast`]: Self::downcast - #[inline] - #[unstable(feature = "downcast_unchecked", issue = "90850")] - pub unsafe fn downcast_unchecked<T: Any>(self) -> Box<T, A> { - debug_assert!(self.is::<T>()); - unsafe { - let (raw, alloc): (*mut (dyn Any + Send), _) = Box::into_raw_with_allocator(self); - Box::from_raw_in(raw as *mut T, alloc) - } - } -} - -impl<A: Allocator> Box<dyn Any + Send + Sync, A> { - /// Attempts to downcast the box to a concrete type. - /// - /// # Examples - /// - /// ``` - /// use std::any::Any; - /// - /// fn print_if_string(value: Box<dyn Any + Send + Sync>) { - /// if let Ok(string) = value.downcast::<String>() { - /// println!("String ({}): {}", string.len(), string); - /// } - /// } - /// - /// let my_string = "Hello World".to_string(); - /// print_if_string(Box::new(my_string)); - /// print_if_string(Box::new(0i8)); - /// ``` - #[inline] - #[stable(feature = "box_send_sync_any_downcast", since = "1.51.0")] - pub fn downcast<T: Any>(self) -> Result<Box<T, A>, Self> { - if self.is::<T>() { unsafe { Ok(self.downcast_unchecked::<T>()) } } else { Err(self) } - } - - /// Downcasts the box to a concrete type. - /// - /// For a safe alternative see [`downcast`]. - /// - /// # Examples - /// - /// ``` - /// #![feature(downcast_unchecked)] - /// - /// use std::any::Any; - /// - /// let x: Box<dyn Any + Send + Sync> = Box::new(1_usize); - /// - /// unsafe { - /// assert_eq!(*x.downcast_unchecked::<usize>(), 1); - /// } - /// ``` - /// - /// # Safety - /// - /// The contained value must be of type `T`. Calling this method - /// with the incorrect type is *undefined behavior*. - /// - /// [`downcast`]: Self::downcast - #[inline] - #[unstable(feature = "downcast_unchecked", issue = "90850")] - pub unsafe fn downcast_unchecked<T: Any>(self) -> Box<T, A> { - debug_assert!(self.is::<T>()); - unsafe { - let (raw, alloc): (*mut (dyn Any + Send + Sync), _) = - Box::into_raw_with_allocator(self); - Box::from_raw_in(raw as *mut T, alloc) - } - } -} - #[stable(feature = "rust1", since = "1.0.0")] impl<T: fmt::Display + ?Sized, A: Allocator> fmt::Display for Box<T, A> { fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { @@ -2381,71 +1959,6 @@ unsafe impl<T: ?Sized, A: Allocator> DerefPure for Box<T, A> {} #[unstable(feature = "legacy_receiver_trait", issue = "none")] impl<T: ?Sized, A: Allocator> LegacyReceiver for Box<T, A> {} -#[stable(feature = "rust1", since = "1.0.0")] -impl<I: Iterator + ?Sized, A: Allocator> Iterator for Box<I, A> { - type Item = I::Item; - fn next(&mut self) -> Option<I::Item> { - (**self).next() - } - fn size_hint(&self) -> (usize, Option<usize>) { - (**self).size_hint() - } - fn nth(&mut self, n: usize) -> Option<I::Item> { - (**self).nth(n) - } - fn last(self) -> Option<I::Item> { - BoxIter::last(self) - } -} - -trait BoxIter { - type Item; - fn last(self) -> Option<Self::Item>; -} - -impl<I: Iterator + ?Sized, A: Allocator> BoxIter for Box<I, A> { - type Item = I::Item; - default fn last(self) -> Option<I::Item> { - #[inline] - fn some<T>(_: Option<T>, x: T) -> Option<T> { - Some(x) - } - - self.fold(None, some) - } -} - -/// Specialization for sized `I`s that uses `I`s implementation of `last()` -/// instead of the default. -#[stable(feature = "rust1", since = "1.0.0")] -impl<I: Iterator, A: Allocator> BoxIter for Box<I, A> { - fn last(self) -> Option<I::Item> { - (*self).last() - } -} - -#[stable(feature = "rust1", since = "1.0.0")] -impl<I: DoubleEndedIterator + ?Sized, A: Allocator> DoubleEndedIterator for Box<I, A> { - fn next_back(&mut self) -> Option<I::Item> { - (**self).next_back() - } - fn nth_back(&mut self, n: usize) -> Option<I::Item> { - (**self).nth_back(n) - } -} -#[stable(feature = "rust1", since = "1.0.0")] -impl<I: ExactSizeIterator + ?Sized, A: Allocator> ExactSizeIterator for Box<I, A> { - fn len(&self) -> usize { - (**self).len() - } - fn is_empty(&self) -> bool { - (**self).is_empty() - } -} - -#[stable(feature = "fused", since = "1.26.0")] -impl<I: FusedIterator + ?Sized, A: Allocator> FusedIterator for Box<I, A> {} - #[stable(feature = "boxed_closure_impls", since = "1.35.0")] impl<Args: Tuple, F: FnOnce<Args> + ?Sized, A: Allocator> FnOnce<Args> for Box<F, A> { type Output = <F as FnOnce<Args>>::Output; @@ -2501,157 +2014,24 @@ impl<Args: Tuple, F: AsyncFn<Args> + ?Sized, A: Allocator> AsyncFn<Args> for Box #[unstable(feature = "coerce_unsized", issue = "18598")] impl<T: ?Sized + Unsize<U>, U: ?Sized, A: Allocator> CoerceUnsized<Box<U, A>> for Box<T, A> {} +#[unstable(feature = "pin_coerce_unsized_trait", issue = "123430")] +unsafe impl<T: ?Sized, A: Allocator> PinCoerceUnsized for Box<T, A> {} + // It is quite crucial that we only allow the `Global` allocator here. // Handling arbitrary custom allocators (which can affect the `Box` layout heavily!) // would need a lot of codegen and interpreter adjustments. #[unstable(feature = "dispatch_from_dyn", issue = "none")] impl<T: ?Sized + Unsize<U>, U: ?Sized> DispatchFromDyn<Box<U>> for Box<T, Global> {} -#[cfg(not(no_global_oom_handling))] -#[stable(feature = "boxed_slice_from_iter", since = "1.32.0")] -impl<I> FromIterator<I> for Box<[I]> { - fn from_iter<T: IntoIterator<Item = I>>(iter: T) -> Self { - iter.into_iter().collect::<Vec<_>>().into_boxed_slice() - } -} - -/// This implementation is required to make sure that the `Box<[I]>: IntoIterator` -/// implementation doesn't overlap with `IntoIterator for T where T: Iterator` blanket. -#[stable(feature = "boxed_slice_into_iter", since = "1.80.0")] -impl<I, A: Allocator> !Iterator for Box<[I], A> {} - -/// This implementation is required to make sure that the `&Box<[I]>: IntoIterator` -/// implementation doesn't overlap with `IntoIterator for T where T: Iterator` blanket. -#[stable(feature = "boxed_slice_into_iter", since = "1.80.0")] -impl<'a, I, A: Allocator> !Iterator for &'a Box<[I], A> {} - -/// This implementation is required to make sure that the `&mut Box<[I]>: IntoIterator` -/// implementation doesn't overlap with `IntoIterator for T where T: Iterator` blanket. -#[stable(feature = "boxed_slice_into_iter", since = "1.80.0")] -impl<'a, I, A: Allocator> !Iterator for &'a mut Box<[I], A> {} - -// Note: the `#[rustc_skip_during_method_dispatch(boxed_slice)]` on `trait IntoIterator` -// hides this implementation from explicit `.into_iter()` calls on editions < 2024, -// so those calls will still resolve to the slice implementation, by reference. -#[stable(feature = "boxed_slice_into_iter", since = "1.80.0")] -impl<I, A: Allocator> IntoIterator for Box<[I], A> { - type IntoIter = vec::IntoIter<I, A>; - type Item = I; - fn into_iter(self) -> vec::IntoIter<I, A> { - self.into_vec().into_iter() - } -} - -#[stable(feature = "boxed_slice_into_iter", since = "1.80.0")] -impl<'a, I, A: Allocator> IntoIterator for &'a Box<[I], A> { - type IntoIter = slice::Iter<'a, I>; - type Item = &'a I; - fn into_iter(self) -> slice::Iter<'a, I> { - self.iter() - } -} - -#[stable(feature = "boxed_slice_into_iter", since = "1.80.0")] -impl<'a, I, A: Allocator> IntoIterator for &'a mut Box<[I], A> { - type IntoIter = slice::IterMut<'a, I>; - type Item = &'a mut I; - fn into_iter(self) -> slice::IterMut<'a, I> { - self.iter_mut() - } -} - -#[cfg(not(no_global_oom_handling))] -#[stable(feature = "boxed_str_from_iter", since = "1.80.0")] -impl FromIterator<char> for Box<str> { - fn from_iter<T: IntoIterator<Item = char>>(iter: T) -> Self { - String::from_iter(iter).into_boxed_str() - } -} - -#[cfg(not(no_global_oom_handling))] -#[stable(feature = "boxed_str_from_iter", since = "1.80.0")] -impl<'a> FromIterator<&'a char> for Box<str> { - fn from_iter<T: IntoIterator<Item = &'a char>>(iter: T) -> Self { - String::from_iter(iter).into_boxed_str() - } -} - -#[cfg(not(no_global_oom_handling))] -#[stable(feature = "boxed_str_from_iter", since = "1.80.0")] -impl<'a> FromIterator<&'a str> for Box<str> { - fn from_iter<T: IntoIterator<Item = &'a str>>(iter: T) -> Self { - String::from_iter(iter).into_boxed_str() - } -} - -#[cfg(not(no_global_oom_handling))] -#[stable(feature = "boxed_str_from_iter", since = "1.80.0")] -impl FromIterator<String> for Box<str> { - fn from_iter<T: IntoIterator<Item = String>>(iter: T) -> Self { - String::from_iter(iter).into_boxed_str() - } -} - -#[cfg(not(no_global_oom_handling))] -#[stable(feature = "boxed_str_from_iter", since = "1.80.0")] -impl<A: Allocator> FromIterator<Box<str, A>> for Box<str> { - fn from_iter<T: IntoIterator<Item = Box<str, A>>>(iter: T) -> Self { - String::from_iter(iter).into_boxed_str() - } -} - -#[cfg(not(no_global_oom_handling))] -#[stable(feature = "boxed_str_from_iter", since = "1.80.0")] -impl<'a> FromIterator<Cow<'a, str>> for Box<str> { - fn from_iter<T: IntoIterator<Item = Cow<'a, str>>>(iter: T) -> Self { - String::from_iter(iter).into_boxed_str() - } -} - -#[cfg(not(no_global_oom_handling))] -#[stable(feature = "box_slice_clone", since = "1.3.0")] -impl<T: Clone, A: Allocator + Clone> Clone for Box<[T], A> { - fn clone(&self) -> Self { - let alloc = Box::allocator(self).clone(); - self.to_vec_in(alloc).into_boxed_slice() - } - - /// Copies `source`'s contents into `self` without creating a new allocation, - /// so long as the two are of the same length. - /// - /// # Examples - /// - /// ``` - /// let x = Box::new([5, 6, 7]); - /// let mut y = Box::new([8, 9, 10]); - /// let yp: *const [i32] = &*y; - /// - /// y.clone_from(&x); - /// - /// // The value is the same - /// assert_eq!(x, y); - /// - /// // And no allocation occurred - /// assert_eq!(yp, &*y); - /// ``` - fn clone_from(&mut self, source: &Self) { - if self.len() == source.len() { - self.clone_from_slice(&source); - } else { - *self = source.clone(); - } - } -} - #[stable(feature = "box_borrow", since = "1.1.0")] -impl<T: ?Sized, A: Allocator> borrow::Borrow<T> for Box<T, A> { +impl<T: ?Sized, A: Allocator> Borrow<T> for Box<T, A> { fn borrow(&self) -> &T { &**self } } #[stable(feature = "box_borrow", since = "1.1.0")] -impl<T: ?Sized, A: Allocator> borrow::BorrowMut<T> for Box<T, A> { +impl<T: ?Sized, A: Allocator> BorrowMut<T> for Box<T, A> { fn borrow_mut(&mut self) -> &mut T { &mut **self } @@ -2728,311 +2108,23 @@ impl<F: ?Sized + Future + Unpin, A: Allocator> Future for Box<F, A> { } } -#[unstable(feature = "async_iterator", issue = "79024")] -impl<S: ?Sized + AsyncIterator + Unpin> AsyncIterator for Box<S> { - type Item = S::Item; - - fn poll_next(mut self: Pin<&mut Self>, cx: &mut Context<'_>) -> Poll<Option<Self::Item>> { - Pin::new(&mut **self).poll_next(cx) - } - - fn size_hint(&self) -> (usize, Option<usize>) { - (**self).size_hint() - } -} - -impl dyn Error { - #[inline] - #[stable(feature = "error_downcast", since = "1.3.0")] - #[rustc_allow_incoherent_impl] - /// Attempts to downcast the box to a concrete type. - pub fn downcast<T: Error + 'static>(self: Box<Self>) -> Result<Box<T>, Box<dyn Error>> { - if self.is::<T>() { - unsafe { - let raw: *mut dyn Error = Box::into_raw(self); - Ok(Box::from_raw(raw as *mut T)) - } - } else { - Err(self) - } - } -} - -impl dyn Error + Send { - #[inline] - #[stable(feature = "error_downcast", since = "1.3.0")] - #[rustc_allow_incoherent_impl] - /// Attempts to downcast the box to a concrete type. - pub fn downcast<T: Error + 'static>(self: Box<Self>) -> Result<Box<T>, Box<dyn Error + Send>> { - let err: Box<dyn Error> = self; - <dyn Error>::downcast(err).map_err(|s| unsafe { - // Reapply the `Send` marker. - mem::transmute::<Box<dyn Error>, Box<dyn Error + Send>>(s) - }) - } -} - -impl dyn Error + Send + Sync { - #[inline] - #[stable(feature = "error_downcast", since = "1.3.0")] - #[rustc_allow_incoherent_impl] - /// Attempts to downcast the box to a concrete type. - pub fn downcast<T: Error + 'static>(self: Box<Self>) -> Result<Box<T>, Box<Self>> { - let err: Box<dyn Error> = self; - <dyn Error>::downcast(err).map_err(|s| unsafe { - // Reapply the `Send + Sync` markers. - mem::transmute::<Box<dyn Error>, Box<dyn Error + Send + Sync>>(s) - }) - } -} - -#[cfg(not(no_global_oom_handling))] -#[stable(feature = "rust1", since = "1.0.0")] -impl<'a, E: Error + 'a> From<E> for Box<dyn Error + 'a> { - /// Converts a type of [`Error`] into a box of dyn [`Error`]. - /// - /// # Examples - /// - /// ``` - /// use std::error::Error; - /// use std::fmt; - /// use std::mem; - /// - /// #[derive(Debug)] - /// struct AnError; - /// - /// impl fmt::Display for AnError { - /// fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { - /// write!(f, "An error") - /// } - /// } - /// - /// impl Error for AnError {} - /// - /// let an_error = AnError; - /// assert!(0 == mem::size_of_val(&an_error)); - /// let a_boxed_error = Box::<dyn Error>::from(an_error); - /// assert!(mem::size_of::<Box<dyn Error>>() == mem::size_of_val(&a_boxed_error)) - /// ``` - fn from(err: E) -> Box<dyn Error + 'a> { - Box::new(err) - } -} - -#[cfg(not(no_global_oom_handling))] -#[stable(feature = "rust1", since = "1.0.0")] -impl<'a, E: Error + Send + Sync + 'a> From<E> for Box<dyn Error + Send + Sync + 'a> { - /// Converts a type of [`Error`] + [`Send`] + [`Sync`] into a box of - /// dyn [`Error`] + [`Send`] + [`Sync`]. - /// - /// # Examples - /// - /// ``` - /// use std::error::Error; - /// use std::fmt; - /// use std::mem; - /// - /// #[derive(Debug)] - /// struct AnError; - /// - /// impl fmt::Display for AnError { - /// fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { - /// write!(f, "An error") - /// } - /// } - /// - /// impl Error for AnError {} - /// - /// unsafe impl Send for AnError {} - /// - /// unsafe impl Sync for AnError {} - /// - /// let an_error = AnError; - /// assert!(0 == mem::size_of_val(&an_error)); - /// let a_boxed_error = Box::<dyn Error + Send + Sync>::from(an_error); - /// assert!( - /// mem::size_of::<Box<dyn Error + Send + Sync>>() == mem::size_of_val(&a_boxed_error)) - /// ``` - fn from(err: E) -> Box<dyn Error + Send + Sync + 'a> { - Box::new(err) - } -} - -#[cfg(not(no_global_oom_handling))] -#[stable(feature = "rust1", since = "1.0.0")] -impl<'a> From<String> for Box<dyn Error + Send + Sync + 'a> { - /// Converts a [`String`] into a box of dyn [`Error`] + [`Send`] + [`Sync`]. - /// - /// # Examples - /// - /// ``` - /// use std::error::Error; - /// use std::mem; - /// - /// let a_string_error = "a string error".to_string(); - /// let a_boxed_error = Box::<dyn Error + Send + Sync>::from(a_string_error); - /// assert!( - /// mem::size_of::<Box<dyn Error + Send + Sync>>() == mem::size_of_val(&a_boxed_error)) - /// ``` - #[inline] - fn from(err: String) -> Box<dyn Error + Send + Sync + 'a> { - struct StringError(String); - - impl Error for StringError { - #[allow(deprecated)] - fn description(&self) -> &str { - &self.0 - } - } - - impl fmt::Display for StringError { - fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { - fmt::Display::fmt(&self.0, f) - } - } - - // Purposefully skip printing "StringError(..)" - impl fmt::Debug for StringError { - fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { - fmt::Debug::fmt(&self.0, f) - } - } - - Box::new(StringError(err)) - } -} - -#[cfg(not(no_global_oom_handling))] -#[stable(feature = "string_box_error", since = "1.6.0")] -impl<'a> From<String> for Box<dyn Error + 'a> { - /// Converts a [`String`] into a box of dyn [`Error`]. - /// - /// # Examples - /// - /// ``` - /// use std::error::Error; - /// use std::mem; - /// - /// let a_string_error = "a string error".to_string(); - /// let a_boxed_error = Box::<dyn Error>::from(a_string_error); - /// assert!(mem::size_of::<Box<dyn Error>>() == mem::size_of_val(&a_boxed_error)) - /// ``` - fn from(str_err: String) -> Box<dyn Error + 'a> { - let err1: Box<dyn Error + Send + Sync> = From::from(str_err); - let err2: Box<dyn Error> = err1; - err2 - } -} - -#[cfg(not(no_global_oom_handling))] -#[stable(feature = "rust1", since = "1.0.0")] -impl<'a> From<&str> for Box<dyn Error + Send + Sync + 'a> { - /// Converts a [`str`] into a box of dyn [`Error`] + [`Send`] + [`Sync`]. - /// - /// [`str`]: prim@str - /// - /// # Examples - /// - /// ``` - /// use std::error::Error; - /// use std::mem; - /// - /// let a_str_error = "a str error"; - /// let a_boxed_error = Box::<dyn Error + Send + Sync>::from(a_str_error); - /// assert!( - /// mem::size_of::<Box<dyn Error + Send + Sync>>() == mem::size_of_val(&a_boxed_error)) - /// ``` - #[inline] - fn from(err: &str) -> Box<dyn Error + Send + Sync + 'a> { - From::from(String::from(err)) - } -} - -#[cfg(not(no_global_oom_handling))] -#[stable(feature = "string_box_error", since = "1.6.0")] -impl<'a> From<&str> for Box<dyn Error + 'a> { - /// Converts a [`str`] into a box of dyn [`Error`]. - /// - /// [`str`]: prim@str - /// - /// # Examples - /// - /// ``` - /// use std::error::Error; - /// use std::mem; - /// - /// let a_str_error = "a str error"; - /// let a_boxed_error = Box::<dyn Error>::from(a_str_error); - /// assert!(mem::size_of::<Box<dyn Error>>() == mem::size_of_val(&a_boxed_error)) - /// ``` - fn from(err: &str) -> Box<dyn Error + 'a> { - From::from(String::from(err)) - } -} - -#[cfg(not(no_global_oom_handling))] -#[stable(feature = "cow_box_error", since = "1.22.0")] -impl<'a, 'b> From<Cow<'b, str>> for Box<dyn Error + Send + Sync + 'a> { - /// Converts a [`Cow`] into a box of dyn [`Error`] + [`Send`] + [`Sync`]. - /// - /// # Examples - /// - /// ``` - /// use std::error::Error; - /// use std::mem; - /// use std::borrow::Cow; - /// - /// let a_cow_str_error = Cow::from("a str error"); - /// let a_boxed_error = Box::<dyn Error + Send + Sync>::from(a_cow_str_error); - /// assert!( - /// mem::size_of::<Box<dyn Error + Send + Sync>>() == mem::size_of_val(&a_boxed_error)) - /// ``` - fn from(err: Cow<'b, str>) -> Box<dyn Error + Send + Sync + 'a> { - From::from(String::from(err)) - } -} - -#[cfg(not(no_global_oom_handling))] -#[stable(feature = "cow_box_error", since = "1.22.0")] -impl<'a, 'b> From<Cow<'b, str>> for Box<dyn Error + 'a> { - /// Converts a [`Cow`] into a box of dyn [`Error`]. - /// - /// # Examples - /// - /// ``` - /// use std::error::Error; - /// use std::mem; - /// use std::borrow::Cow; - /// - /// let a_cow_str_error = Cow::from("a str error"); - /// let a_boxed_error = Box::<dyn Error>::from(a_cow_str_error); - /// assert!(mem::size_of::<Box<dyn Error>>() == mem::size_of_val(&a_boxed_error)) - /// ``` - fn from(err: Cow<'b, str>) -> Box<dyn Error + 'a> { - From::from(String::from(err)) - } -} - #[stable(feature = "box_error", since = "1.8.0")] -impl<T: core::error::Error> core::error::Error for Box<T> { +impl<E: Error> Error for Box<E> { #[allow(deprecated, deprecated_in_future)] fn description(&self) -> &str { - core::error::Error::description(&**self) + Error::description(&**self) } #[allow(deprecated)] - fn cause(&self) -> Option<&dyn core::error::Error> { - core::error::Error::cause(&**self) + fn cause(&self) -> Option<&dyn Error> { + Error::cause(&**self) } - fn source(&self) -> Option<&(dyn core::error::Error + 'static)> { - core::error::Error::source(&**self) + fn source(&self) -> Option<&(dyn Error + 'static)> { + Error::source(&**self) } - fn provide<'b>(&'b self, request: &mut core::error::Request<'b>) { - core::error::Error::provide(&**self, request); + fn provide<'b>(&'b self, request: &mut error::Request<'b>) { + Error::provide(&**self, request); } } - -#[unstable(feature = "pin_coerce_unsized_trait", issue = "123430")] -unsafe impl<T: ?Sized, A: Allocator> PinCoerceUnsized for Box<T, A> {} diff --git a/library/alloc/src/boxed/convert.rs b/library/alloc/src/boxed/convert.rs new file mode 100644 index 00000000000..19a583ca546 --- /dev/null +++ b/library/alloc/src/boxed/convert.rs @@ -0,0 +1,747 @@ +use core::any::Any; +use core::error::Error; +use core::mem; +use core::pin::Pin; +#[cfg(not(no_global_oom_handling))] +use core::{fmt, ptr}; + +use crate::alloc::Allocator; +#[cfg(not(no_global_oom_handling))] +use crate::borrow::Cow; +use crate::boxed::Box; +#[cfg(not(no_global_oom_handling))] +use crate::raw_vec::RawVec; +#[cfg(not(no_global_oom_handling))] +use crate::str::from_boxed_utf8_unchecked; +#[cfg(not(no_global_oom_handling))] +use crate::string::String; +#[cfg(not(no_global_oom_handling))] +use crate::vec::Vec; + +#[cfg(not(no_global_oom_handling))] +#[stable(feature = "from_for_ptrs", since = "1.6.0")] +impl<T> From<T> for Box<T> { + /// Converts a `T` into a `Box<T>` + /// + /// The conversion allocates on the heap and moves `t` + /// from the stack into it. + /// + /// # Examples + /// + /// ```rust + /// let x = 5; + /// let boxed = Box::new(5); + /// + /// assert_eq!(Box::from(x), boxed); + /// ``` + fn from(t: T) -> Self { + Box::new(t) + } +} + +#[stable(feature = "pin", since = "1.33.0")] +impl<T: ?Sized, A: Allocator> From<Box<T, A>> for Pin<Box<T, A>> +where + A: 'static, +{ + /// Converts a `Box<T>` into a `Pin<Box<T>>`. If `T` does not implement [`Unpin`], then + /// `*boxed` will be pinned in memory and unable to be moved. + /// + /// This conversion does not allocate on the heap and happens in place. + /// + /// This is also available via [`Box::into_pin`]. + /// + /// Constructing and pinning a `Box` with <code><Pin<Box\<T>>>::from([Box::new]\(x))</code> + /// can also be written more concisely using <code>[Box::pin]\(x)</code>. + /// This `From` implementation is useful if you already have a `Box<T>`, or you are + /// constructing a (pinned) `Box` in a different way than with [`Box::new`]. + fn from(boxed: Box<T, A>) -> Self { + Box::into_pin(boxed) + } +} + +/// Specialization trait used for `From<&[T]>`. +#[cfg(not(no_global_oom_handling))] +trait BoxFromSlice<T> { + fn from_slice(slice: &[T]) -> Self; +} + +#[cfg(not(no_global_oom_handling))] +impl<T: Clone> BoxFromSlice<T> for Box<[T]> { + #[inline] + default fn from_slice(slice: &[T]) -> Self { + slice.to_vec().into_boxed_slice() + } +} + +#[cfg(not(no_global_oom_handling))] +impl<T: Copy> BoxFromSlice<T> for Box<[T]> { + #[inline] + fn from_slice(slice: &[T]) -> Self { + let len = slice.len(); + let buf = RawVec::with_capacity(len); + unsafe { + ptr::copy_nonoverlapping(slice.as_ptr(), buf.ptr(), len); + buf.into_box(slice.len()).assume_init() + } + } +} + +#[cfg(not(no_global_oom_handling))] +#[stable(feature = "box_from_slice", since = "1.17.0")] +impl<T: Clone> From<&[T]> for Box<[T]> { + /// Converts a `&[T]` into a `Box<[T]>` + /// + /// This conversion allocates on the heap + /// and performs a copy of `slice` and its contents. + /// + /// # Examples + /// ```rust + /// // create a &[u8] which will be used to create a Box<[u8]> + /// let slice: &[u8] = &[104, 101, 108, 108, 111]; + /// let boxed_slice: Box<[u8]> = Box::from(slice); + /// + /// println!("{boxed_slice:?}"); + /// ``` + #[inline] + fn from(slice: &[T]) -> Box<[T]> { + <Self as BoxFromSlice<T>>::from_slice(slice) + } +} + +#[cfg(not(no_global_oom_handling))] +#[stable(feature = "box_from_cow", since = "1.45.0")] +impl<T: Clone> From<Cow<'_, [T]>> for Box<[T]> { + /// Converts a `Cow<'_, [T]>` into a `Box<[T]>` + /// + /// When `cow` is the `Cow::Borrowed` variant, this + /// conversion allocates on the heap and copies the + /// underlying slice. Otherwise, it will try to reuse the owned + /// `Vec`'s allocation. + #[inline] + fn from(cow: Cow<'_, [T]>) -> Box<[T]> { + match cow { + Cow::Borrowed(slice) => Box::from(slice), + Cow::Owned(slice) => Box::from(slice), + } + } +} + +#[cfg(not(no_global_oom_handling))] +#[stable(feature = "box_from_slice", since = "1.17.0")] +impl From<&str> for Box<str> { + /// Converts a `&str` into a `Box<str>` + /// + /// This conversion allocates on the heap + /// and performs a copy of `s`. + /// + /// # Examples + /// + /// ```rust + /// let boxed: Box<str> = Box::from("hello"); + /// println!("{boxed}"); + /// ``` + #[inline] + fn from(s: &str) -> Box<str> { + unsafe { from_boxed_utf8_unchecked(Box::from(s.as_bytes())) } + } +} + +#[cfg(not(no_global_oom_handling))] +#[stable(feature = "box_from_cow", since = "1.45.0")] +impl From<Cow<'_, str>> for Box<str> { + /// Converts a `Cow<'_, str>` into a `Box<str>` + /// + /// When `cow` is the `Cow::Borrowed` variant, this + /// conversion allocates on the heap and copies the + /// underlying `str`. Otherwise, it will try to reuse the owned + /// `String`'s allocation. + /// + /// # Examples + /// + /// ```rust + /// use std::borrow::Cow; + /// + /// let unboxed = Cow::Borrowed("hello"); + /// let boxed: Box<str> = Box::from(unboxed); + /// println!("{boxed}"); + /// ``` + /// + /// ```rust + /// # use std::borrow::Cow; + /// let unboxed = Cow::Owned("hello".to_string()); + /// let boxed: Box<str> = Box::from(unboxed); + /// println!("{boxed}"); + /// ``` + #[inline] + fn from(cow: Cow<'_, str>) -> Box<str> { + match cow { + Cow::Borrowed(s) => Box::from(s), + Cow::Owned(s) => Box::from(s), + } + } +} + +#[stable(feature = "boxed_str_conv", since = "1.19.0")] +impl<A: Allocator> From<Box<str, A>> for Box<[u8], A> { + /// Converts a `Box<str>` into a `Box<[u8]>` + /// + /// This conversion does not allocate on the heap and happens in place. + /// + /// # Examples + /// ```rust + /// // create a Box<str> which will be used to create a Box<[u8]> + /// let boxed: Box<str> = Box::from("hello"); + /// let boxed_str: Box<[u8]> = Box::from(boxed); + /// + /// // create a &[u8] which will be used to create a Box<[u8]> + /// let slice: &[u8] = &[104, 101, 108, 108, 111]; + /// let boxed_slice = Box::from(slice); + /// + /// assert_eq!(boxed_slice, boxed_str); + /// ``` + #[inline] + fn from(s: Box<str, A>) -> Self { + let (raw, alloc) = Box::into_raw_with_allocator(s); + unsafe { Box::from_raw_in(raw as *mut [u8], alloc) } + } +} + +#[cfg(not(no_global_oom_handling))] +#[stable(feature = "box_from_array", since = "1.45.0")] +impl<T, const N: usize> From<[T; N]> for Box<[T]> { + /// Converts a `[T; N]` into a `Box<[T]>` + /// + /// This conversion moves the array to newly heap-allocated memory. + /// + /// # Examples + /// + /// ```rust + /// let boxed: Box<[u8]> = Box::from([4, 2]); + /// println!("{boxed:?}"); + /// ``` + fn from(array: [T; N]) -> Box<[T]> { + Box::new(array) + } +} + +/// Casts a boxed slice to a boxed array. +/// +/// # Safety +/// +/// `boxed_slice.len()` must be exactly `N`. +unsafe fn boxed_slice_as_array_unchecked<T, A: Allocator, const N: usize>( + boxed_slice: Box<[T], A>, +) -> Box<[T; N], A> { + debug_assert_eq!(boxed_slice.len(), N); + + let (ptr, alloc) = Box::into_raw_with_allocator(boxed_slice); + // SAFETY: Pointer and allocator came from an existing box, + // and our safety condition requires that the length is exactly `N` + unsafe { Box::from_raw_in(ptr as *mut [T; N], alloc) } +} + +#[stable(feature = "boxed_slice_try_from", since = "1.43.0")] +impl<T, const N: usize> TryFrom<Box<[T]>> for Box<[T; N]> { + type Error = Box<[T]>; + + /// Attempts to convert a `Box<[T]>` into a `Box<[T; N]>`. + /// + /// The conversion occurs in-place and does not require a + /// new memory allocation. + /// + /// # Errors + /// + /// Returns the old `Box<[T]>` in the `Err` variant if + /// `boxed_slice.len()` does not equal `N`. + fn try_from(boxed_slice: Box<[T]>) -> Result<Self, Self::Error> { + if boxed_slice.len() == N { + Ok(unsafe { boxed_slice_as_array_unchecked(boxed_slice) }) + } else { + Err(boxed_slice) + } + } +} + +#[cfg(not(no_global_oom_handling))] +#[stable(feature = "boxed_array_try_from_vec", since = "1.66.0")] +impl<T, const N: usize> TryFrom<Vec<T>> for Box<[T; N]> { + type Error = Vec<T>; + + /// Attempts to convert a `Vec<T>` into a `Box<[T; N]>`. + /// + /// Like [`Vec::into_boxed_slice`], this is in-place if `vec.capacity() == N`, + /// but will require a reallocation otherwise. + /// + /// # Errors + /// + /// Returns the original `Vec<T>` in the `Err` variant if + /// `boxed_slice.len()` does not equal `N`. + /// + /// # Examples + /// + /// This can be used with [`vec!`] to create an array on the heap: + /// + /// ``` + /// let state: Box<[f32; 100]> = vec![1.0; 100].try_into().unwrap(); + /// assert_eq!(state.len(), 100); + /// ``` + fn try_from(vec: Vec<T>) -> Result<Self, Self::Error> { + if vec.len() == N { + let boxed_slice = vec.into_boxed_slice(); + Ok(unsafe { boxed_slice_as_array_unchecked(boxed_slice) }) + } else { + Err(vec) + } + } +} + +impl<A: Allocator> Box<dyn Any, A> { + /// Attempts to downcast the box to a concrete type. + /// + /// # Examples + /// + /// ``` + /// use std::any::Any; + /// + /// fn print_if_string(value: Box<dyn Any>) { + /// if let Ok(string) = value.downcast::<String>() { + /// println!("String ({}): {}", string.len(), string); + /// } + /// } + /// + /// let my_string = "Hello World".to_string(); + /// print_if_string(Box::new(my_string)); + /// print_if_string(Box::new(0i8)); + /// ``` + #[inline] + #[stable(feature = "rust1", since = "1.0.0")] + pub fn downcast<T: Any>(self) -> Result<Box<T, A>, Self> { + if self.is::<T>() { unsafe { Ok(self.downcast_unchecked::<T>()) } } else { Err(self) } + } + + /// Downcasts the box to a concrete type. + /// + /// For a safe alternative see [`downcast`]. + /// + /// # Examples + /// + /// ``` + /// #![feature(downcast_unchecked)] + /// + /// use std::any::Any; + /// + /// let x: Box<dyn Any> = Box::new(1_usize); + /// + /// unsafe { + /// assert_eq!(*x.downcast_unchecked::<usize>(), 1); + /// } + /// ``` + /// + /// # Safety + /// + /// The contained value must be of type `T`. Calling this method + /// with the incorrect type is *undefined behavior*. + /// + /// [`downcast`]: Self::downcast + #[inline] + #[unstable(feature = "downcast_unchecked", issue = "90850")] + pub unsafe fn downcast_unchecked<T: Any>(self) -> Box<T, A> { + debug_assert!(self.is::<T>()); + unsafe { + let (raw, alloc): (*mut dyn Any, _) = Box::into_raw_with_allocator(self); + Box::from_raw_in(raw as *mut T, alloc) + } + } +} + +impl<A: Allocator> Box<dyn Any + Send, A> { + /// Attempts to downcast the box to a concrete type. + /// + /// # Examples + /// + /// ``` + /// use std::any::Any; + /// + /// fn print_if_string(value: Box<dyn Any + Send>) { + /// if let Ok(string) = value.downcast::<String>() { + /// println!("String ({}): {}", string.len(), string); + /// } + /// } + /// + /// let my_string = "Hello World".to_string(); + /// print_if_string(Box::new(my_string)); + /// print_if_string(Box::new(0i8)); + /// ``` + #[inline] + #[stable(feature = "rust1", since = "1.0.0")] + pub fn downcast<T: Any>(self) -> Result<Box<T, A>, Self> { + if self.is::<T>() { unsafe { Ok(self.downcast_unchecked::<T>()) } } else { Err(self) } + } + + /// Downcasts the box to a concrete type. + /// + /// For a safe alternative see [`downcast`]. + /// + /// # Examples + /// + /// ``` + /// #![feature(downcast_unchecked)] + /// + /// use std::any::Any; + /// + /// let x: Box<dyn Any + Send> = Box::new(1_usize); + /// + /// unsafe { + /// assert_eq!(*x.downcast_unchecked::<usize>(), 1); + /// } + /// ``` + /// + /// # Safety + /// + /// The contained value must be of type `T`. Calling this method + /// with the incorrect type is *undefined behavior*. + /// + /// [`downcast`]: Self::downcast + #[inline] + #[unstable(feature = "downcast_unchecked", issue = "90850")] + pub unsafe fn downcast_unchecked<T: Any>(self) -> Box<T, A> { + debug_assert!(self.is::<T>()); + unsafe { + let (raw, alloc): (*mut (dyn Any + Send), _) = Box::into_raw_with_allocator(self); + Box::from_raw_in(raw as *mut T, alloc) + } + } +} + +impl<A: Allocator> Box<dyn Any + Send + Sync, A> { + /// Attempts to downcast the box to a concrete type. + /// + /// # Examples + /// + /// ``` + /// use std::any::Any; + /// + /// fn print_if_string(value: Box<dyn Any + Send + Sync>) { + /// if let Ok(string) = value.downcast::<String>() { + /// println!("String ({}): {}", string.len(), string); + /// } + /// } + /// + /// let my_string = "Hello World".to_string(); + /// print_if_string(Box::new(my_string)); + /// print_if_string(Box::new(0i8)); + /// ``` + #[inline] + #[stable(feature = "box_send_sync_any_downcast", since = "1.51.0")] + pub fn downcast<T: Any>(self) -> Result<Box<T, A>, Self> { + if self.is::<T>() { unsafe { Ok(self.downcast_unchecked::<T>()) } } else { Err(self) } + } + + /// Downcasts the box to a concrete type. + /// + /// For a safe alternative see [`downcast`]. + /// + /// # Examples + /// + /// ``` + /// #![feature(downcast_unchecked)] + /// + /// use std::any::Any; + /// + /// let x: Box<dyn Any + Send + Sync> = Box::new(1_usize); + /// + /// unsafe { + /// assert_eq!(*x.downcast_unchecked::<usize>(), 1); + /// } + /// ``` + /// + /// # Safety + /// + /// The contained value must be of type `T`. Calling this method + /// with the incorrect type is *undefined behavior*. + /// + /// [`downcast`]: Self::downcast + #[inline] + #[unstable(feature = "downcast_unchecked", issue = "90850")] + pub unsafe fn downcast_unchecked<T: Any>(self) -> Box<T, A> { + debug_assert!(self.is::<T>()); + unsafe { + let (raw, alloc): (*mut (dyn Any + Send + Sync), _) = + Box::into_raw_with_allocator(self); + Box::from_raw_in(raw as *mut T, alloc) + } + } +} + +#[cfg(not(no_global_oom_handling))] +#[stable(feature = "rust1", since = "1.0.0")] +impl<'a, E: Error + 'a> From<E> for Box<dyn Error + 'a> { + /// Converts a type of [`Error`] into a box of dyn [`Error`]. + /// + /// # Examples + /// + /// ``` + /// use std::error::Error; + /// use std::fmt; + /// use std::mem; + /// + /// #[derive(Debug)] + /// struct AnError; + /// + /// impl fmt::Display for AnError { + /// fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { + /// write!(f, "An error") + /// } + /// } + /// + /// impl Error for AnError {} + /// + /// let an_error = AnError; + /// assert!(0 == mem::size_of_val(&an_error)); + /// let a_boxed_error = Box::<dyn Error>::from(an_error); + /// assert!(mem::size_of::<Box<dyn Error>>() == mem::size_of_val(&a_boxed_error)) + /// ``` + fn from(err: E) -> Box<dyn Error + 'a> { + Box::new(err) + } +} + +#[cfg(not(no_global_oom_handling))] +#[stable(feature = "rust1", since = "1.0.0")] +impl<'a, E: Error + Send + Sync + 'a> From<E> for Box<dyn Error + Send + Sync + 'a> { + /// Converts a type of [`Error`] + [`Send`] + [`Sync`] into a box of + /// dyn [`Error`] + [`Send`] + [`Sync`]. + /// + /// # Examples + /// + /// ``` + /// use std::error::Error; + /// use std::fmt; + /// use std::mem; + /// + /// #[derive(Debug)] + /// struct AnError; + /// + /// impl fmt::Display for AnError { + /// fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { + /// write!(f, "An error") + /// } + /// } + /// + /// impl Error for AnError {} + /// + /// unsafe impl Send for AnError {} + /// + /// unsafe impl Sync for AnError {} + /// + /// let an_error = AnError; + /// assert!(0 == mem::size_of_val(&an_error)); + /// let a_boxed_error = Box::<dyn Error + Send + Sync>::from(an_error); + /// assert!( + /// mem::size_of::<Box<dyn Error + Send + Sync>>() == mem::size_of_val(&a_boxed_error)) + /// ``` + fn from(err: E) -> Box<dyn Error + Send + Sync + 'a> { + Box::new(err) + } +} + +#[cfg(not(no_global_oom_handling))] +#[stable(feature = "rust1", since = "1.0.0")] +impl<'a> From<String> for Box<dyn Error + Send + Sync + 'a> { + /// Converts a [`String`] into a box of dyn [`Error`] + [`Send`] + [`Sync`]. + /// + /// # Examples + /// + /// ``` + /// use std::error::Error; + /// use std::mem; + /// + /// let a_string_error = "a string error".to_string(); + /// let a_boxed_error = Box::<dyn Error + Send + Sync>::from(a_string_error); + /// assert!( + /// mem::size_of::<Box<dyn Error + Send + Sync>>() == mem::size_of_val(&a_boxed_error)) + /// ``` + #[inline] + fn from(err: String) -> Box<dyn Error + Send + Sync + 'a> { + struct StringError(String); + + impl Error for StringError { + #[allow(deprecated)] + fn description(&self) -> &str { + &self.0 + } + } + + impl fmt::Display for StringError { + fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { + fmt::Display::fmt(&self.0, f) + } + } + + // Purposefully skip printing "StringError(..)" + impl fmt::Debug for StringError { + fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { + fmt::Debug::fmt(&self.0, f) + } + } + + Box::new(StringError(err)) + } +} + +#[cfg(not(no_global_oom_handling))] +#[stable(feature = "string_box_error", since = "1.6.0")] +impl<'a> From<String> for Box<dyn Error + 'a> { + /// Converts a [`String`] into a box of dyn [`Error`]. + /// + /// # Examples + /// + /// ``` + /// use std::error::Error; + /// use std::mem; + /// + /// let a_string_error = "a string error".to_string(); + /// let a_boxed_error = Box::<dyn Error>::from(a_string_error); + /// assert!(mem::size_of::<Box<dyn Error>>() == mem::size_of_val(&a_boxed_error)) + /// ``` + fn from(str_err: String) -> Box<dyn Error + 'a> { + let err1: Box<dyn Error + Send + Sync> = From::from(str_err); + let err2: Box<dyn Error> = err1; + err2 + } +} + +#[cfg(not(no_global_oom_handling))] +#[stable(feature = "rust1", since = "1.0.0")] +impl<'a> From<&str> for Box<dyn Error + Send + Sync + 'a> { + /// Converts a [`str`] into a box of dyn [`Error`] + [`Send`] + [`Sync`]. + /// + /// [`str`]: prim@str + /// + /// # Examples + /// + /// ``` + /// use std::error::Error; + /// use std::mem; + /// + /// let a_str_error = "a str error"; + /// let a_boxed_error = Box::<dyn Error + Send + Sync>::from(a_str_error); + /// assert!( + /// mem::size_of::<Box<dyn Error + Send + Sync>>() == mem::size_of_val(&a_boxed_error)) + /// ``` + #[inline] + fn from(err: &str) -> Box<dyn Error + Send + Sync + 'a> { + From::from(String::from(err)) + } +} + +#[cfg(not(no_global_oom_handling))] +#[stable(feature = "string_box_error", since = "1.6.0")] +impl<'a> From<&str> for Box<dyn Error + 'a> { + /// Converts a [`str`] into a box of dyn [`Error`]. + /// + /// [`str`]: prim@str + /// + /// # Examples + /// + /// ``` + /// use std::error::Error; + /// use std::mem; + /// + /// let a_str_error = "a str error"; + /// let a_boxed_error = Box::<dyn Error>::from(a_str_error); + /// assert!(mem::size_of::<Box<dyn Error>>() == mem::size_of_val(&a_boxed_error)) + /// ``` + fn from(err: &str) -> Box<dyn Error + 'a> { + From::from(String::from(err)) + } +} + +#[cfg(not(no_global_oom_handling))] +#[stable(feature = "cow_box_error", since = "1.22.0")] +impl<'a, 'b> From<Cow<'b, str>> for Box<dyn Error + Send + Sync + 'a> { + /// Converts a [`Cow`] into a box of dyn [`Error`] + [`Send`] + [`Sync`]. + /// + /// # Examples + /// + /// ``` + /// use std::error::Error; + /// use std::mem; + /// use std::borrow::Cow; + /// + /// let a_cow_str_error = Cow::from("a str error"); + /// let a_boxed_error = Box::<dyn Error + Send + Sync>::from(a_cow_str_error); + /// assert!( + /// mem::size_of::<Box<dyn Error + Send + Sync>>() == mem::size_of_val(&a_boxed_error)) + /// ``` + fn from(err: Cow<'b, str>) -> Box<dyn Error + Send + Sync + 'a> { + From::from(String::from(err)) + } +} + +#[cfg(not(no_global_oom_handling))] +#[stable(feature = "cow_box_error", since = "1.22.0")] +impl<'a, 'b> From<Cow<'b, str>> for Box<dyn Error + 'a> { + /// Converts a [`Cow`] into a box of dyn [`Error`]. + /// + /// # Examples + /// + /// ``` + /// use std::error::Error; + /// use std::mem; + /// use std::borrow::Cow; + /// + /// let a_cow_str_error = Cow::from("a str error"); + /// let a_boxed_error = Box::<dyn Error>::from(a_cow_str_error); + /// assert!(mem::size_of::<Box<dyn Error>>() == mem::size_of_val(&a_boxed_error)) + /// ``` + fn from(err: Cow<'b, str>) -> Box<dyn Error + 'a> { + From::from(String::from(err)) + } +} + +impl dyn Error { + /// Attempts to downcast the box to a concrete type. + #[inline] + #[stable(feature = "error_downcast", since = "1.3.0")] + #[rustc_allow_incoherent_impl] + pub fn downcast<T: Error + 'static>(self: Box<Self>) -> Result<Box<T>, Box<dyn Error>> { + if self.is::<T>() { + unsafe { + let raw: *mut dyn Error = Box::into_raw(self); + Ok(Box::from_raw(raw as *mut T)) + } + } else { + Err(self) + } + } +} + +impl dyn Error + Send { + /// Attempts to downcast the box to a concrete type. + #[inline] + #[stable(feature = "error_downcast", since = "1.3.0")] + #[rustc_allow_incoherent_impl] + pub fn downcast<T: Error + 'static>(self: Box<Self>) -> Result<Box<T>, Box<dyn Error + Send>> { + let err: Box<dyn Error> = self; + <dyn Error>::downcast(err).map_err(|s| unsafe { + // Reapply the `Send` marker. + mem::transmute::<Box<dyn Error>, Box<dyn Error + Send>>(s) + }) + } +} + +impl dyn Error + Send + Sync { + /// Attempts to downcast the box to a concrete type. + #[inline] + #[stable(feature = "error_downcast", since = "1.3.0")] + #[rustc_allow_incoherent_impl] + pub fn downcast<T: Error + 'static>(self: Box<Self>) -> Result<Box<T>, Box<Self>> { + let err: Box<dyn Error> = self; + <dyn Error>::downcast(err).map_err(|s| unsafe { + // Reapply the `Send + Sync` markers. + mem::transmute::<Box<dyn Error>, Box<dyn Error + Send + Sync>>(s) + }) + } +} diff --git a/library/alloc/src/boxed/iter.rs b/library/alloc/src/boxed/iter.rs new file mode 100644 index 00000000000..90582aa49c6 --- /dev/null +++ b/library/alloc/src/boxed/iter.rs @@ -0,0 +1,194 @@ +use core::async_iter::AsyncIterator; +use core::iter::FusedIterator; +use core::pin::Pin; +use core::slice; +use core::task::{Context, Poll}; + +use crate::alloc::Allocator; +#[cfg(not(no_global_oom_handling))] +use crate::borrow::Cow; +use crate::boxed::Box; +#[cfg(not(no_global_oom_handling))] +use crate::string::String; +use crate::vec; +#[cfg(not(no_global_oom_handling))] +use crate::vec::Vec; + +#[stable(feature = "rust1", since = "1.0.0")] +impl<I: Iterator + ?Sized, A: Allocator> Iterator for Box<I, A> { + type Item = I::Item; + fn next(&mut self) -> Option<I::Item> { + (**self).next() + } + fn size_hint(&self) -> (usize, Option<usize>) { + (**self).size_hint() + } + fn nth(&mut self, n: usize) -> Option<I::Item> { + (**self).nth(n) + } + fn last(self) -> Option<I::Item> { + BoxIter::last(self) + } +} + +trait BoxIter { + type Item; + fn last(self) -> Option<Self::Item>; +} + +impl<I: Iterator + ?Sized, A: Allocator> BoxIter for Box<I, A> { + type Item = I::Item; + default fn last(self) -> Option<I::Item> { + #[inline] + fn some<T>(_: Option<T>, x: T) -> Option<T> { + Some(x) + } + + self.fold(None, some) + } +} + +/// Specialization for sized `I`s that uses `I`s implementation of `last()` +/// instead of the default. +#[stable(feature = "rust1", since = "1.0.0")] +impl<I: Iterator, A: Allocator> BoxIter for Box<I, A> { + fn last(self) -> Option<I::Item> { + (*self).last() + } +} + +#[stable(feature = "rust1", since = "1.0.0")] +impl<I: DoubleEndedIterator + ?Sized, A: Allocator> DoubleEndedIterator for Box<I, A> { + fn next_back(&mut self) -> Option<I::Item> { + (**self).next_back() + } + fn nth_back(&mut self, n: usize) -> Option<I::Item> { + (**self).nth_back(n) + } +} +#[stable(feature = "rust1", since = "1.0.0")] +impl<I: ExactSizeIterator + ?Sized, A: Allocator> ExactSizeIterator for Box<I, A> { + fn len(&self) -> usize { + (**self).len() + } + fn is_empty(&self) -> bool { + (**self).is_empty() + } +} + +#[stable(feature = "fused", since = "1.26.0")] +impl<I: FusedIterator + ?Sized, A: Allocator> FusedIterator for Box<I, A> {} + +#[unstable(feature = "async_iterator", issue = "79024")] +impl<S: ?Sized + AsyncIterator + Unpin> AsyncIterator for Box<S> { + type Item = S::Item; + + fn poll_next(mut self: Pin<&mut Self>, cx: &mut Context<'_>) -> Poll<Option<Self::Item>> { + Pin::new(&mut **self).poll_next(cx) + } + + fn size_hint(&self) -> (usize, Option<usize>) { + (**self).size_hint() + } +} + +/// This implementation is required to make sure that the `Box<[I]>: IntoIterator` +/// implementation doesn't overlap with `IntoIterator for T where T: Iterator` blanket. +#[stable(feature = "boxed_slice_into_iter", since = "1.80.0")] +impl<I, A: Allocator> !Iterator for Box<[I], A> {} + +/// This implementation is required to make sure that the `&Box<[I]>: IntoIterator` +/// implementation doesn't overlap with `IntoIterator for T where T: Iterator` blanket. +#[stable(feature = "boxed_slice_into_iter", since = "1.80.0")] +impl<'a, I, A: Allocator> !Iterator for &'a Box<[I], A> {} + +/// This implementation is required to make sure that the `&mut Box<[I]>: IntoIterator` +/// implementation doesn't overlap with `IntoIterator for T where T: Iterator` blanket. +#[stable(feature = "boxed_slice_into_iter", since = "1.80.0")] +impl<'a, I, A: Allocator> !Iterator for &'a mut Box<[I], A> {} + +// Note: the `#[rustc_skip_during_method_dispatch(boxed_slice)]` on `trait IntoIterator` +// hides this implementation from explicit `.into_iter()` calls on editions < 2024, +// so those calls will still resolve to the slice implementation, by reference. +#[stable(feature = "boxed_slice_into_iter", since = "1.80.0")] +impl<I, A: Allocator> IntoIterator for Box<[I], A> { + type IntoIter = vec::IntoIter<I, A>; + type Item = I; + fn into_iter(self) -> vec::IntoIter<I, A> { + self.into_vec().into_iter() + } +} + +#[stable(feature = "boxed_slice_into_iter", since = "1.80.0")] +impl<'a, I, A: Allocator> IntoIterator for &'a Box<[I], A> { + type IntoIter = slice::Iter<'a, I>; + type Item = &'a I; + fn into_iter(self) -> slice::Iter<'a, I> { + self.iter() + } +} + +#[stable(feature = "boxed_slice_into_iter", since = "1.80.0")] +impl<'a, I, A: Allocator> IntoIterator for &'a mut Box<[I], A> { + type IntoIter = slice::IterMut<'a, I>; + type Item = &'a mut I; + fn into_iter(self) -> slice::IterMut<'a, I> { + self.iter_mut() + } +} + +#[cfg(not(no_global_oom_handling))] +#[stable(feature = "boxed_slice_from_iter", since = "1.32.0")] +impl<I> FromIterator<I> for Box<[I]> { + fn from_iter<T: IntoIterator<Item = I>>(iter: T) -> Self { + iter.into_iter().collect::<Vec<_>>().into_boxed_slice() + } +} + +#[cfg(not(no_global_oom_handling))] +#[stable(feature = "boxed_str_from_iter", since = "1.80.0")] +impl FromIterator<char> for Box<str> { + fn from_iter<T: IntoIterator<Item = char>>(iter: T) -> Self { + String::from_iter(iter).into_boxed_str() + } +} + +#[cfg(not(no_global_oom_handling))] +#[stable(feature = "boxed_str_from_iter", since = "1.80.0")] +impl<'a> FromIterator<&'a char> for Box<str> { + fn from_iter<T: IntoIterator<Item = &'a char>>(iter: T) -> Self { + String::from_iter(iter).into_boxed_str() + } +} + +#[cfg(not(no_global_oom_handling))] +#[stable(feature = "boxed_str_from_iter", since = "1.80.0")] +impl<'a> FromIterator<&'a str> for Box<str> { + fn from_iter<T: IntoIterator<Item = &'a str>>(iter: T) -> Self { + String::from_iter(iter).into_boxed_str() + } +} + +#[cfg(not(no_global_oom_handling))] +#[stable(feature = "boxed_str_from_iter", since = "1.80.0")] +impl FromIterator<String> for Box<str> { + fn from_iter<T: IntoIterator<Item = String>>(iter: T) -> Self { + String::from_iter(iter).into_boxed_str() + } +} + +#[cfg(not(no_global_oom_handling))] +#[stable(feature = "boxed_str_from_iter", since = "1.80.0")] +impl<A: Allocator> FromIterator<Box<str, A>> for Box<str> { + fn from_iter<T: IntoIterator<Item = Box<str, A>>>(iter: T) -> Self { + String::from_iter(iter).into_boxed_str() + } +} + +#[cfg(not(no_global_oom_handling))] +#[stable(feature = "boxed_str_from_iter", since = "1.80.0")] +impl<'a> FromIterator<Cow<'a, str>> for Box<str> { + fn from_iter<T: IntoIterator<Item = Cow<'a, str>>>(iter: T) -> Self { + String::from_iter(iter).into_boxed_str() + } +} diff --git a/library/alloc/src/rc.rs b/library/alloc/src/rc.rs index 9fdd51ce331..fc8646e96d9 100644 --- a/library/alloc/src/rc.rs +++ b/library/alloc/src/rc.rs @@ -376,6 +376,21 @@ impl<T: ?Sized, A: Allocator> Rc<T, A> { unsafe fn from_ptr_in(ptr: *mut RcInner<T>, alloc: A) -> Self { unsafe { Self::from_inner_in(NonNull::new_unchecked(ptr), alloc) } } + + // Non-inlined part of `drop`. + #[inline(never)] + unsafe fn drop_slow(&mut self) { + // Reconstruct the "strong weak" pointer and drop it when this + // variable goes out of scope. This ensures that the memory is + // deallocated even if the destructor of `T` panics. + let _weak = Weak { ptr: self.ptr, alloc: &self.alloc }; + + // Destroy the contained object. + // We cannot use `get_mut_unchecked` here, because `self.alloc` is borrowed. + unsafe { + ptr::drop_in_place(&mut (*self.ptr.as_ptr()).value); + } + } } impl<T> Rc<T> { @@ -2252,21 +2267,12 @@ unsafe impl<#[may_dangle] T: ?Sized, A: Allocator> Drop for Rc<T, A> { /// drop(foo); // Doesn't print anything /// drop(foo2); // Prints "dropped!" /// ``` + #[inline] fn drop(&mut self) { unsafe { self.inner().dec_strong(); if self.inner().strong() == 0 { - // destroy the contained object - ptr::drop_in_place(Self::get_mut_unchecked(self)); - - // remove the implicit "strong weak" pointer now that we've - // destroyed the contents. - self.inner().dec_weak(); - - if self.inner().weak() == 0 { - self.alloc - .deallocate(self.ptr.cast(), Layout::for_value_raw(self.ptr.as_ptr())); - } + self.drop_slow(); } } } diff --git a/library/alloc/src/sync.rs b/library/alloc/src/sync.rs index 15a1b0f2834..98a2fe24257 100644 --- a/library/alloc/src/sync.rs +++ b/library/alloc/src/sync.rs @@ -1872,15 +1872,17 @@ impl<T: ?Sized, A: Allocator> Arc<T, A> { // Non-inlined part of `drop`. #[inline(never)] unsafe fn drop_slow(&mut self) { + // Drop the weak ref collectively held by all strong references when this + // variable goes out of scope. This ensures that the memory is deallocated + // even if the destructor of `T` panics. + // Take a reference to `self.alloc` instead of cloning because 1. it'll last long + // enough, and 2. you should be able to drop `Arc`s with unclonable allocators + let _weak = Weak { ptr: self.ptr, alloc: &self.alloc }; + // Destroy the data at this time, even though we must not free the box // allocation itself (there might still be weak pointers lying around). - unsafe { ptr::drop_in_place(Self::get_mut_unchecked(self)) }; - - // Drop the weak ref collectively held by all strong references - // Take a reference to `self.alloc` instead of cloning because 1. it'll - // last long enough, and 2. you should be able to drop `Arc`s with - // unclonable allocators - drop(Weak { ptr: self.ptr, alloc: &self.alloc }); + // We cannot use `get_mut_unchecked` here, because `self.alloc` is borrowed. + unsafe { ptr::drop_in_place(&mut (*self.ptr.as_ptr()).data) }; } /// Returns `true` if the two `Arc`s point to the same allocation in a vein similar to diff --git a/library/alloc/tests/arc.rs b/library/alloc/tests/arc.rs index dc27c578b57..a259c0131ec 100644 --- a/library/alloc/tests/arc.rs +++ b/library/alloc/tests/arc.rs @@ -1,5 +1,5 @@ use std::any::Any; -use std::cell::RefCell; +use std::cell::{Cell, RefCell}; use std::iter::TrustedLen; use std::mem; use std::sync::{Arc, Weak}; @@ -89,7 +89,7 @@ fn eq() { // The test code below is identical to that in `rc.rs`. // For better maintainability we therefore define this type alias. -type Rc<T> = Arc<T>; +type Rc<T, A = std::alloc::Global> = Arc<T, A>; const SHARED_ITER_MAX: u16 = 100; @@ -210,6 +210,42 @@ fn weak_may_dangle() { // borrow might be used here, when `val` is dropped and runs the `Drop` code for type `std::sync::Weak` } +/// Test that a panic from a destructor does not leak the allocation. +#[test] +#[cfg_attr(not(panic = "unwind"), ignore = "test requires unwinding support")] +fn panic_no_leak() { + use std::alloc::{AllocError, Allocator, Global, Layout}; + use std::panic::{AssertUnwindSafe, catch_unwind}; + use std::ptr::NonNull; + + struct AllocCount(Cell<i32>); + unsafe impl Allocator for AllocCount { + fn allocate(&self, layout: Layout) -> Result<NonNull<[u8]>, AllocError> { + self.0.set(self.0.get() + 1); + Global.allocate(layout) + } + unsafe fn deallocate(&self, ptr: NonNull<u8>, layout: Layout) { + self.0.set(self.0.get() - 1); + unsafe { Global.deallocate(ptr, layout) } + } + } + + struct PanicOnDrop; + impl Drop for PanicOnDrop { + fn drop(&mut self) { + panic!("PanicOnDrop"); + } + } + + let alloc = AllocCount(Cell::new(0)); + let rc = Rc::new_in(PanicOnDrop, &alloc); + assert_eq!(alloc.0.get(), 1); + + let panic_message = catch_unwind(AssertUnwindSafe(|| drop(rc))).unwrap_err(); + assert_eq!(*panic_message.downcast_ref::<&'static str>().unwrap(), "PanicOnDrop"); + assert_eq!(alloc.0.get(), 0); +} + /// This is similar to the doc-test for `Arc::make_mut()`, but on an unsized type (slice). #[test] fn make_mut_unsized() { diff --git a/library/alloc/tests/boxed.rs b/library/alloc/tests/boxed.rs index bfc31a626fa..6a8ba5c92fb 100644 --- a/library/alloc/tests/boxed.rs +++ b/library/alloc/tests/boxed.rs @@ -4,6 +4,7 @@ use core::mem::MaybeUninit; use core::ptr::NonNull; #[test] +#[cfg_attr(not(bootstrap), expect(dangling_pointers_from_temporaries))] fn uninitialized_zero_size_box() { assert_eq!( &*Box::<()>::new_uninit() as *const _, @@ -59,6 +60,44 @@ fn box_deref_lval() { assert_eq!(x.get(), 1000); } +/// Test that a panic from a destructor does not leak the allocation. +#[test] +#[cfg_attr(not(panic = "unwind"), ignore = "test requires unwinding support")] +fn panic_no_leak() { + use std::alloc::{AllocError, Allocator, Global, Layout}; + use std::panic::{AssertUnwindSafe, catch_unwind}; + use std::ptr::NonNull; + + struct AllocCount(Cell<i32>); + unsafe impl Allocator for AllocCount { + fn allocate(&self, layout: Layout) -> Result<NonNull<[u8]>, AllocError> { + self.0.set(self.0.get() + 1); + Global.allocate(layout) + } + unsafe fn deallocate(&self, ptr: NonNull<u8>, layout: Layout) { + self.0.set(self.0.get() - 1); + unsafe { Global.deallocate(ptr, layout) } + } + } + + struct PanicOnDrop { + _data: u8, + } + impl Drop for PanicOnDrop { + fn drop(&mut self) { + panic!("PanicOnDrop"); + } + } + + let alloc = AllocCount(Cell::new(0)); + let b = Box::new_in(PanicOnDrop { _data: 42 }, &alloc); + assert_eq!(alloc.0.get(), 1); + + let panic_message = catch_unwind(AssertUnwindSafe(|| drop(b))).unwrap_err(); + assert_eq!(*panic_message.downcast_ref::<&'static str>().unwrap(), "PanicOnDrop"); + assert_eq!(alloc.0.get(), 0); +} + #[allow(unused)] pub struct ConstAllocator; diff --git a/library/alloc/tests/rc.rs b/library/alloc/tests/rc.rs index 29dbdcf225e..451765d7242 100644 --- a/library/alloc/tests/rc.rs +++ b/library/alloc/tests/rc.rs @@ -1,5 +1,5 @@ use std::any::Any; -use std::cell::RefCell; +use std::cell::{Cell, RefCell}; use std::iter::TrustedLen; use std::mem; use std::rc::{Rc, Weak}; @@ -206,6 +206,42 @@ fn weak_may_dangle() { // borrow might be used here, when `val` is dropped and runs the `Drop` code for type `std::rc::Weak` } +/// Test that a panic from a destructor does not leak the allocation. +#[test] +#[cfg_attr(not(panic = "unwind"), ignore = "test requires unwinding support")] +fn panic_no_leak() { + use std::alloc::{AllocError, Allocator, Global, Layout}; + use std::panic::{AssertUnwindSafe, catch_unwind}; + use std::ptr::NonNull; + + struct AllocCount(Cell<i32>); + unsafe impl Allocator for AllocCount { + fn allocate(&self, layout: Layout) -> Result<NonNull<[u8]>, AllocError> { + self.0.set(self.0.get() + 1); + Global.allocate(layout) + } + unsafe fn deallocate(&self, ptr: NonNull<u8>, layout: Layout) { + self.0.set(self.0.get() - 1); + unsafe { Global.deallocate(ptr, layout) } + } + } + + struct PanicOnDrop; + impl Drop for PanicOnDrop { + fn drop(&mut self) { + panic!("PanicOnDrop"); + } + } + + let alloc = AllocCount(Cell::new(0)); + let rc = Rc::new_in(PanicOnDrop, &alloc); + assert_eq!(alloc.0.get(), 1); + + let panic_message = catch_unwind(AssertUnwindSafe(|| drop(rc))).unwrap_err(); + assert_eq!(*panic_message.downcast_ref::<&'static str>().unwrap(), "PanicOnDrop"); + assert_eq!(alloc.0.get(), 0); +} + #[allow(unused)] mod pin_coerce_unsized { use alloc::rc::{Rc, UniqueRc}; diff --git a/library/core/benches/lib.rs b/library/core/benches/lib.rs index 3f1c58bbd72..32d15c386cb 100644 --- a/library/core/benches/lib.rs +++ b/library/core/benches/lib.rs @@ -8,7 +8,6 @@ #![feature(iter_array_chunks)] #![feature(iter_next_chunk)] #![feature(iter_advance_by)] -#![feature(isqrt)] extern crate test; diff --git a/library/core/src/cell.rs b/library/core/src/cell.rs index 0b106244793..7e6c042274d 100644 --- a/library/core/src/cell.rs +++ b/library/core/src/cell.rs @@ -304,6 +304,7 @@ pub use once::OnceCell; /// ``` /// /// See the [module-level documentation](self) for more. +#[cfg_attr(not(test), rustc_diagnostic_item = "Cell")] #[stable(feature = "rust1", since = "1.0.0")] #[repr(transparent)] #[rustc_pub_transparent] diff --git a/library/core/src/char/methods.rs b/library/core/src/char/methods.rs index 9c667edb476..206bbf5690e 100644 --- a/library/core/src/char/methods.rs +++ b/library/core/src/char/methods.rs @@ -320,8 +320,9 @@ impl char { /// '1'.is_digit(37); /// ``` #[stable(feature = "rust1", since = "1.0.0")] + #[rustc_const_unstable(feature = "const_char_is_digit", issue = "132241")] #[inline] - pub fn is_digit(self, radix: u32) -> bool { + pub const fn is_digit(self, radix: u32) -> bool { self.to_digit(radix).is_some() } diff --git a/library/core/src/ffi/c_str.rs b/library/core/src/ffi/c_str.rs index 0f4386190ee..93dd351b029 100644 --- a/library/core/src/ffi/c_str.rs +++ b/library/core/src/ffi/c_str.rs @@ -464,7 +464,9 @@ impl CStr { /// behavior when `ptr` is used inside the `unsafe` block: /// /// ```no_run - /// # #![allow(unused_must_use)] #![allow(temporary_cstring_as_ptr)] + /// # #![allow(unused_must_use)] + /// # #![cfg_attr(bootstrap, expect(temporary_cstring_as_ptr))] + /// # #![cfg_attr(not(bootstrap), expect(dangling_pointers_from_temporaries))] /// use std::ffi::CString; /// /// // Do not do this: diff --git a/library/core/src/lib.rs b/library/core/src/lib.rs index 9c3bf827438..115fdd7a140 100644 --- a/library/core/src/lib.rs +++ b/library/core/src/lib.rs @@ -134,6 +134,7 @@ #![feature(const_raw_ptr_comparison)] #![feature(const_size_of_val)] #![feature(const_size_of_val_raw)] +#![feature(const_sockaddr_setters)] #![feature(const_strict_overflow_ops)] #![feature(const_swap)] #![feature(const_try)] @@ -149,7 +150,6 @@ #![feature(ip)] #![feature(is_ascii_octdigit)] #![feature(is_val_statically_known)] -#![feature(isqrt)] #![feature(lazy_get)] #![feature(link_cfg)] #![feature(non_null_from_ref)] @@ -185,7 +185,9 @@ #![feature(cfg_target_has_atomic_equal_alignment)] #![feature(cfg_ub_checks)] #![feature(const_for)] +#![feature(const_is_char_boundary)] #![feature(const_precise_live_drops)] +#![feature(const_str_split_at)] #![feature(decl_macro)] #![feature(deprecated_suggestion)] #![feature(doc_cfg)] diff --git a/library/core/src/marker.rs b/library/core/src/marker.rs index 1237fc82a17..1c5c58d64a2 100644 --- a/library/core/src/marker.rs +++ b/library/core/src/marker.rs @@ -1063,9 +1063,10 @@ pub trait FnPtr: Copy + Clone { } /// Derive macro generating impls of traits related to smart pointers. -#[rustc_builtin_macro(SmartPointer, attributes(pointee))] +#[rustc_builtin_macro(CoercePointee, attributes(pointee))] #[allow_internal_unstable(dispatch_from_dyn, coerce_unsized, unsize)] -#[unstable(feature = "derive_smart_pointer", issue = "123430")] -pub macro SmartPointer($item:item) { +#[unstable(feature = "derive_coerce_pointee", issue = "123430")] +#[cfg(not(bootstrap))] +pub macro CoercePointee($item:item) { /* compiler built-in */ } diff --git a/library/core/src/net/socket_addr.rs b/library/core/src/net/socket_addr.rs index a46495add6a..9204797e6e1 100644 --- a/library/core/src/net/socket_addr.rs +++ b/library/core/src/net/socket_addr.rs @@ -198,9 +198,10 @@ impl SocketAddr { /// socket.set_ip(IpAddr::V4(Ipv4Addr::new(10, 10, 0, 1))); /// assert_eq!(socket.ip(), IpAddr::V4(Ipv4Addr::new(10, 10, 0, 1))); /// ``` - #[stable(feature = "sockaddr_setters", since = "1.9.0")] #[inline] - pub fn set_ip(&mut self, new_ip: IpAddr) { + #[stable(feature = "sockaddr_setters", since = "1.9.0")] + #[rustc_const_unstable(feature = "const_sockaddr_setters", issue = "131714")] + pub const fn set_ip(&mut self, new_ip: IpAddr) { // `match (*self, new_ip)` would have us mutate a copy of self only to throw it away. match (self, new_ip) { (&mut SocketAddr::V4(ref mut a), IpAddr::V4(new_ip)) => a.set_ip(new_ip), @@ -241,9 +242,10 @@ impl SocketAddr { /// socket.set_port(1025); /// assert_eq!(socket.port(), 1025); /// ``` - #[stable(feature = "sockaddr_setters", since = "1.9.0")] #[inline] - pub fn set_port(&mut self, new_port: u16) { + #[stable(feature = "sockaddr_setters", since = "1.9.0")] + #[rustc_const_unstable(feature = "const_sockaddr_setters", issue = "131714")] + pub const fn set_port(&mut self, new_port: u16) { match *self { SocketAddr::V4(ref mut a) => a.set_port(new_port), SocketAddr::V6(ref mut a) => a.set_port(new_port), @@ -346,9 +348,10 @@ impl SocketAddrV4 { /// socket.set_ip(Ipv4Addr::new(192, 168, 0, 1)); /// assert_eq!(socket.ip(), &Ipv4Addr::new(192, 168, 0, 1)); /// ``` - #[stable(feature = "sockaddr_setters", since = "1.9.0")] #[inline] - pub fn set_ip(&mut self, new_ip: Ipv4Addr) { + #[stable(feature = "sockaddr_setters", since = "1.9.0")] + #[rustc_const_unstable(feature = "const_sockaddr_setters", issue = "131714")] + pub const fn set_ip(&mut self, new_ip: Ipv4Addr) { self.ip = new_ip; } @@ -381,9 +384,10 @@ impl SocketAddrV4 { /// socket.set_port(4242); /// assert_eq!(socket.port(), 4242); /// ``` - #[stable(feature = "sockaddr_setters", since = "1.9.0")] #[inline] - pub fn set_port(&mut self, new_port: u16) { + #[stable(feature = "sockaddr_setters", since = "1.9.0")] + #[rustc_const_unstable(feature = "const_sockaddr_setters", issue = "131714")] + pub const fn set_port(&mut self, new_port: u16) { self.port = new_port; } } @@ -442,9 +446,10 @@ impl SocketAddrV6 { /// socket.set_ip(Ipv6Addr::new(76, 45, 0, 0, 0, 0, 0, 0)); /// assert_eq!(socket.ip(), &Ipv6Addr::new(76, 45, 0, 0, 0, 0, 0, 0)); /// ``` - #[stable(feature = "sockaddr_setters", since = "1.9.0")] #[inline] - pub fn set_ip(&mut self, new_ip: Ipv6Addr) { + #[stable(feature = "sockaddr_setters", since = "1.9.0")] + #[rustc_const_unstable(feature = "const_sockaddr_setters", issue = "131714")] + pub const fn set_ip(&mut self, new_ip: Ipv6Addr) { self.ip = new_ip; } @@ -477,9 +482,10 @@ impl SocketAddrV6 { /// socket.set_port(4242); /// assert_eq!(socket.port(), 4242); /// ``` - #[stable(feature = "sockaddr_setters", since = "1.9.0")] #[inline] - pub fn set_port(&mut self, new_port: u16) { + #[stable(feature = "sockaddr_setters", since = "1.9.0")] + #[rustc_const_unstable(feature = "const_sockaddr_setters", issue = "131714")] + pub const fn set_port(&mut self, new_port: u16) { self.port = new_port; } @@ -524,9 +530,10 @@ impl SocketAddrV6 { /// socket.set_flowinfo(56); /// assert_eq!(socket.flowinfo(), 56); /// ``` - #[stable(feature = "sockaddr_setters", since = "1.9.0")] #[inline] - pub fn set_flowinfo(&mut self, new_flowinfo: u32) { + #[stable(feature = "sockaddr_setters", since = "1.9.0")] + #[rustc_const_unstable(feature = "const_sockaddr_setters", issue = "131714")] + pub const fn set_flowinfo(&mut self, new_flowinfo: u32) { self.flowinfo = new_flowinfo; } @@ -566,9 +573,10 @@ impl SocketAddrV6 { /// socket.set_scope_id(42); /// assert_eq!(socket.scope_id(), 42); /// ``` - #[stable(feature = "sockaddr_setters", since = "1.9.0")] #[inline] - pub fn set_scope_id(&mut self, new_scope_id: u32) { + #[stable(feature = "sockaddr_setters", since = "1.9.0")] + #[rustc_const_unstable(feature = "const_sockaddr_setters", issue = "131714")] + pub const fn set_scope_id(&mut self, new_scope_id: u32) { self.scope_id = new_scope_id; } } diff --git a/library/core/src/num/int_macros.rs b/library/core/src/num/int_macros.rs index 1d640ea74c4..3a9060df286 100644 --- a/library/core/src/num/int_macros.rs +++ b/library/core/src/num/int_macros.rs @@ -1629,11 +1629,10 @@ macro_rules! int_impl { /// /// Basic usage: /// ``` - /// #![feature(isqrt)] #[doc = concat!("assert_eq!(10", stringify!($SelfT), ".checked_isqrt(), Some(3));")] /// ``` - #[unstable(feature = "isqrt", issue = "116226")] - #[rustc_const_unstable(feature = "isqrt", issue = "116226")] + #[stable(feature = "isqrt", since = "CURRENT_RUSTC_VERSION")] + #[rustc_const_stable(feature = "isqrt", since = "CURRENT_RUSTC_VERSION")] #[must_use = "this returns the result of the operation, \ without modifying the original"] #[inline] @@ -2880,11 +2879,10 @@ macro_rules! int_impl { /// /// Basic usage: /// ``` - /// #![feature(isqrt)] #[doc = concat!("assert_eq!(10", stringify!($SelfT), ".isqrt(), 3);")] /// ``` - #[unstable(feature = "isqrt", issue = "116226")] - #[rustc_const_unstable(feature = "isqrt", issue = "116226")] + #[stable(feature = "isqrt", since = "CURRENT_RUSTC_VERSION")] + #[rustc_const_stable(feature = "isqrt", since = "CURRENT_RUSTC_VERSION")] #[must_use = "this returns the result of the operation, \ without modifying the original"] #[inline] @@ -3181,44 +3179,6 @@ macro_rules! int_impl { } } - /// Calculates the middle point of `self` and `rhs`. - /// - /// `midpoint(a, b)` is `(a + b) >> 1` as if it were performed in a - /// sufficiently-large signed integral type. This implies that the result is - /// always rounded towards negative infinity and that no overflow will ever occur. - /// - /// # Examples - /// - /// ``` - /// #![feature(num_midpoint)] - #[doc = concat!("assert_eq!(0", stringify!($SelfT), ".midpoint(4), 2);")] - #[doc = concat!("assert_eq!(0", stringify!($SelfT), ".midpoint(-1), -1);")] - #[doc = concat!("assert_eq!((-1", stringify!($SelfT), ").midpoint(0), -1);")] - /// ``` - #[unstable(feature = "num_midpoint", issue = "110840")] - #[rustc_const_unstable(feature = "const_num_midpoint", issue = "110840")] - #[rustc_allow_const_fn_unstable(const_num_midpoint)] - #[must_use = "this returns the result of the operation, \ - without modifying the original"] - #[inline] - pub const fn midpoint(self, rhs: Self) -> Self { - const U: $UnsignedT = <$SelfT>::MIN.unsigned_abs(); - - // Map an $SelfT to an $UnsignedT - // ex: i8 [-128; 127] to [0; 255] - const fn map(a: $SelfT) -> $UnsignedT { - (a as $UnsignedT) ^ U - } - - // Map an $UnsignedT to an $SelfT - // ex: u8 [0; 255] to [-128; 127] - const fn demap(a: $UnsignedT) -> $SelfT { - (a ^ U) as $SelfT - } - - demap(<$UnsignedT>::midpoint(map(self), map(rhs))) - } - /// Returns the logarithm of the number with respect to an arbitrary base, /// rounded down. /// diff --git a/library/core/src/num/mod.rs b/library/core/src/num/mod.rs index f95cfd33ae5..6a0b40ff517 100644 --- a/library/core/src/num/mod.rs +++ b/library/core/src/num/mod.rs @@ -124,6 +124,37 @@ macro_rules! midpoint_impl { ((self ^ rhs) >> 1) + (self & rhs) } }; + ($SelfT:ty, signed) => { + /// Calculates the middle point of `self` and `rhs`. + /// + /// `midpoint(a, b)` is `(a + b) / 2` as if it were performed in a + /// sufficiently-large signed integral type. This implies that the result is + /// always rounded towards zero and that no overflow will ever occur. + /// + /// # Examples + /// + /// ``` + /// #![feature(num_midpoint)] + #[doc = concat!("assert_eq!(0", stringify!($SelfT), ".midpoint(4), 2);")] + #[doc = concat!("assert_eq!((-1", stringify!($SelfT), ").midpoint(2), 0);")] + #[doc = concat!("assert_eq!((-7", stringify!($SelfT), ").midpoint(0), -3);")] + #[doc = concat!("assert_eq!(0", stringify!($SelfT), ".midpoint(-7), -3);")] + #[doc = concat!("assert_eq!(0", stringify!($SelfT), ".midpoint(7), 3);")] + /// ``` + #[unstable(feature = "num_midpoint", issue = "110840")] + #[rustc_const_unstable(feature = "const_num_midpoint", issue = "110840")] + #[must_use = "this returns the result of the operation, \ + without modifying the original"] + #[inline] + pub const fn midpoint(self, rhs: Self) -> Self { + // Use the well known branchless algorithm from Hacker's Delight to compute + // `(a + b) / 2` without overflowing: `((a ^ b) >> 1) + (a & b)`. + let t = ((self ^ rhs) >> 1) + (self & rhs); + // Except that it fails for integers whose sum is an odd negative number as + // their floor is one less than their average. So we adjust the result. + t + (if t < 0 { 1 } else { 0 } & (self ^ rhs)) + } + }; ($SelfT:ty, $WideT:ty, unsigned) => { /// Calculates the middle point of `self` and `rhs`. /// @@ -147,6 +178,32 @@ macro_rules! midpoint_impl { ((self as $WideT + rhs as $WideT) / 2) as $SelfT } }; + ($SelfT:ty, $WideT:ty, signed) => { + /// Calculates the middle point of `self` and `rhs`. + /// + /// `midpoint(a, b)` is `(a + b) / 2` as if it were performed in a + /// sufficiently-large signed integral type. This implies that the result is + /// always rounded towards zero and that no overflow will ever occur. + /// + /// # Examples + /// + /// ``` + /// #![feature(num_midpoint)] + #[doc = concat!("assert_eq!(0", stringify!($SelfT), ".midpoint(4), 2);")] + #[doc = concat!("assert_eq!((-1", stringify!($SelfT), ").midpoint(2), 0);")] + #[doc = concat!("assert_eq!((-7", stringify!($SelfT), ").midpoint(0), -3);")] + #[doc = concat!("assert_eq!(0", stringify!($SelfT), ".midpoint(-7), -3);")] + #[doc = concat!("assert_eq!(0", stringify!($SelfT), ".midpoint(7), 3);")] + /// ``` + #[unstable(feature = "num_midpoint", issue = "110840")] + #[rustc_const_unstable(feature = "const_num_midpoint", issue = "110840")] + #[must_use = "this returns the result of the operation, \ + without modifying the original"] + #[inline] + pub const fn midpoint(self, rhs: $SelfT) -> $SelfT { + ((self as $WideT + rhs as $WideT) / 2) as $SelfT + } + }; } macro_rules! widening_impl { @@ -300,6 +357,7 @@ impl i8 { from_xe_bytes_doc = "", bound_condition = "", } + midpoint_impl! { i8, i16, signed } } impl i16 { @@ -323,6 +381,7 @@ impl i16 { from_xe_bytes_doc = "", bound_condition = "", } + midpoint_impl! { i16, i32, signed } } impl i32 { @@ -346,6 +405,7 @@ impl i32 { from_xe_bytes_doc = "", bound_condition = "", } + midpoint_impl! { i32, i64, signed } } impl i64 { @@ -369,6 +429,7 @@ impl i64 { from_xe_bytes_doc = "", bound_condition = "", } + midpoint_impl! { i64, signed } } impl i128 { @@ -394,6 +455,7 @@ impl i128 { from_xe_bytes_doc = "", bound_condition = "", } + midpoint_impl! { i128, signed } } #[cfg(target_pointer_width = "16")] @@ -418,6 +480,7 @@ impl isize { from_xe_bytes_doc = usize_isize_from_xe_bytes_doc!(), bound_condition = " on 16-bit targets", } + midpoint_impl! { isize, i32, signed } } #[cfg(target_pointer_width = "32")] @@ -442,6 +505,7 @@ impl isize { from_xe_bytes_doc = usize_isize_from_xe_bytes_doc!(), bound_condition = " on 32-bit targets", } + midpoint_impl! { isize, i64, signed } } #[cfg(target_pointer_width = "64")] @@ -466,6 +530,7 @@ impl isize { from_xe_bytes_doc = usize_isize_from_xe_bytes_doc!(), bound_condition = " on 64-bit targets", } + midpoint_impl! { isize, signed } } /// If the 6th bit is set ascii is lower case. diff --git a/library/core/src/num/nonzero.rs b/library/core/src/num/nonzero.rs index fdb84827e27..f6e271954fe 100644 --- a/library/core/src/num/nonzero.rs +++ b/library/core/src/num/nonzero.rs @@ -1527,7 +1527,6 @@ macro_rules! nonzero_integer_signedness_dependent_methods { /// /// Basic usage: /// ``` - /// #![feature(isqrt)] /// # use std::num::NonZero; /// # /// # fn main() { test().unwrap(); } @@ -1539,8 +1538,8 @@ macro_rules! nonzero_integer_signedness_dependent_methods { /// # Some(()) /// # } /// ``` - #[unstable(feature = "isqrt", issue = "116226")] - #[rustc_const_unstable(feature = "isqrt", issue = "116226")] + #[stable(feature = "isqrt", since = "CURRENT_RUSTC_VERSION")] + #[rustc_const_stable(feature = "isqrt", since = "CURRENT_RUSTC_VERSION")] #[must_use = "this returns the result of the operation, \ without modifying the original"] #[inline] diff --git a/library/core/src/num/uint_macros.rs b/library/core/src/num/uint_macros.rs index 9c5fe563d93..eb4ea4b3c40 100644 --- a/library/core/src/num/uint_macros.rs +++ b/library/core/src/num/uint_macros.rs @@ -2753,11 +2753,10 @@ macro_rules! uint_impl { /// /// Basic usage: /// ``` - /// #![feature(isqrt)] #[doc = concat!("assert_eq!(10", stringify!($SelfT), ".isqrt(), 3);")] /// ``` - #[unstable(feature = "isqrt", issue = "116226")] - #[rustc_const_unstable(feature = "isqrt", issue = "116226")] + #[stable(feature = "isqrt", since = "CURRENT_RUSTC_VERSION")] + #[rustc_const_stable(feature = "isqrt", since = "CURRENT_RUSTC_VERSION")] #[must_use = "this returns the result of the operation, \ without modifying the original"] #[inline] diff --git a/library/core/src/primitive_docs.rs b/library/core/src/primitive_docs.rs index bf9bfd84b56..4a6fca5085c 100644 --- a/library/core/src/primitive_docs.rs +++ b/library/core/src/primitive_docs.rs @@ -1612,6 +1612,9 @@ mod prim_ref {} /// pointers, make your type [`Option<fn()>`](core::option#options-and-pointers-nullable-pointers) /// with your required signature. /// +/// Note that FFI requires additional care to ensure that the ABI for both sides of the call match. +/// The exact requirements are not currently documented. +/// /// ### Safety /// /// Plain function pointers are obtained by casting either plain functions, or closures that don't @@ -1750,8 +1753,13 @@ mod prim_ref {} /// is also used rarely. So, most likely you do not have to worry about ABI compatibility. /// /// But assuming such circumstances, what are the rules? For this section, we are only considering -/// the ABI of direct Rust-to-Rust calls, not linking in general -- once functions are imported via -/// `extern` blocks, there are more things to consider that we do not go into here. +/// the ABI of direct Rust-to-Rust calls (with both definition and callsite visible to the +/// Rust compiler), not linking in general -- once functions are imported via `extern` blocks, there +/// are more things to consider that we do not go into here. Note that this also applies to +/// passing/calling functions across language boundaries via function pointers. +/// +/// **Nothing in this section should be taken as a guarantee for non-Rust-to-Rust calls, even with +/// types from `core::ffi` or `libc`**. /// /// For two signatures to be considered *ABI-compatible*, they must use a compatible ABI string, /// must take the same number of arguments, the individual argument types and the return types must diff --git a/library/core/src/str/mod.rs b/library/core/src/str/mod.rs index 89addc4cb74..9ef99e9dae8 100644 --- a/library/core/src/str/mod.rs +++ b/library/core/src/str/mod.rs @@ -185,8 +185,9 @@ impl str { /// ``` #[must_use] #[stable(feature = "is_char_boundary", since = "1.9.0")] + #[rustc_const_unstable(feature = "const_is_char_boundary", issue = "131516")] #[inline] - pub fn is_char_boundary(&self, index: usize) -> bool { + pub const fn is_char_boundary(&self, index: usize) -> bool { // 0 is always ok. // Test for 0 explicitly so that it can optimize out the check // easily and skip reading string data for that case. @@ -195,8 +196,8 @@ impl str { return true; } - match self.as_bytes().get(index) { - // For `None` we have two options: + if index >= self.len() { + // For `true` we have two options: // // - index == self.len() // Empty strings are valid, so return true @@ -205,9 +206,9 @@ impl str { // // The check is placed exactly here, because it improves generated // code on higher opt-levels. See PR #84751 for more details. - None => index == self.len(), - - Some(&b) => b.is_utf8_char_boundary(), + index == self.len() + } else { + self.as_bytes()[index].is_utf8_char_boundary() } } @@ -637,7 +638,8 @@ impl str { #[inline] #[must_use] #[stable(feature = "str_split_at", since = "1.4.0")] - pub fn split_at(&self, mid: usize) -> (&str, &str) { + #[rustc_const_unstable(feature = "const_str_split_at", issue = "131518")] + pub const fn split_at(&self, mid: usize) -> (&str, &str) { match self.split_at_checked(mid) { None => slice_error_fail(self, 0, mid), Some(pair) => pair, @@ -677,7 +679,8 @@ impl str { #[inline] #[must_use] #[stable(feature = "str_split_at", since = "1.4.0")] - pub fn split_at_mut(&mut self, mid: usize) -> (&mut str, &mut str) { + #[rustc_const_unstable(feature = "const_str_split_at", issue = "131518")] + pub const fn split_at_mut(&mut self, mid: usize) -> (&mut str, &mut str) { // is_char_boundary checks that the index is in [0, .len()] if self.is_char_boundary(mid) { // SAFETY: just checked that `mid` is on a char boundary. @@ -716,11 +719,12 @@ impl str { #[inline] #[must_use] #[stable(feature = "split_at_checked", since = "1.80.0")] - pub fn split_at_checked(&self, mid: usize) -> Option<(&str, &str)> { + #[rustc_const_unstable(feature = "const_str_split_at", issue = "131518")] + pub const fn split_at_checked(&self, mid: usize) -> Option<(&str, &str)> { // is_char_boundary checks that the index is in [0, .len()] if self.is_char_boundary(mid) { // SAFETY: just checked that `mid` is on a char boundary. - Some(unsafe { (self.get_unchecked(0..mid), self.get_unchecked(mid..self.len())) }) + Some(unsafe { self.split_at_unchecked(mid) }) } else { None } @@ -756,7 +760,9 @@ impl str { #[inline] #[must_use] #[stable(feature = "split_at_checked", since = "1.80.0")] - pub fn split_at_mut_checked(&mut self, mid: usize) -> Option<(&mut str, &mut str)> { + #[rustc_const_unstable(feature = "const_str_split_at", issue = "131518")] + #[rustc_allow_const_fn_unstable(const_is_char_boundary)] + pub const fn split_at_mut_checked(&mut self, mid: usize) -> Option<(&mut str, &mut str)> { // is_char_boundary checks that the index is in [0, .len()] if self.is_char_boundary(mid) { // SAFETY: just checked that `mid` is on a char boundary. @@ -772,7 +778,25 @@ impl str { /// /// The caller must ensure that `mid` is a valid byte offset from the start /// of the string and falls on the boundary of a UTF-8 code point. - unsafe fn split_at_mut_unchecked(&mut self, mid: usize) -> (&mut str, &mut str) { + const unsafe fn split_at_unchecked(&self, mid: usize) -> (&str, &str) { + let len = self.len(); + let ptr = self.as_ptr(); + // SAFETY: caller guarantees `mid` is on a char boundary. + unsafe { + ( + from_utf8_unchecked(slice::from_raw_parts(ptr, mid)), + from_utf8_unchecked(slice::from_raw_parts(ptr.add(mid), len - mid)), + ) + } + } + + /// Divides one string slice into two at an index. + /// + /// # Safety + /// + /// The caller must ensure that `mid` is a valid byte offset from the start + /// of the string and falls on the boundary of a UTF-8 code point. + const unsafe fn split_at_mut_unchecked(&mut self, mid: usize) -> (&mut str, &mut str) { let len = self.len(); let ptr = self.as_mut_ptr(); // SAFETY: caller guarantees `mid` is on a char boundary. diff --git a/library/core/tests/lib.rs b/library/core/tests/lib.rs index 8c898718865..2a9f1660a62 100644 --- a/library/core/tests/lib.rs +++ b/library/core/tests/lib.rs @@ -53,7 +53,6 @@ #![feature(ip)] #![feature(ip_from)] #![feature(is_ascii_octdigit)] -#![feature(isqrt)] #![feature(iter_advance_by)] #![feature(iter_array_chunks)] #![feature(iter_chain)] diff --git a/library/core/tests/num/int_macros.rs b/library/core/tests/num/int_macros.rs index 1608080d6b6..474d57049ab 100644 --- a/library/core/tests/num/int_macros.rs +++ b/library/core/tests/num/int_macros.rs @@ -369,8 +369,8 @@ macro_rules! int_module { assert_eq_const_safe!(<$T>::midpoint(3, 4), 3); assert_eq_const_safe!(<$T>::midpoint(4, 3), 3); - assert_eq_const_safe!(<$T>::midpoint(<$T>::MIN, <$T>::MAX), -1); - assert_eq_const_safe!(<$T>::midpoint(<$T>::MAX, <$T>::MIN), -1); + assert_eq_const_safe!(<$T>::midpoint(<$T>::MIN, <$T>::MAX), 0); + assert_eq_const_safe!(<$T>::midpoint(<$T>::MAX, <$T>::MIN), 0); assert_eq_const_safe!(<$T>::midpoint(<$T>::MIN, <$T>::MIN), <$T>::MIN); assert_eq_const_safe!(<$T>::midpoint(<$T>::MAX, <$T>::MAX), <$T>::MAX); diff --git a/library/core/tests/num/midpoint.rs b/library/core/tests/num/midpoint.rs new file mode 100644 index 00000000000..71e98006784 --- /dev/null +++ b/library/core/tests/num/midpoint.rs @@ -0,0 +1,54 @@ +//! Test the following expectations: +//! - midpoint(a, b) == (a + b) / 2 +//! - midpoint(a, b) == midpoint(b, a) +//! - midpoint(-a, -b) == -midpoint(a, b) + +#[test] +#[cfg(not(miri))] +fn midpoint_obvious_impl_i8() { + for a in i8::MIN..=i8::MAX { + for b in i8::MIN..=i8::MAX { + assert_eq!(i8::midpoint(a, b), ((a as i16 + b as i16) / 2) as i8); + } + } +} + +#[test] +#[cfg(not(miri))] +fn midpoint_obvious_impl_u8() { + for a in u8::MIN..=u8::MAX { + for b in u8::MIN..=u8::MAX { + assert_eq!(u8::midpoint(a, b), ((a as u16 + b as u16) / 2) as u8); + } + } +} + +#[test] +#[cfg(not(miri))] +fn midpoint_order_expectation_i8() { + for a in i8::MIN..=i8::MAX { + for b in i8::MIN..=i8::MAX { + assert_eq!(i8::midpoint(a, b), i8::midpoint(b, a)); + } + } +} + +#[test] +#[cfg(not(miri))] +fn midpoint_order_expectation_u8() { + for a in u8::MIN..=u8::MAX { + for b in u8::MIN..=u8::MAX { + assert_eq!(u8::midpoint(a, b), u8::midpoint(b, a)); + } + } +} + +#[test] +#[cfg(not(miri))] +fn midpoint_negative_expectation() { + for a in 0..=i8::MAX { + for b in 0..=i8::MAX { + assert_eq!(i8::midpoint(-a, -b), -i8::midpoint(a, b)); + } + } +} diff --git a/library/core/tests/num/mod.rs b/library/core/tests/num/mod.rs index 6da9b9a1329..0add9a01e68 100644 --- a/library/core/tests/num/mod.rs +++ b/library/core/tests/num/mod.rs @@ -28,6 +28,7 @@ mod dec2flt; mod flt2dec; mod int_log; mod int_sqrt; +mod midpoint; mod ops; mod wrapping; diff --git a/library/proc_macro/src/lib.rs b/library/proc_macro/src/lib.rs index ae47bb7adf4..15770248b31 100644 --- a/library/proc_macro/src/lib.rs +++ b/library/proc_macro/src/lib.rs @@ -32,6 +32,7 @@ #![feature(restricted_std)] #![feature(rustc_attrs)] #![feature(min_specialization)] +#![feature(extend_one)] #![recursion_limit = "256"] #![allow(internal_features)] #![deny(ffi_unwind_calls)] @@ -43,6 +44,7 @@ pub mod bridge; mod diagnostic; mod escape; +mod to_tokens; use std::ffi::CStr; use std::ops::{Range, RangeBounds}; @@ -52,6 +54,8 @@ use std::{error, fmt}; #[unstable(feature = "proc_macro_diagnostic", issue = "54140")] pub use diagnostic::{Diagnostic, Level, MultiSpan}; +#[unstable(feature = "proc_macro_totokens", issue = "130977")] +pub use to_tokens::ToTokens; use crate::escape::{EscapeOptions, escape_bytes}; diff --git a/library/proc_macro/src/to_tokens.rs b/library/proc_macro/src/to_tokens.rs new file mode 100644 index 00000000000..8f697b416d5 --- /dev/null +++ b/library/proc_macro/src/to_tokens.rs @@ -0,0 +1,310 @@ +use std::borrow::Cow; +use std::ffi::{CStr, CString}; +use std::rc::Rc; + +use crate::{ConcatTreesHelper, Group, Ident, Literal, Punct, Span, TokenStream, TokenTree}; + +/// Types that can be interpolated inside a [`quote!`] invocation. +/// +/// [`quote!`]: crate::quote! +#[unstable(feature = "proc_macro_totokens", issue = "130977")] +pub trait ToTokens { + /// Write `self` to the given `TokenStream`. + /// + /// # Example + /// + /// Example implementation for a struct representing Rust paths like + /// `std::cmp::PartialEq`: + /// + /// ``` + /// #![feature(proc_macro_totokens)] + /// + /// use std::iter; + /// use proc_macro::{Spacing, Punct, TokenStream, TokenTree, ToTokens}; + /// + /// pub struct Path { + /// pub global: bool, + /// pub segments: Vec<PathSegment>, + /// } + /// + /// impl ToTokens for Path { + /// fn to_tokens(&self, tokens: &mut TokenStream) { + /// for (i, segment) in self.segments.iter().enumerate() { + /// if i > 0 || self.global { + /// // Double colon `::` + /// tokens.extend(iter::once(TokenTree::from(Punct::new(':', Spacing::Joint)))); + /// tokens.extend(iter::once(TokenTree::from(Punct::new(':', Spacing::Alone)))); + /// } + /// segment.to_tokens(tokens); + /// } + /// } + /// } + /// # + /// # pub struct PathSegment; + /// # + /// # impl ToTokens for PathSegment { + /// # fn to_tokens(&self, tokens: &mut TokenStream) { + /// # unimplemented!() + /// # } + /// # } + /// ``` + fn to_tokens(&self, tokens: &mut TokenStream); + + /// Convert `self` directly into a `TokenStream` object. + /// + /// This method is implicitly implemented using `to_tokens`, and acts as a + /// convenience method for consumers of the `ToTokens` trait. + fn to_token_stream(&self) -> TokenStream { + let mut tokens = TokenStream::new(); + self.to_tokens(&mut tokens); + tokens + } + + /// Convert `self` directly into a `TokenStream` object. + /// + /// This method is implicitly implemented using `to_tokens`, and acts as a + /// convenience method for consumers of the `ToTokens` trait. + fn into_token_stream(self) -> TokenStream + where + Self: Sized, + { + self.to_token_stream() + } +} + +#[unstable(feature = "proc_macro_totokens", issue = "130977")] +impl ToTokens for TokenTree { + fn to_tokens(&self, tokens: &mut TokenStream) { + tokens.extend_one(self.clone()); + } + + fn into_token_stream(self) -> TokenStream { + let mut builder = ConcatTreesHelper::new(1); + builder.push(self); + builder.build() + } +} + +#[unstable(feature = "proc_macro_totokens", issue = "130977")] +impl ToTokens for TokenStream { + fn to_tokens(&self, tokens: &mut TokenStream) { + tokens.extend(self.clone()); + } + + fn into_token_stream(self) -> TokenStream { + self + } +} + +#[unstable(feature = "proc_macro_totokens", issue = "130977")] +impl ToTokens for Literal { + fn to_tokens(&self, tokens: &mut TokenStream) { + tokens.extend_one(TokenTree::from(self.clone())); + } +} + +#[unstable(feature = "proc_macro_totokens", issue = "130977")] +impl ToTokens for Ident { + fn to_tokens(&self, tokens: &mut TokenStream) { + tokens.extend_one(TokenTree::from(self.clone())); + } +} + +#[unstable(feature = "proc_macro_totokens", issue = "130977")] +impl ToTokens for Punct { + fn to_tokens(&self, tokens: &mut TokenStream) { + tokens.extend_one(TokenTree::from(self.clone())); + } +} + +#[unstable(feature = "proc_macro_totokens", issue = "130977")] +impl ToTokens for Group { + fn to_tokens(&self, tokens: &mut TokenStream) { + tokens.extend_one(TokenTree::from(self.clone())); + } +} + +#[unstable(feature = "proc_macro_totokens", issue = "130977")] +impl<T: ToTokens + ?Sized> ToTokens for &T { + fn to_tokens(&self, tokens: &mut TokenStream) { + (**self).to_tokens(tokens) + } +} + +#[unstable(feature = "proc_macro_totokens", issue = "130977")] +impl<T: ToTokens + ?Sized> ToTokens for &mut T { + fn to_tokens(&self, tokens: &mut TokenStream) { + (**self).to_tokens(tokens) + } +} + +#[unstable(feature = "proc_macro_totokens", issue = "130977")] +impl<T: ToTokens + ?Sized> ToTokens for Box<T> { + fn to_tokens(&self, tokens: &mut TokenStream) { + (**self).to_tokens(tokens) + } +} + +#[unstable(feature = "proc_macro_totokens", issue = "130977")] +impl<T: ToTokens + ?Sized> ToTokens for Rc<T> { + fn to_tokens(&self, tokens: &mut TokenStream) { + (**self).to_tokens(tokens) + } +} + +#[unstable(feature = "proc_macro_totokens", issue = "130977")] +impl<T: ToTokens + ToOwned + ?Sized> ToTokens for Cow<'_, T> { + fn to_tokens(&self, tokens: &mut TokenStream) { + (**self).to_tokens(tokens) + } +} + +#[unstable(feature = "proc_macro_totokens", issue = "130977")] +impl<T: ToTokens> ToTokens for Option<T> { + fn to_tokens(&self, tokens: &mut TokenStream) { + if let Some(t) = self { + t.to_tokens(tokens); + } + } +} + +#[unstable(feature = "proc_macro_totokens", issue = "130977")] +impl ToTokens for u8 { + fn to_tokens(&self, tokens: &mut TokenStream) { + Literal::u8_suffixed(*self).to_tokens(tokens) + } +} + +#[unstable(feature = "proc_macro_totokens", issue = "130977")] +impl ToTokens for u16 { + fn to_tokens(&self, tokens: &mut TokenStream) { + Literal::u16_suffixed(*self).to_tokens(tokens) + } +} + +#[unstable(feature = "proc_macro_totokens", issue = "130977")] +impl ToTokens for u32 { + fn to_tokens(&self, tokens: &mut TokenStream) { + Literal::u32_suffixed(*self).to_tokens(tokens) + } +} + +#[unstable(feature = "proc_macro_totokens", issue = "130977")] +impl ToTokens for u64 { + fn to_tokens(&self, tokens: &mut TokenStream) { + Literal::u64_suffixed(*self).to_tokens(tokens) + } +} + +#[unstable(feature = "proc_macro_totokens", issue = "130977")] +impl ToTokens for u128 { + fn to_tokens(&self, tokens: &mut TokenStream) { + Literal::u128_suffixed(*self).to_tokens(tokens) + } +} + +#[unstable(feature = "proc_macro_totokens", issue = "130977")] +impl ToTokens for i8 { + fn to_tokens(&self, tokens: &mut TokenStream) { + Literal::i8_suffixed(*self).to_tokens(tokens) + } +} + +#[unstable(feature = "proc_macro_totokens", issue = "130977")] +impl ToTokens for i16 { + fn to_tokens(&self, tokens: &mut TokenStream) { + Literal::i16_suffixed(*self).to_tokens(tokens) + } +} + +#[unstable(feature = "proc_macro_totokens", issue = "130977")] +impl ToTokens for i32 { + fn to_tokens(&self, tokens: &mut TokenStream) { + Literal::i32_suffixed(*self).to_tokens(tokens) + } +} + +#[unstable(feature = "proc_macro_totokens", issue = "130977")] +impl ToTokens for i64 { + fn to_tokens(&self, tokens: &mut TokenStream) { + Literal::i64_suffixed(*self).to_tokens(tokens) + } +} + +#[unstable(feature = "proc_macro_totokens", issue = "130977")] +impl ToTokens for i128 { + fn to_tokens(&self, tokens: &mut TokenStream) { + Literal::i128_suffixed(*self).to_tokens(tokens) + } +} + +#[unstable(feature = "proc_macro_totokens", issue = "130977")] +impl ToTokens for f32 { + fn to_tokens(&self, tokens: &mut TokenStream) { + Literal::f32_suffixed(*self).to_tokens(tokens) + } +} + +#[unstable(feature = "proc_macro_totokens", issue = "130977")] +impl ToTokens for f64 { + fn to_tokens(&self, tokens: &mut TokenStream) { + Literal::f64_suffixed(*self).to_tokens(tokens) + } +} + +#[unstable(feature = "proc_macro_totokens", issue = "130977")] +impl ToTokens for usize { + fn to_tokens(&self, tokens: &mut TokenStream) { + Literal::usize_suffixed(*self).to_tokens(tokens) + } +} + +#[unstable(feature = "proc_macro_totokens", issue = "130977")] +impl ToTokens for isize { + fn to_tokens(&self, tokens: &mut TokenStream) { + Literal::isize_suffixed(*self).to_tokens(tokens) + } +} + +#[unstable(feature = "proc_macro_totokens", issue = "130977")] +impl ToTokens for bool { + fn to_tokens(&self, tokens: &mut TokenStream) { + let word = if *self { "true" } else { "false" }; + Ident::new(word, Span::call_site()).to_tokens(tokens) + } +} + +#[unstable(feature = "proc_macro_totokens", issue = "130977")] +impl ToTokens for char { + fn to_tokens(&self, tokens: &mut TokenStream) { + Literal::character(*self).to_tokens(tokens) + } +} + +#[unstable(feature = "proc_macro_totokens", issue = "130977")] +impl ToTokens for str { + fn to_tokens(&self, tokens: &mut TokenStream) { + Literal::string(self).to_tokens(tokens) + } +} + +#[unstable(feature = "proc_macro_totokens", issue = "130977")] +impl ToTokens for String { + fn to_tokens(&self, tokens: &mut TokenStream) { + Literal::string(self).to_tokens(tokens) + } +} + +#[unstable(feature = "proc_macro_totokens", issue = "130977")] +impl ToTokens for CStr { + fn to_tokens(&self, tokens: &mut TokenStream) { + Literal::c_string(self).to_tokens(tokens) + } +} + +#[unstable(feature = "proc_macro_totokens", issue = "130977")] +impl ToTokens for CString { + fn to_tokens(&self, tokens: &mut TokenStream) { + Literal::c_string(self).to_tokens(tokens) + } +} diff --git a/library/std/src/fs.rs b/library/std/src/fs.rs index 8a0d2a7f5cf..3079c8b1d90 100644 --- a/library/std/src/fs.rs +++ b/library/std/src/fs.rs @@ -1197,7 +1197,7 @@ impl OpenOptions { /// Sets the option for truncating a previous file. /// - /// If a file is successfully opened with this option set it will truncate + /// If a file is successfully opened with this option set to true, it will truncate /// the file to 0 length if it already exists. /// /// The file must be opened with write access for truncate to work. diff --git a/library/std/src/sys/sync/condvar/no_threads.rs b/library/std/src/sys/sync/condvar/no_threads.rs index 36b89c5f5be..2a67ed766aa 100644 --- a/library/std/src/sys/sync/condvar/no_threads.rs +++ b/library/std/src/sys/sync/condvar/no_threads.rs @@ -5,7 +5,7 @@ pub struct Condvar {} impl Condvar { #[inline] - #[rustc_const_stable(feature = "const_locks", since = "1.63.0")] + #[cfg_attr(bootstrap, rustc_const_stable(feature = "const_locks", since = "1.63.0"))] pub const fn new() -> Condvar { Condvar {} } diff --git a/library/std/src/sys/sync/condvar/xous.rs b/library/std/src/sys/sync/condvar/xous.rs index cb55a3e3369..b9e5f47abfc 100644 --- a/library/std/src/sys/sync/condvar/xous.rs +++ b/library/std/src/sys/sync/condvar/xous.rs @@ -20,7 +20,6 @@ unsafe impl Sync for Condvar {} impl Condvar { #[inline] - #[rustc_const_stable(feature = "const_locks", since = "1.63.0")] pub const fn new() -> Condvar { Condvar { counter: AtomicUsize::new(0), timed_out: AtomicUsize::new(0) } } diff --git a/library/std/src/sys/sync/mutex/no_threads.rs b/library/std/src/sys/sync/mutex/no_threads.rs index 4a13c55fb8b..7b243575e01 100644 --- a/library/std/src/sys/sync/mutex/no_threads.rs +++ b/library/std/src/sys/sync/mutex/no_threads.rs @@ -10,7 +10,7 @@ unsafe impl Sync for Mutex {} // no threads on this platform impl Mutex { #[inline] - #[rustc_const_stable(feature = "const_locks", since = "1.63.0")] + #[cfg_attr(bootstrap, rustc_const_stable(feature = "const_locks", since = "1.63.0"))] pub const fn new() -> Mutex { Mutex { locked: Cell::new(false) } } diff --git a/library/std/src/sys/sync/mutex/xous.rs b/library/std/src/sys/sync/mutex/xous.rs index 233e638f913..c6b954c1711 100644 --- a/library/std/src/sys/sync/mutex/xous.rs +++ b/library/std/src/sys/sync/mutex/xous.rs @@ -24,7 +24,6 @@ pub struct Mutex { impl Mutex { #[inline] - #[rustc_const_stable(feature = "const_locks", since = "1.63.0")] pub const fn new() -> Mutex { Mutex { locked: AtomicUsize::new(0), contended: AtomicBool::new(false) } } diff --git a/library/std/src/sys/sync/once/no_threads.rs b/library/std/src/sys/sync/once/no_threads.rs index cdcffe790f5..fb1b496510a 100644 --- a/library/std/src/sys/sync/once/no_threads.rs +++ b/library/std/src/sys/sync/once/no_threads.rs @@ -35,7 +35,7 @@ unsafe impl Sync for Once {} impl Once { #[inline] - #[rustc_const_stable(feature = "const_once_new", since = "1.32.0")] + #[cfg_attr(bootstrap, rustc_const_stable(feature = "const_once_new", since = "1.32.0"))] pub const fn new() -> Once { Once { state: Cell::new(State::Incomplete) } } diff --git a/library/std/src/sys/sync/rwlock/no_threads.rs b/library/std/src/sys/sync/rwlock/no_threads.rs index 789ef9b29e5..6965e2e2cab 100644 --- a/library/std/src/sys/sync/rwlock/no_threads.rs +++ b/library/std/src/sys/sync/rwlock/no_threads.rs @@ -10,7 +10,7 @@ unsafe impl Sync for RwLock {} // no threads on this platform impl RwLock { #[inline] - #[rustc_const_stable(feature = "const_locks", since = "1.63.0")] + #[cfg_attr(bootstrap, rustc_const_stable(feature = "const_locks", since = "1.63.0"))] pub const fn new() -> RwLock { RwLock { mode: Cell::new(0) } } diff --git a/library/stdarch b/library/stdarch -Subproject c881fe3231b3947a4766aa15a26a93022fbb872 +Subproject ff9a4445038eae46fd095188740946808581bc0 diff --git a/src/bootstrap/src/core/build_steps/compile.rs b/src/bootstrap/src/core/build_steps/compile.rs index 27bbc8bd8ff..e13d4ccc618 100644 --- a/src/bootstrap/src/core/build_steps/compile.rs +++ b/src/bootstrap/src/core/build_steps/compile.rs @@ -15,7 +15,6 @@ use std::path::{Path, PathBuf}; use std::process::Stdio; use std::{env, fs, str}; -use build_helper::git::get_closest_merge_commit; use serde_derive::Deserialize; use crate::core::build_steps::tool::SourceType; @@ -27,7 +26,7 @@ use crate::core::builder::{ use crate::core::config::{DebuginfoLevel, LlvmLibunwind, RustcLto, TargetSelection}; use crate::utils::exec::command; use crate::utils::helpers::{ - self, exe, get_clang_cl_resource_dir, is_debug_info, is_dylib, symlink_dir, t, up_to_date, + exe, get_clang_cl_resource_dir, is_debug_info, is_dylib, symlink_dir, t, up_to_date, }; use crate::{CLang, Compiler, DependencyType, GitRepo, LLVM_TOOLS, Mode}; @@ -125,23 +124,9 @@ impl Step for Std { // Force compilation of the standard library from source if the `library` is modified. This allows // library team to compile the standard library without needing to compile the compiler with // the `rust.download-rustc=true` option. - let force_recompile = - if builder.rust_info().is_managed_git_subrepository() && builder.download_rustc() { - let closest_merge_commit = - get_closest_merge_commit(Some(&builder.src), &builder.config.git_config(), &[]) - .unwrap(); - - // Check if `library` has changes (returns false otherwise) - !t!(helpers::git(Some(&builder.src)) - .args(["diff-index", "--quiet", &closest_merge_commit]) - .arg("--") - .arg(builder.src.join("library")) - .as_command_mut() - .status()) - .success() - } else { - false - }; + let force_recompile = builder.rust_info().is_managed_git_subrepository() + && builder.download_rustc() + && builder.config.last_modified_commit(&["library"], "download-rustc", true).is_none(); run.builder.ensure(Std { compiler: run.builder.compiler(run.builder.top_stage, run.build_triple()), diff --git a/src/bootstrap/src/core/config/config.rs b/src/bootstrap/src/core/config/config.rs index 087dde0d9c6..139ca7eb52e 100644 --- a/src/bootstrap/src/core/config/config.rs +++ b/src/bootstrap/src/core/config/config.rs @@ -2871,14 +2871,7 @@ impl Config { // Warn if there were changes to the compiler or standard library since the ancestor commit. let mut git = helpers::git(Some(&self.src)); - git.args(["diff-index", "--quiet", &commit, "--"]); - - // Handle running from a directory other than the top level - let top_level = &self.src; - - for path in modified_paths { - git.arg(top_level.join(path)); - } + git.args(["diff-index", "--quiet", &commit, "--"]).args(modified_paths); let has_changes = !t!(git.as_command_mut().status()).success(); if has_changes { diff --git a/src/bootstrap/src/lib.rs b/src/bootstrap/src/lib.rs index a9db0377a50..ba74cabcd30 100644 --- a/src/bootstrap/src/lib.rs +++ b/src/bootstrap/src/lib.rs @@ -541,7 +541,7 @@ impl Build { } let output = helpers::git(Some(&self.src)) .args(["config", "--file"]) - .arg(self.config.src.join(".gitmodules")) + .arg(".gitmodules") .args(["--get-regexp", "path"]) .run_capture(self) .stdout(); diff --git a/src/ci/docker/host-x86_64/dist-various-2/Dockerfile b/src/ci/docker/host-x86_64/dist-various-2/Dockerfile index 8aabfaafbab..ece5f174d06 100644 --- a/src/ci/docker/host-x86_64/dist-various-2/Dockerfile +++ b/src/ci/docker/host-x86_64/dist-various-2/Dockerfile @@ -56,9 +56,9 @@ ENV \ CFLAGS_x86_64_fortanix_unknown_sgx="-D__ELF__ -isystem/usr/include/x86_64-linux-gnu -mlvi-hardening -mllvm -x86-experimental-lvi-inline-asm-hardening" \ CXX_x86_64_fortanix_unknown_sgx=clang++-11 \ CXXFLAGS_x86_64_fortanix_unknown_sgx="-D__ELF__ -isystem/usr/include/x86_64-linux-gnu -mlvi-hardening -mllvm -x86-experimental-lvi-inline-asm-hardening" \ - AR_i686_unknown_freebsd=i686-unknown-freebsd13-ar \ - CC_i686_unknown_freebsd=i686-unknown-freebsd13-clang \ - CXX_i686_unknown_freebsd=i686-unknown-freebsd13-clang++ \ + AR_i686_unknown_freebsd=i686-unknown-freebsd12-ar \ + CC_i686_unknown_freebsd=i686-unknown-freebsd12-clang \ + CXX_i686_unknown_freebsd=i686-unknown-freebsd12-clang++ \ CC_aarch64_unknown_uefi=clang-11 \ CXX_aarch64_unknown_uefi=clang++-11 \ CC_i686_unknown_uefi=clang-11 \ diff --git a/src/ci/docker/host-x86_64/dist-x86_64-freebsd/Dockerfile b/src/ci/docker/host-x86_64/dist-x86_64-freebsd/Dockerfile index fd0f5da8c49..f42e6f770eb 100644 --- a/src/ci/docker/host-x86_64/dist-x86_64-freebsd/Dockerfile +++ b/src/ci/docker/host-x86_64/dist-x86_64-freebsd/Dockerfile @@ -29,9 +29,9 @@ COPY scripts/cmake.sh /scripts/ RUN /scripts/cmake.sh ENV \ - AR_x86_64_unknown_freebsd=x86_64-unknown-freebsd13-ar \ - CC_x86_64_unknown_freebsd=x86_64-unknown-freebsd13-clang \ - CXX_x86_64_unknown_freebsd=x86_64-unknown-freebsd13-clang++ + AR_x86_64_unknown_freebsd=x86_64-unknown-freebsd12-ar \ + CC_x86_64_unknown_freebsd=x86_64-unknown-freebsd12-clang \ + CXX_x86_64_unknown_freebsd=x86_64-unknown-freebsd12-clang++ ENV HOSTS=x86_64-unknown-freebsd diff --git a/src/ci/docker/host-x86_64/mingw-check/Dockerfile b/src/ci/docker/host-x86_64/mingw-check/Dockerfile index 0f8ebb987c3..fdc8a7310c8 100644 --- a/src/ci/docker/host-x86_64/mingw-check/Dockerfile +++ b/src/ci/docker/host-x86_64/mingw-check/Dockerfile @@ -51,7 +51,8 @@ ENV SCRIPT \ /scripts/check-default-config-profiles.sh && \ python3 ../x.py check --target=i686-pc-windows-gnu --host=i686-pc-windows-gnu && \ python3 ../x.py clippy bootstrap -Dwarnings && \ - python3 ../x.py clippy compiler library -Aclippy::all -Dclippy::correctness && \ + python3 ../x.py clippy library -Aclippy::all -Dclippy::correctness && \ + python3 ../x.py clippy compiler -Aclippy::all -Dclippy::correctness -Dclippy::clone_on_ref_ptr && \ python3 ../x.py build --stage 0 src/tools/build-manifest && \ python3 ../x.py test --stage 0 src/tools/compiletest && \ python3 ../x.py test --stage 0 core alloc std test proc_macro && \ diff --git a/src/ci/docker/scripts/freebsd-toolchain.sh b/src/ci/docker/scripts/freebsd-toolchain.sh index 4826b81d56c..0d02636db91 100755 --- a/src/ci/docker/scripts/freebsd-toolchain.sh +++ b/src/ci/docker/scripts/freebsd-toolchain.sh @@ -5,8 +5,8 @@ set -eux arch=$1 binutils_version=2.40 -freebsd_version=13.2 -triple=$arch-unknown-freebsd13 +freebsd_version=12.3 +triple=$arch-unknown-freebsd12 sysroot=/usr/local/$triple hide_output() { @@ -59,7 +59,7 @@ done # Originally downloaded from: # URL=https://download.freebsd.org/ftp/releases/${freebsd_arch}/${freebsd_version}-RELEASE/base.txz -URL=https://ci-mirrors.rust-lang.org/rustc/2024-02-18-freebsd-${freebsd_version}-${freebsd_arch}-base.txz +URL=https://ci-mirrors.rust-lang.org/rustc/2022-05-06-freebsd-${freebsd_version}-${freebsd_arch}-base.txz curl "$URL" | tar xJf - -C "$sysroot" --wildcards "${files_to_extract[@]}" # Clang can do cross-builds out of the box, if we give it the right @@ -68,7 +68,7 @@ curl "$URL" | tar xJf - -C "$sysroot" --wildcards "${files_to_extract[@]}" # there might be other problems.) # # The --target option is last because the cross-build of LLVM uses -# --target without an OS version ("-freebsd" vs. "-freebsd13"). This +# --target without an OS version ("-freebsd" vs. "-freebsd12"). This # makes Clang default to libstdc++ (which no longer exists), and also # controls other features, like GNU-style symbol table hashing and # anything predicated on the version number in the __FreeBSD__ diff --git a/src/doc/rustc/src/SUMMARY.md b/src/doc/rustc/src/SUMMARY.md index e05d9a40f00..18f76ac6fe0 100644 --- a/src/doc/rustc/src/SUMMARY.md +++ b/src/doc/rustc/src/SUMMARY.md @@ -66,9 +66,10 @@ - [powerpc-unknown-openbsd](platform-support/powerpc-unknown-openbsd.md) - [powerpc-unknown-linux-muslspe](platform-support/powerpc-unknown-linux-muslspe.md) - [powerpc64-ibm-aix](platform-support/aix.md) + - [riscv32e*-unknown-none-elf](platform-support/riscv32e-unknown-none-elf.md) + - [riscv32i*-unknown-none-elf](platform-support/riscv32-unknown-none-elf.md) - [riscv32im-risc0-zkvm-elf](platform-support/riscv32im-risc0-zkvm-elf.md) - [riscv32imac-unknown-xous-elf](platform-support/riscv32imac-unknown-xous-elf.md) - - [riscv32*-unknown-none-elf](platform-support/riscv32-unknown-none-elf.md) - [riscv64gc-unknown-linux-gnu](platform-support/riscv64gc-unknown-linux-gnu.md) - [riscv64gc-unknown-linux-musl](platform-support/riscv64gc-unknown-linux-musl.md) - [sparc-unknown-none-elf](./platform-support/sparc-unknown-none-elf.md) diff --git a/src/doc/rustc/src/platform-support.md b/src/doc/rustc/src/platform-support.md index 5da03d26eb4..04bb40d750c 100644 --- a/src/doc/rustc/src/platform-support.md +++ b/src/doc/rustc/src/platform-support.md @@ -100,7 +100,7 @@ target | notes [`riscv64gc-unknown-linux-gnu`](platform-support/riscv64gc-unknown-linux-gnu.md) | RISC-V Linux (kernel 4.20, glibc 2.29) [`riscv64gc-unknown-linux-musl`](platform-support/riscv64gc-unknown-linux-musl.md) | RISC-V Linux (kernel 4.20, musl 1.2.3) `s390x-unknown-linux-gnu` | S390x Linux (kernel 3.2, glibc 2.17) -`x86_64-unknown-freebsd` | 64-bit FreeBSD (version 13.2) +`x86_64-unknown-freebsd` | 64-bit FreeBSD `x86_64-unknown-illumos` | illumos `x86_64-unknown-linux-musl` | 64-bit Linux with musl 1.2.3 [`x86_64-unknown-netbsd`](platform-support/netbsd.md) | NetBSD/amd64 @@ -166,7 +166,7 @@ target | std | notes `i586-unknown-linux-musl` | ✓ | 32-bit Linux w/o SSE, musl 1.2.3 [^x86_32-floats-x87] [`i686-linux-android`](platform-support/android.md) | ✓ | 32-bit x86 Android [^x86_32-floats-return-ABI] [`i686-pc-windows-gnullvm`](platform-support/pc-windows-gnullvm.md) | ✓ | 32-bit x86 MinGW (Windows 10+), LLVM ABI [^x86_32-floats-return-ABI] -`i686-unknown-freebsd` | ✓ | 32-bit FreeBSD (version 13.2) [^x86_32-floats-return-ABI] +`i686-unknown-freebsd` | ✓ | 32-bit FreeBSD [^x86_32-floats-return-ABI] `i686-unknown-linux-musl` | ✓ | 32-bit Linux with musl 1.2.3 [^x86_32-floats-return-ABI] [`i686-unknown-uefi`](platform-support/unknown-uefi.md) | ? | 32-bit UEFI [`loongarch64-unknown-none`](platform-support/loongarch-none.md) | * | LoongArch64 Bare-metal (LP64D ABI) @@ -258,7 +258,7 @@ target | std | host | notes [`aarch64-unknown-teeos`](platform-support/aarch64-unknown-teeos.md) | ? | | ARM64 TEEOS | [`aarch64-unknown-nto-qnx700`](platform-support/nto-qnx.md) | ? | | ARM64 QNX Neutrino 7.0 RTOS | [`aarch64-unknown-nto-qnx710`](platform-support/nto-qnx.md) | ✓ | | ARM64 QNX Neutrino 7.1 RTOS | -`aarch64-unknown-freebsd` | ✓ | ✓ | ARM64 FreeBSD (version 13.2) +`aarch64-unknown-freebsd` | ✓ | ✓ | ARM64 FreeBSD [`aarch64-unknown-hermit`](platform-support/hermit.md) | ✓ | | ARM64 Hermit `aarch64-unknown-illumos` | ✓ | ✓ | ARM64 illumos `aarch64-unknown-linux-gnu_ilp32` | ✓ | ✓ | ARM64 Linux (ILP32 ABI) @@ -277,14 +277,14 @@ target | std | host | notes `armv4t-unknown-linux-gnueabi` | ? | | Armv4T Linux [`armv5te-none-eabi`](platform-support/armv5te-none-eabi.md) | * | | Bare Armv5TE `armv5te-unknown-linux-uclibceabi` | ? | | Armv5TE Linux with uClibc -`armv6-unknown-freebsd` | ✓ | ✓ | Armv6 FreeBSD (version 13.2) +`armv6-unknown-freebsd` | ✓ | ✓ | Armv6 FreeBSD [`armv6-unknown-netbsd-eabihf`](platform-support/netbsd.md) | ✓ | ✓ | Armv6 NetBSD w/hard-float [`armv6k-nintendo-3ds`](platform-support/armv6k-nintendo-3ds.md) | ? | | Armv6k Nintendo 3DS, Horizon (Requires devkitARM toolchain) [`armv7-rtems-eabihf`](platform-support/armv7-rtems-eabihf.md) | ? | | RTEMS OS for ARM BSPs [`armv7-sony-vita-newlibeabihf`](platform-support/armv7-sony-vita-newlibeabihf.md) | ✓ | | Armv7-A Cortex-A9 Sony PlayStation Vita (requires VITASDK toolchain) [`armv7-unknown-linux-uclibceabi`](platform-support/armv7-unknown-linux-uclibceabi.md) | ✓ | ✓ | Armv7-A Linux with uClibc, softfloat [`armv7-unknown-linux-uclibceabihf`](platform-support/armv7-unknown-linux-uclibceabihf.md) | ✓ | ? | Armv7-A Linux with uClibc, hardfloat -`armv7-unknown-freebsd` | ✓ | ✓ | Armv7-A FreeBSD (version 13.2) +`armv7-unknown-freebsd` | ✓ | ✓ | Armv7-A FreeBSD [`armv7-unknown-netbsd-eabihf`](platform-support/netbsd.md) | ✓ | ✓ | Armv7-A NetBSD w/hard-float [`armv7-unknown-trusty`](platform-support/trusty.md) | ? | | [`armv7-wrs-vxworks-eabihf`](platform-support/vxworks.md) | ✓ | | Armv7-A for VxWorks @@ -343,9 +343,9 @@ target | std | host | notes [`powerpc-unknown-openbsd`](platform-support/powerpc-unknown-openbsd.md) | * | | [`powerpc-wrs-vxworks-spe`](platform-support/vxworks.md) | ✓ | | [`powerpc-wrs-vxworks`](platform-support/vxworks.md) | ✓ | | -`powerpc64-unknown-freebsd` | ✓ | ✓ | PPC64 FreeBSD (ELFv1 and ELFv2, version 13.2) -`powerpc64le-unknown-freebsd` | | | PPC64LE FreeBSD (version 13.2) -`powerpc-unknown-freebsd` | | | PowerPC FreeBSD (version 13.2) +`powerpc64-unknown-freebsd` | ✓ | ✓ | PPC64 FreeBSD (ELFv1 and ELFv2) +`powerpc64le-unknown-freebsd` | | | PPC64LE FreeBSD +`powerpc-unknown-freebsd` | | | PowerPC FreeBSD `powerpc64-unknown-linux-musl` | ? | | 64-bit PowerPC Linux with musl 1.2.3 [`powerpc64-wrs-vxworks`](platform-support/vxworks.md) | ✓ | | `powerpc64le-unknown-linux-musl` | ? | | 64-bit PowerPC Linux with musl 1.2.3, Little Endian @@ -361,7 +361,7 @@ target | std | host | notes [`riscv32imafc-esp-espidf`](platform-support/esp-idf.md) | ✓ | | RISC-V ESP-IDF [`riscv32-wrs-vxworks`](platform-support/vxworks.md) | ✓ | | [`riscv64gc-unknown-hermit`](platform-support/hermit.md) | ✓ | | RISC-V Hermit -`riscv64gc-unknown-freebsd` | | | RISC-V FreeBSD (version 13.2) +`riscv64gc-unknown-freebsd` | | | RISC-V FreeBSD `riscv64gc-unknown-fuchsia` | | | RISC-V Fuchsia [`riscv64gc-unknown-netbsd`](platform-support/netbsd.md) | ✓ | ✓ | RISC-V NetBSD [`riscv64gc-unknown-openbsd`](platform-support/openbsd.md) | ✓ | ✓ | OpenBSD/riscv64 @@ -414,8 +414,8 @@ target | std | host | notes [`riscv32imafc-unknown-nuttx-elf`](platform-support/nuttx.md) | * | | RISC-V 32bit with NuttX [`riscv64imac-unknown-nuttx-elf`](platform-support/nuttx.md) | * | | RISC-V 64bit with NuttX [`riscv64gc-unknown-nuttx-elf`](platform-support/nuttx.md) | * | | RISC-V 64bit with NuttX -[`riscv32e-unknown-none-elf`](platform-support/riscv32-unknown-none-elf.md) | * | | Bare RISC-V (RV32E ISA) -[`riscv32em-unknown-none-elf`](platform-support/riscv32-unknown-none-elf.md) | * | | Bare RISC-V (RV32EM ISA) -[`riscv32emc-unknown-none-elf`](platform-support/riscv32-unknown-none-elf.md) | * | | Bare RISC-V (RV32EMC ISA) +[`riscv32e-unknown-none-elf`](platform-support/riscv32e-unknown-none-elf.md) | * | | Bare RISC-V (RV32E ISA) +[`riscv32em-unknown-none-elf`](platform-support/riscv32e-unknown-none-elf.md) | * | | Bare RISC-V (RV32EM ISA) +[`riscv32emc-unknown-none-elf`](platform-support/riscv32e-unknown-none-elf.md) | * | | Bare RISC-V (RV32EMC ISA) [runs on NVIDIA GPUs]: https://github.com/japaric-archived/nvptx#targets diff --git a/src/doc/rustc/src/platform-support/aix.md b/src/doc/rustc/src/platform-support/aix.md index c3ce71a1835..5a198062b95 100644 --- a/src/doc/rustc/src/platform-support/aix.md +++ b/src/doc/rustc/src/platform-support/aix.md @@ -6,8 +6,8 @@ Rust for AIX operating system, currently only 64-bit PowerPC is supported. ## Target maintainers -- QIU Chaofan `qiucofan@cn.ibm.com`, https://github.com/ecnelises -- Kai LUO, `lkail@cn.ibm.com`, https://github.com/bzEq +- David Tenty `daltenty@ibm.com`, https://github.com/daltenty +- Chris Cambly, `ccambly@ca.ibm.com`, https://github.com/gilamn5tr ## Requirements diff --git a/src/doc/rustc/src/platform-support/fuchsia.md b/src/doc/rustc/src/platform-support/fuchsia.md index 5643c6a0188..489f46e1cb9 100644 --- a/src/doc/rustc/src/platform-support/fuchsia.md +++ b/src/doc/rustc/src/platform-support/fuchsia.md @@ -7,17 +7,9 @@ updatable, and performant. ## Target maintainers -The [Fuchsia team]: +See [`fuchsia.toml`] in the `team` repository for current target maintainers. -- Tyler Mandry ([@tmandry](https://github.com/tmandry)) -- David Koloski ([@djkoloski](https://github.com/djkoloski)) -- Julia Ryan ([@P1n3appl3](https://github.com/P1n3appl3)) -- Erick Tryzelaar ([@erickt](https://github.com/erickt)) - -As the team evolves over time, the specific members listed here may differ from -the members reported by the API. The API should be considered to be -authoritative if this occurs. Instead of pinging individual members, use -`@rustbot ping fuchsia` to contact the team on GitHub. +[`fuchsia.toml`]: https://github.com/rust-lang/team/blob/master/teams/fuchsia.toml ## Table of contents @@ -525,14 +517,6 @@ ${SDK_PATH}/tools/${ARCH}/ffx repository publish \ pkg/repo ``` -Then we can add the repository to `ffx`'s package server as `hello-fuchsia` using: - -```sh -${SDK_PATH}/tools/${ARCH}/ffx repository add-from-pm \ - --repository hello-fuchsia \ - pkg/repo -``` - ## Running a Fuchsia component on an emulator At this point, we are ready to run our Fuchsia @@ -590,7 +574,8 @@ Now, start a package repository server to serve our package to the emulator: ```sh -${SDK_PATH}/tools/${ARCH}/ffx repository server start +${SDK_PATH}/tools/${ARCH}/ffx repository server start \ + --background --repository hello-fuchsia --repo-path pkg-repo ``` Once the repository server is up and running, register it with the target Fuchsia system running in the emulator: diff --git a/src/etc/cat-and-grep.sh b/src/etc/cat-and-grep.sh index 238f7f5b660..68c6993ac15 100755 --- a/src/etc/cat-and-grep.sh +++ b/src/etc/cat-and-grep.sh @@ -33,7 +33,6 @@ while getopts ':vieh' OPTION; do case "$OPTION" in v) INVERT=1 - ERROR_MSG='should not be found' ;; i) GREPFLAGS="i$GREPFLAGS" diff --git a/src/etc/htmldocck.py b/src/etc/htmldocck.py index 599e1e8102c..851b01a7458 100755 --- a/src/etc/htmldocck.py +++ b/src/etc/htmldocck.py @@ -250,7 +250,7 @@ def get_known_directive_names(): os.path.join( # We go back to `src`. os.path.dirname(os.path.dirname(__file__)), - "tools/compiletest/src/command-list.rs", + "tools/compiletest/src/directive-list.rs", ), "r", encoding="utf8" diff --git a/src/librustdoc/clean/blanket_impl.rs b/src/librustdoc/clean/blanket_impl.rs index 1f3cb4a61b8..a6d9676dd84 100644 --- a/src/librustdoc/clean/blanket_impl.rs +++ b/src/librustdoc/clean/blanket_impl.rs @@ -1,7 +1,7 @@ use rustc_hir as hir; use rustc_infer::infer::{DefineOpaqueTypes, InferOk, TyCtxtInferExt}; use rustc_infer::traits; -use rustc_middle::ty::{self, Upcast}; +use rustc_middle::ty::{self, TypingMode, Upcast}; use rustc_span::DUMMY_SP; use rustc_span::def_id::DefId; use rustc_trait_selection::traits::query::evaluate_obligation::InferCtxtExt; @@ -38,7 +38,7 @@ pub(crate) fn synthesize_blanket_impls( if !matches!(trait_ref.skip_binder().self_ty().kind(), ty::Param(_)) { continue; } - let infcx = tcx.infer_ctxt().build(); + let infcx = tcx.infer_ctxt().build(TypingMode::non_body_analysis()); let args = infcx.fresh_args_for_item(DUMMY_SP, item_def_id); let impl_ty = ty.instantiate(tcx, args); let param_env = ty::ParamEnv::empty(); diff --git a/src/librustdoc/clean/inline.rs b/src/librustdoc/clean/inline.rs index e7f921eef7f..97529e420e3 100644 --- a/src/librustdoc/clean/inline.rs +++ b/src/librustdoc/clean/inline.rs @@ -248,9 +248,7 @@ pub(crate) fn record_extern_fqn(cx: &mut DocContext<'_>, did: DefId, kind: ItemT // Check to see if it is a macro 2.0 or built-in macro if matches!( CStore::from_tcx(cx.tcx).load_macro_untracked(did, cx.tcx), - LoadedMacro::MacroDef(def, _) - if matches!(&def.kind, ast::ItemKind::MacroDef(ast_def) - if !ast_def.macro_rules) + LoadedMacro::MacroDef { def, .. } if !def.macro_rules ) { once(crate_name).chain(relative).collect() } else { @@ -747,24 +745,12 @@ fn build_macro( is_doc_hidden: bool, ) -> clean::ItemKind { match CStore::from_tcx(cx.tcx).load_macro_untracked(def_id, cx.tcx) { - LoadedMacro::MacroDef(item_def, _) => match macro_kind { + LoadedMacro::MacroDef { def, .. } => match macro_kind { MacroKind::Bang => { - if let ast::ItemKind::MacroDef(ref def) = item_def.kind { - let vis = - cx.tcx.visibility(import_def_id.map(|d| d.to_def_id()).unwrap_or(def_id)); - clean::MacroItem(clean::Macro { - source: utils::display_macro_source( - cx, - name, - def, - def_id, - vis, - is_doc_hidden, - ), - }) - } else { - unreachable!() - } + let vis = cx.tcx.visibility(import_def_id.map(|d| d.to_def_id()).unwrap_or(def_id)); + clean::MacroItem(clean::Macro { + source: utils::display_macro_source(cx, name, &def, def_id, vis, is_doc_hidden), + }) } MacroKind::Derive | MacroKind::Attr => { clean::ProcMacroItem(clean::ProcMacro { kind: macro_kind, helpers: Vec::new() }) diff --git a/src/librustdoc/clean/mod.rs b/src/librustdoc/clean/mod.rs index ea349f878e0..58663fcbafe 100644 --- a/src/librustdoc/clean/mod.rs +++ b/src/librustdoc/clean/mod.rs @@ -45,7 +45,7 @@ use rustc_hir::def_id::{DefId, DefIdMap, DefIdSet, LOCAL_CRATE, LocalDefId}; use rustc_hir_analysis::lower_ty; use rustc_middle::metadata::Reexport; use rustc_middle::middle::resolve_bound_vars as rbv; -use rustc_middle::ty::{self, AdtKind, GenericArgsRef, Ty, TyCtxt, TypeVisitableExt}; +use rustc_middle::ty::{self, AdtKind, GenericArgsRef, Ty, TyCtxt, TypeVisitableExt, TypingMode}; use rustc_middle::{bug, span_bug}; use rustc_span::ExpnKind; use rustc_span::hygiene::{AstPass, MacroKind}; @@ -1829,7 +1829,7 @@ pub(crate) fn clean_ty<'tcx>(ty: &hir::Ty<'tcx>, cx: &mut DocContext<'tcx>) -> T Array(Box::new(clean_ty(ty, cx)), length.into()) } TyKind::Tup(tys) => Tuple(tys.iter().map(|ty| clean_ty(ty, cx)).collect()), - TyKind::OpaqueDef(ty, _) => { + TyKind::OpaqueDef(ty) => { ImplTrait(ty.bounds.iter().filter_map(|x| clean_generic_bound(x, cx)).collect()) } TyKind::Path(_) => clean_qpath(ty, cx), @@ -1863,7 +1863,7 @@ fn normalize<'tcx>( use rustc_trait_selection::traits::query::normalize::QueryNormalizeExt; // Try to normalize `<X as Y>::T` to a type - let infcx = cx.tcx.infer_ctxt().build(); + let infcx = cx.tcx.infer_ctxt().build(TypingMode::non_body_analysis()); let normalized = infcx .at(&ObligationCause::dummy(), cx.param_env) .query_normalize(ty) @@ -2399,7 +2399,7 @@ pub(crate) fn clean_variant_def_with_args<'tcx>( use rustc_trait_selection::infer::TyCtxtInferExt; use rustc_trait_selection::traits::query::normalize::QueryNormalizeExt; - let infcx = cx.tcx.infer_ctxt().build(); + let infcx = cx.tcx.infer_ctxt().build(TypingMode::non_body_analysis()); let kind = match variant.ctor_kind() { Some(CtorKind::Const) => VariantKind::CLike, Some(CtorKind::Fn) => VariantKind::Tuple( diff --git a/src/librustdoc/doctest/runner.rs b/src/librustdoc/doctest/runner.rs index 093755103f3..234f40c6c1a 100644 --- a/src/librustdoc/doctest/runner.rs +++ b/src/librustdoc/doctest/runner.rs @@ -198,10 +198,6 @@ fn generate_mergeable_doctest( } else { writeln!(output, "mod {test_id} {{\n{}{}", doctest.crates, doctest.maybe_crate_attrs) .unwrap(); - if scraped_test.langstr.no_run { - // To prevent having warnings about unused items since they're not called. - writeln!(output, "#![allow(unused)]").unwrap(); - } if doctest.has_main_fn { output.push_str(&doctest.everything_else); } else { diff --git a/src/librustdoc/html/format.rs b/src/librustdoc/html/format.rs index ea2f930ab83..47c21d89177 100644 --- a/src/librustdoc/html/format.rs +++ b/src/librustdoc/html/format.rs @@ -16,16 +16,15 @@ use itertools::Itertools; use rustc_attr::{ConstStability, StabilityLevel, StableSince}; use rustc_data_structures::captures::Captures; use rustc_data_structures::fx::FxHashSet; +use rustc_hir as hir; use rustc_hir::def::DefKind; use rustc_hir::def_id::{DefId, LOCAL_CRATE}; use rustc_metadata::creader::{CStore, LoadedMacro}; -use rustc_middle::ty; -use rustc_middle::ty::TyCtxt; +use rustc_middle::ty::{self, TyCtxt, TypingMode}; use rustc_span::symbol::kw; use rustc_span::{Symbol, sym}; use rustc_target::spec::abi::Abi; use tracing::{debug, trace}; -use {rustc_ast as ast, rustc_hir as hir}; use super::url_parts_builder::{UrlPartsBuilder, estimate_item_path_byte_length}; use crate::clean::types::ExternalLocation; @@ -554,10 +553,8 @@ fn generate_macro_def_id_path( // Check to see if it is a macro 2.0 or built-in macro. // More information in <https://rust-lang.github.io/rfcs/1584-macros.html>. let is_macro_2 = match cstore.load_macro_untracked(def_id, tcx) { - LoadedMacro::MacroDef(def, _) => { - // If `ast_def.macro_rules` is `true`, then it's not a macro 2.0. - matches!(&def.kind, ast::ItemKind::MacroDef(ast_def) if !ast_def.macro_rules) - } + // If `def.macro_rules` is `true`, then it's not a macro 2.0. + LoadedMacro::MacroDef { def, .. } => !def.macro_rules, _ => false, }; @@ -615,7 +612,7 @@ fn generate_item_def_id_path( // No need to try to infer the actual parent item if it's not an associated item from the `impl` // block. if def_id != original_def_id && matches!(tcx.def_kind(def_id), DefKind::Impl { .. }) { - let infcx = tcx.infer_ctxt().build(); + let infcx = tcx.infer_ctxt().build(TypingMode::non_body_analysis()); def_id = infcx .at(&ObligationCause::dummy(), tcx.param_env(def_id)) .query_normalize(ty::Binder::dummy(tcx.type_of(def_id).instantiate_identity())) diff --git a/src/librustdoc/html/render/search_index.rs b/src/librustdoc/html/render/search_index.rs index c958458b662..d1939adc1a5 100644 --- a/src/librustdoc/html/render/search_index.rs +++ b/src/librustdoc/html/render/search_index.rs @@ -759,7 +759,10 @@ pub(crate) fn get_function_type_for_search<'tcx>( } }); let (mut inputs, mut output, where_clause) = match item.kind { - clean::FunctionItem(ref f) | clean::MethodItem(ref f, _) | clean::TyMethodItem(ref f) => { + clean::ForeignFunctionItem(ref f, _) + | clean::FunctionItem(ref f) + | clean::MethodItem(ref f, _) + | clean::TyMethodItem(ref f) => { get_fn_inputs_and_outputs(f, tcx, impl_or_trait_generics, cache) } _ => return None, diff --git a/src/librustdoc/html/render/type_layout.rs b/src/librustdoc/html/render/type_layout.rs index cd4e597ff28..79209cee94f 100644 --- a/src/librustdoc/html/render/type_layout.rs +++ b/src/librustdoc/html/render/type_layout.rs @@ -60,8 +60,8 @@ pub(crate) fn document_type_layout<'a, 'cx: 'a>( span_bug!(tcx.def_span(ty_def_id), "not an adt") }; let name = adt.variant(variant_idx).name; - let is_unsized = variant_layout.abi.is_unsized(); - let is_uninhabited = variant_layout.abi.is_uninhabited(); + let is_unsized = variant_layout.is_unsized(); + let is_uninhabited = variant_layout.is_uninhabited(); let size = variant_layout.size.bytes() - tag_size; let type_layout_size = TypeLayoutSize { is_unsized, is_uninhabited, size }; (name, type_layout_size) @@ -72,8 +72,8 @@ pub(crate) fn document_type_layout<'a, 'cx: 'a>( }; let type_layout_size = tcx.layout_of(param_env.and(ty)).map(|layout| { - let is_unsized = layout.abi.is_unsized(); - let is_uninhabited = layout.abi.is_uninhabited(); + let is_unsized = layout.is_unsized(); + let is_uninhabited = layout.is_uninhabited(); let size = layout.size.bytes(); TypeLayoutSize { is_unsized, is_uninhabited, size } }); diff --git a/src/librustdoc/html/static/css/rustdoc.css b/src/librustdoc/html/static/css/rustdoc.css index ae4d55e93ac..1042d254749 100644 --- a/src/librustdoc/html/static/css/rustdoc.css +++ b/src/librustdoc/html/static/css/rustdoc.css @@ -230,7 +230,7 @@ h4.code-header { padding: 0; white-space: pre-wrap; } -.structfield { +.structfield, .sub-variant-field { margin: 0.6em 0; } @@ -959,7 +959,7 @@ pre, .rustdoc.src .example-wrap, .example-wrap .src-line-numbers { background: var(--table-alt-row-background-color); } -.docblock .stab, .docblock-short .stab { +.docblock .stab, .docblock-short .stab, .docblock p code { display: inline-block; } diff --git a/src/tools/clippy/clippy_lints/src/deprecated_lints.rs b/src/tools/clippy/clippy_lints/src/deprecated_lints.rs index 0066ed64325..77dbe9b78a1 100644 --- a/src/tools/clippy/clippy_lints/src/deprecated_lints.rs +++ b/src/tools/clippy/clippy_lints/src/deprecated_lints.rs @@ -166,7 +166,7 @@ declare_with_version! { RENAMED(RENAMED_VERSION): &[(&str, &str)] = &[ #[clippy::version = ""] ("clippy::positional_named_format_parameters", "named_arguments_used_positionally"), #[clippy::version = ""] - ("clippy::temporary_cstring_as_ptr", "temporary_cstring_as_ptr"), + ("clippy::temporary_cstring_as_ptr", "dangling_pointers_from_temporaries"), #[clippy::version = ""] ("clippy::undropped_manually_drops", "undropped_manually_drops"), #[clippy::version = ""] diff --git a/src/tools/clippy/clippy_lints/src/eta_reduction.rs b/src/tools/clippy/clippy_lints/src/eta_reduction.rs index cabc6592258..6ca599ed361 100644 --- a/src/tools/clippy/clippy_lints/src/eta_reduction.rs +++ b/src/tools/clippy/clippy_lints/src/eta_reduction.rs @@ -9,7 +9,8 @@ use rustc_hir::{BindingMode, Expr, ExprKind, FnRetTy, Param, PatKind, QPath, Saf use rustc_infer::infer::TyCtxtInferExt; use rustc_lint::{LateContext, LateLintPass}; use rustc_middle::ty::{ - self, Binder, ClosureKind, FnSig, GenericArg, GenericArgKind, List, Region, Ty, TypeVisitableExt, TypeckResults, + self, Binder, ClosureKind, FnSig, GenericArg, GenericArgKind, List, Region, Ty, TypeVisitableExt, + TypeckResults, }; use rustc_session::declare_lint_pass; use rustc_span::symbol::sym; @@ -203,7 +204,7 @@ fn check_clousure<'tcx>(cx: &LateContext<'tcx>, outer_receiver: Option<&Expr<'tc // 'cuz currently nothing changes after deleting this check. local_used_in(cx, l, args) || local_used_after_expr(cx, l, expr) }) { - match cx.tcx.infer_ctxt().build().err_ctxt().type_implements_fn_trait( + match cx.tcx.infer_ctxt().build(cx.typing_mode()).err_ctxt().type_implements_fn_trait( cx.param_env, Binder::bind_with_vars(callee_ty_adjusted, List::empty()), ty::PredicatePolarity::Positive, diff --git a/src/tools/clippy/clippy_lints/src/functions/must_use.rs b/src/tools/clippy/clippy_lints/src/functions/must_use.rs index cfd11e9339f..c74ba088b78 100644 --- a/src/tools/clippy/clippy_lints/src/functions/must_use.rs +++ b/src/tools/clippy/clippy_lints/src/functions/must_use.rs @@ -117,7 +117,7 @@ fn check_needless_must_use( } else if attr.value_str().is_none() && is_must_use_ty(cx, return_ty(cx, item_id)) { // Ignore async functions unless Future::Output type is a must_use type if sig.header.is_async() { - let infcx = cx.tcx.infer_ctxt().build(); + let infcx = cx.tcx.infer_ctxt().build(cx.typing_mode()); if let Some(future_ty) = infcx.err_ctxt().get_impl_future_output_ty(return_ty(cx, item_id)) && !is_must_use_ty(cx, future_ty) { diff --git a/src/tools/clippy/clippy_lints/src/future_not_send.rs b/src/tools/clippy/clippy_lints/src/future_not_send.rs index a4dbe134f36..cf08c16458b 100644 --- a/src/tools/clippy/clippy_lints/src/future_not_send.rs +++ b/src/tools/clippy/clippy_lints/src/future_not_send.rs @@ -74,7 +74,7 @@ impl<'tcx> LateLintPass<'tcx> for FutureNotSend { if is_future { let send_trait = cx.tcx.get_diagnostic_item(sym::Send).unwrap(); let span = decl.output.span(); - let infcx = cx.tcx.infer_ctxt().build(); + let infcx = cx.tcx.infer_ctxt().build(cx.typing_mode()); let ocx = ObligationCtxt::new_with_diagnostics(&infcx); let cause = traits::ObligationCause::misc(span, fn_def_id); ocx.register_bound(cause, cx.param_env, ret_ty, send_trait); diff --git a/src/tools/clippy/clippy_lints/src/lifetimes.rs b/src/tools/clippy/clippy_lints/src/lifetimes.rs index 5a3930b8bb8..d55be2b036a 100644 --- a/src/tools/clippy/clippy_lints/src/lifetimes.rs +++ b/src/tools/clippy/clippy_lints/src/lifetimes.rs @@ -420,15 +420,6 @@ impl<'tcx> Visitor<'tcx> for RefVisitor<'_, 'tcx> { fn visit_ty(&mut self, ty: &'tcx Ty<'_>) { match ty.kind { - TyKind::OpaqueDef(opaque, bounds) => { - let len = self.lts.len(); - self.visit_opaque_ty(opaque); - self.lts.truncate(len); - self.lts.extend(bounds.iter().filter_map(|bound| match bound { - GenericArg::Lifetime(&l) => Some(l), - _ => None, - })); - }, TyKind::BareFn(&BareFnTy { decl, .. }) => { let mut sub_visitor = RefVisitor::new(self.cx); sub_visitor.visit_fn_decl(decl); diff --git a/src/tools/clippy/clippy_lints/src/manual_async_fn.rs b/src/tools/clippy/clippy_lints/src/manual_async_fn.rs index 67255c1af79..c904137da1a 100644 --- a/src/tools/clippy/clippy_lints/src/manual_async_fn.rs +++ b/src/tools/clippy/clippy_lints/src/manual_async_fn.rs @@ -4,9 +4,11 @@ use rustc_errors::Applicability; use rustc_hir::intravisit::FnKind; use rustc_hir::{ Block, Body, Closure, ClosureKind, CoroutineDesugaring, CoroutineKind, CoroutineSource, Expr, ExprKind, FnDecl, - FnRetTy, GenericArg, GenericBound, ImplItem, Item, LifetimeName, Node, TraitRef, Ty, TyKind, + FnRetTy, GenericBound, ImplItem, Item, Node, OpaqueTy, TraitRef, Ty, TyKind, }; use rustc_lint::{LateContext, LateLintPass}; +use rustc_middle::middle::resolve_bound_vars::ResolvedArg; +use rustc_middle::ty; use rustc_session::declare_lint_pass; use rustc_span::def_id::LocalDefId; use rustc_span::{Span, sym}; @@ -44,21 +46,22 @@ impl<'tcx> LateLintPass<'tcx> for ManualAsyncFn { decl: &'tcx FnDecl<'_>, body: &'tcx Body<'_>, span: Span, - def_id: LocalDefId, + fn_def_id: LocalDefId, ) { if let Some(header) = kind.header() && !header.asyncness.is_async() // Check that this function returns `impl Future` && let FnRetTy::Return(ret_ty) = decl.output - && let Some((trait_ref, output_lifetimes)) = future_trait_ref(cx, ret_ty) + && let TyKind::OpaqueDef(opaque) = ret_ty.kind + && let Some(trait_ref) = future_trait_ref(cx, opaque) && let Some(output) = future_output_ty(trait_ref) - && captures_all_lifetimes(decl.inputs, &output_lifetimes) + && captures_all_lifetimes(cx, fn_def_id, opaque.def_id) // Check that the body of the function consists of one async block && let ExprKind::Block(block, _) = body.value.kind && block.stmts.is_empty() && let Some(closure_body) = desugared_async_block(cx, block) && let Node::Item(Item {vis_span, ..}) | Node::ImplItem(ImplItem {vis_span, ..}) = - cx.tcx.hir_node_by_def_id(def_id) + cx.tcx.hir_node_by_def_id(fn_def_id) { let header_span = span.with_hi(ret_ty.span.hi()); @@ -101,12 +104,8 @@ impl<'tcx> LateLintPass<'tcx> for ManualAsyncFn { } } -fn future_trait_ref<'tcx>( - cx: &LateContext<'tcx>, - ty: &'tcx Ty<'tcx>, -) -> Option<(&'tcx TraitRef<'tcx>, Vec<LifetimeName>)> { - if let TyKind::OpaqueDef(opaque, bounds) = ty.kind - && let Some(trait_ref) = opaque.bounds.iter().find_map(|bound| { +fn future_trait_ref<'tcx>(cx: &LateContext<'tcx>, opaque: &'tcx OpaqueTy<'tcx>) -> Option<&'tcx TraitRef<'tcx>> { + if let Some(trait_ref) = opaque.bounds.iter().find_map(|bound| { if let GenericBound::Trait(poly) = bound { Some(&poly.trait_ref) } else { @@ -115,18 +114,7 @@ fn future_trait_ref<'tcx>( }) && trait_ref.trait_def_id() == cx.tcx.lang_items().future_trait() { - let output_lifetimes = bounds - .iter() - .filter_map(|bound| { - if let GenericArg::Lifetime(lt) = bound { - Some(lt.res) - } else { - None - } - }) - .collect(); - - return Some((trait_ref, output_lifetimes)); + return Some(trait_ref); } None @@ -145,27 +133,35 @@ fn future_output_ty<'tcx>(trait_ref: &'tcx TraitRef<'tcx>) -> Option<&'tcx Ty<'t None } -fn captures_all_lifetimes(inputs: &[Ty<'_>], output_lifetimes: &[LifetimeName]) -> bool { - let input_lifetimes: Vec<LifetimeName> = inputs +fn captures_all_lifetimes(cx: &LateContext<'_>, fn_def_id: LocalDefId, opaque_def_id: LocalDefId) -> bool { + let early_input_params = ty::GenericArgs::identity_for_item(cx.tcx, fn_def_id); + let late_input_params = cx.tcx.late_bound_vars(cx.tcx.local_def_id_to_hir_id(fn_def_id)); + + let num_early_lifetimes = early_input_params .iter() - .filter_map(|ty| { - if let TyKind::Ref(lt, _) = ty.kind { - Some(lt.res) - } else { - None - } + .filter(|param| param.as_region().is_some()) + .count(); + let num_late_lifetimes = late_input_params + .iter() + .filter(|param_kind| matches!(param_kind, ty::BoundVariableKind::Region(_))) + .count(); + + // There is no lifetime, so they are all captured. + if num_early_lifetimes == 0 && num_late_lifetimes == 0 { + return true; + } + + // By construction, each captured lifetime only appears once in `opaque_captured_lifetimes`. + let num_captured_lifetimes = cx + .tcx + .opaque_captured_lifetimes(opaque_def_id) + .iter() + .filter(|&(lifetime, _)| match *lifetime { + ResolvedArg::EarlyBound(_) | ResolvedArg::LateBound(ty::INNERMOST, _, _) => true, + _ => false, }) - .collect(); - - // The lint should trigger in one of these cases: - // - There are no input lifetimes - // - There's only one output lifetime bound using `+ '_` - // - All input lifetimes are explicitly bound to the output - input_lifetimes.is_empty() - || (output_lifetimes.len() == 1 && matches!(output_lifetimes[0], LifetimeName::Infer)) - || input_lifetimes - .iter() - .all(|in_lt| output_lifetimes.iter().any(|out_lt| in_lt == out_lt)) + .count(); + num_captured_lifetimes == num_early_lifetimes + num_late_lifetimes } fn desugared_async_block<'tcx>(cx: &LateContext<'tcx>, block: &'tcx Block<'tcx>) -> Option<&'tcx Body<'tcx>> { diff --git a/src/tools/clippy/clippy_lints/src/methods/unnecessary_to_owned.rs b/src/tools/clippy/clippy_lints/src/methods/unnecessary_to_owned.rs index cfa1fdb8137..82549413fa9 100644 --- a/src/tools/clippy/clippy_lints/src/methods/unnecessary_to_owned.rs +++ b/src/tools/clippy/clippy_lints/src/methods/unnecessary_to_owned.rs @@ -568,7 +568,7 @@ fn can_change_type<'a>(cx: &LateContext<'a>, mut expr: &'a Expr<'a>, mut ty: Ty< let obligation = Obligation::new(cx.tcx, ObligationCause::dummy(), cx.param_env, predicate); !cx.tcx .infer_ctxt() - .build() + .build(cx.typing_mode()) .predicate_must_hold_modulo_regions(&obligation) }) { return false; diff --git a/src/tools/clippy/clippy_lints/src/needless_borrows_for_generic_args.rs b/src/tools/clippy/clippy_lints/src/needless_borrows_for_generic_args.rs index f6db12ed84e..f7fa31d83aa 100644 --- a/src/tools/clippy/clippy_lints/src/needless_borrows_for_generic_args.rs +++ b/src/tools/clippy/clippy_lints/src/needless_borrows_for_generic_args.rs @@ -278,7 +278,7 @@ fn needless_borrow_count<'tcx>( let predicate = EarlyBinder::bind(predicate).instantiate(cx.tcx, &args_with_referent_ty[..]); let obligation = Obligation::new(cx.tcx, ObligationCause::dummy(), cx.param_env, predicate); - let infcx = cx.tcx.infer_ctxt().build(); + let infcx = cx.tcx.infer_ctxt().build(cx.typing_mode()); infcx.predicate_must_hold_modulo_regions(&obligation) }) }; diff --git a/src/tools/clippy/clippy_lints/src/no_effect.rs b/src/tools/clippy/clippy_lints/src/no_effect.rs index 392cfcb813e..2e5195d459f 100644 --- a/src/tools/clippy/clippy_lints/src/no_effect.rs +++ b/src/tools/clippy/clippy_lints/src/no_effect.rs @@ -160,7 +160,7 @@ impl NoEffect { // Remove `impl Future<Output = T>` to get `T` if cx.tcx.ty_is_opaque_future(ret_ty) && let Some(true_ret_ty) = - cx.tcx.infer_ctxt().build().err_ctxt().get_impl_future_output_ty(ret_ty) + cx.tcx.infer_ctxt().build(cx.typing_mode()).err_ctxt().get_impl_future_output_ty(ret_ty) { ret_ty = true_ret_ty; } diff --git a/src/tools/clippy/clippy_lints/src/ptr.rs b/src/tools/clippy/clippy_lints/src/ptr.rs index f5fcf521b96..a548c6ef3b1 100644 --- a/src/tools/clippy/clippy_lints/src/ptr.rs +++ b/src/tools/clippy/clippy_lints/src/ptr.rs @@ -695,7 +695,7 @@ fn matches_preds<'tcx>( ty: Ty<'tcx>, preds: &'tcx [ty::PolyExistentialPredicate<'tcx>], ) -> bool { - let infcx = cx.tcx.infer_ctxt().build(); + let infcx = cx.tcx.infer_ctxt().build(cx.typing_mode()); preds .iter() .all(|&p| match cx.tcx.instantiate_bound_regions_with_erased(p) { diff --git a/src/tools/clippy/clippy_lints/src/useless_conversion.rs b/src/tools/clippy/clippy_lints/src/useless_conversion.rs index ec3a693d2ef..3b05abc546f 100644 --- a/src/tools/clippy/clippy_lints/src/useless_conversion.rs +++ b/src/tools/clippy/clippy_lints/src/useless_conversion.rs @@ -114,7 +114,7 @@ fn into_iter_bound<'tcx>( if !cx .tcx .infer_ctxt() - .build() + .build(cx.typing_mode()) .predicate_must_hold_modulo_regions(&obligation) { return None; diff --git a/src/tools/clippy/clippy_utils/src/hir_utils.rs b/src/tools/clippy/clippy_utils/src/hir_utils.rs index 181d414cbbd..8004bc68b2e 100644 --- a/src/tools/clippy/clippy_utils/src/hir_utils.rs +++ b/src/tools/clippy/clippy_utils/src/hir_utils.rs @@ -1231,16 +1231,13 @@ impl<'a, 'tcx> SpanlessHash<'a, 'tcx> { } }, TyKind::Path(ref qpath) => self.hash_qpath(qpath), - TyKind::OpaqueDef(_, arg_list) => { - self.hash_generic_args(arg_list); - }, TyKind::TraitObject(_, lifetime, _) => { self.hash_lifetime(lifetime); }, TyKind::Typeof(anon_const) => { self.hash_body(anon_const.body); }, - TyKind::Err(_) | TyKind::Infer | TyKind::Never | TyKind::InferDelegation(..) | TyKind::AnonAdt(_) => {}, + TyKind::Err(_) | TyKind::Infer | TyKind::Never | TyKind::InferDelegation(..) | TyKind::OpaqueDef(_) | TyKind::AnonAdt(_) => {}, } } diff --git a/src/tools/clippy/clippy_utils/src/mir/possible_borrower.rs b/src/tools/clippy/clippy_utils/src/mir/possible_borrower.rs index a00196c4b51..6b3078f52af 100644 --- a/src/tools/clippy/clippy_utils/src/mir/possible_borrower.rs +++ b/src/tools/clippy/clippy_utils/src/mir/possible_borrower.rs @@ -185,9 +185,7 @@ impl<'b, 'tcx> PossibleBorrowerMap<'b, 'tcx> { vis.into_map(cx) }; let maybe_storage_live_result = MaybeStorageLive::new(Cow::Owned(BitSet::new_empty(mir.local_decls.len()))) - .into_engine(cx.tcx, mir) - .pass_name("redundant_clone") - .iterate_to_fixpoint() + .iterate_to_fixpoint(cx.tcx, mir, Some("redundant_clone")) .into_results_cursor(mir); let mut vis = PossibleBorrowerVisitor::new(cx, mir, possible_origin); vis.visit_body(mir); diff --git a/src/tools/clippy/clippy_utils/src/qualify_min_const_fn.rs b/src/tools/clippy/clippy_utils/src/qualify_min_const_fn.rs index 46739862de6..dbadc8432f6 100644 --- a/src/tools/clippy/clippy_utils/src/qualify_min_const_fn.rs +++ b/src/tools/clippy/clippy_utils/src/qualify_min_const_fn.rs @@ -17,7 +17,7 @@ use rustc_middle::mir::{ }; use rustc_middle::traits::{BuiltinImplSource, ImplSource, ObligationCause}; use rustc_middle::ty::adjustment::PointerCoercion; -use rustc_middle::ty::{self, GenericArgKind, TraitRef, Ty, TyCtxt}; +use rustc_middle::ty::{self, GenericArgKind, TraitRef, Ty, TyCtxt, TypingMode}; use rustc_span::Span; use rustc_span::symbol::sym; use rustc_trait_selection::traits::{ObligationCtxt, SelectionContext}; @@ -420,7 +420,7 @@ fn is_ty_const_destruct<'tcx>(tcx: TyCtxt<'tcx>, ty: Ty<'tcx>, body: &Body<'tcx> TraitRef::new(tcx, tcx.require_lang_item(LangItem::Destruct, Some(body.span)), [ty]), ); - let infcx = tcx.infer_ctxt().build(); + let infcx = tcx.infer_ctxt().build(TypingMode::from_param_env(obligation.param_env)); let mut selcx = SelectionContext::new(&infcx); let Some(impl_src) = selcx.select(&obligation).ok().flatten() else { return false; diff --git a/src/tools/clippy/clippy_utils/src/ty.rs b/src/tools/clippy/clippy_utils/src/ty.rs index 07c3d0eada0..c618bfe4488 100644 --- a/src/tools/clippy/clippy_utils/src/ty.rs +++ b/src/tools/clippy/clippy_utils/src/ty.rs @@ -19,7 +19,7 @@ use rustc_middle::ty::layout::ValidityRequirement; use rustc_middle::ty::{ self, AdtDef, AliasTy, AssocItem, AssocKind, Binder, BoundRegion, FnSig, GenericArg, GenericArgKind, GenericArgsRef, GenericParamDefKind, IntTy, ParamEnv, Region, RegionKind, TraitRef, Ty, TyCtxt, TypeSuperVisitable, - TypeVisitable, TypeVisitableExt, TypeVisitor, UintTy, Upcast, VariantDef, VariantDiscr, + TypeVisitable, TypeVisitableExt, TypeVisitor, UintTy, Upcast, VariantDef, VariantDiscr, TypingMode, }; use rustc_span::symbol::Ident; use rustc_span::{DUMMY_SP, Span, Symbol, sym}; @@ -268,7 +268,7 @@ pub fn implements_trait_with_env_from_iter<'tcx>( return false; } - let infcx = tcx.infer_ctxt().build(); + let infcx = tcx.infer_ctxt().build(TypingMode::from_param_env(param_env)); let args = args .into_iter() .map(|arg| arg.into().unwrap_or_else(|| infcx.next_ty_var(DUMMY_SP).into())) @@ -362,7 +362,7 @@ fn is_normalizable_helper<'tcx>( } // prevent recursive loops, false-negative is better than endless loop leading to stack overflow cache.insert(ty, false); - let infcx = cx.tcx.infer_ctxt().build(); + let infcx = cx.tcx.infer_ctxt().build(TypingMode::from_param_env(param_env)); let cause = ObligationCause::dummy(); let result = if infcx.at(&cause, param_env).query_normalize(ty).is_ok() { match ty.kind() { @@ -1268,7 +1268,7 @@ pub fn make_normalized_projection_with_regions<'tcx>( let cause = ObligationCause::dummy(); match tcx .infer_ctxt() - .build() + .build(TypingMode::from_param_env(param_env)) .at(&cause, param_env) .query_normalize(Ty::new_projection_from_args(tcx, ty.def_id, ty.args)) { @@ -1284,7 +1284,7 @@ pub fn make_normalized_projection_with_regions<'tcx>( pub fn normalize_with_regions<'tcx>(tcx: TyCtxt<'tcx>, param_env: ParamEnv<'tcx>, ty: Ty<'tcx>) -> Ty<'tcx> { let cause = ObligationCause::dummy(); - match tcx.infer_ctxt().build().at(&cause, param_env).query_normalize(ty) { + match tcx.infer_ctxt().build(TypingMode::from_param_env(param_env)).at(&cause, param_env).query_normalize(ty) { Ok(ty) => ty.value, Err(_) => ty, } diff --git a/src/tools/clippy/tests/ui/cast.rs b/src/tools/clippy/tests/ui/cast.rs index 146b04ab813..0de53a75c62 100644 --- a/src/tools/clippy/tests/ui/cast.rs +++ b/src/tools/clippy/tests/ui/cast.rs @@ -1,7 +1,6 @@ //@no-rustfix #![feature(repr128)] -#![feature(isqrt)] #![allow(incomplete_features)] #![warn( clippy::cast_precision_loss, diff --git a/src/tools/clippy/tests/ui/cast.stderr b/src/tools/clippy/tests/ui/cast.stderr index 7824bdfac25..452482fc88e 100644 --- a/src/tools/clippy/tests/ui/cast.stderr +++ b/src/tools/clippy/tests/ui/cast.stderr @@ -1,5 +1,5 @@ error: casting `i32` to `f32` causes a loss of precision (`i32` is 32 bits wide, but `f32`'s mantissa is only 23 bits wide) - --> tests/ui/cast.rs:26:5 + --> tests/ui/cast.rs:25:5 | LL | x0 as f32; | ^^^^^^^^^ @@ -8,37 +8,37 @@ LL | x0 as f32; = help: to override `-D warnings` add `#[allow(clippy::cast_precision_loss)]` error: casting `i64` to `f32` causes a loss of precision (`i64` is 64 bits wide, but `f32`'s mantissa is only 23 bits wide) - --> tests/ui/cast.rs:30:5 + --> tests/ui/cast.rs:29:5 | LL | x1 as f32; | ^^^^^^^^^ error: casting `i64` to `f64` causes a loss of precision (`i64` is 64 bits wide, but `f64`'s mantissa is only 52 bits wide) - --> tests/ui/cast.rs:32:5 + --> tests/ui/cast.rs:31:5 | LL | x1 as f64; | ^^^^^^^^^ error: casting `u32` to `f32` causes a loss of precision (`u32` is 32 bits wide, but `f32`'s mantissa is only 23 bits wide) - --> tests/ui/cast.rs:35:5 + --> tests/ui/cast.rs:34:5 | LL | x2 as f32; | ^^^^^^^^^ error: casting `u64` to `f32` causes a loss of precision (`u64` is 64 bits wide, but `f32`'s mantissa is only 23 bits wide) - --> tests/ui/cast.rs:38:5 + --> tests/ui/cast.rs:37:5 | LL | x3 as f32; | ^^^^^^^^^ error: casting `u64` to `f64` causes a loss of precision (`u64` is 64 bits wide, but `f64`'s mantissa is only 52 bits wide) - --> tests/ui/cast.rs:40:5 + --> tests/ui/cast.rs:39:5 | LL | x3 as f64; | ^^^^^^^^^ error: casting `f32` to `i32` may truncate the value - --> tests/ui/cast.rs:43:5 + --> tests/ui/cast.rs:42:5 | LL | 1f32 as i32; | ^^^^^^^^^^^ @@ -48,7 +48,7 @@ LL | 1f32 as i32; = help: to override `-D warnings` add `#[allow(clippy::cast_possible_truncation)]` error: casting `f32` to `u32` may truncate the value - --> tests/ui/cast.rs:45:5 + --> tests/ui/cast.rs:44:5 | LL | 1f32 as u32; | ^^^^^^^^^^^ @@ -56,7 +56,7 @@ LL | 1f32 as u32; = help: if this is intentional allow the lint with `#[allow(clippy::cast_possible_truncation)]` ... error: casting `f32` to `u32` may lose the sign of the value - --> tests/ui/cast.rs:45:5 + --> tests/ui/cast.rs:44:5 | LL | 1f32 as u32; | ^^^^^^^^^^^ @@ -65,7 +65,7 @@ LL | 1f32 as u32; = help: to override `-D warnings` add `#[allow(clippy::cast_sign_loss)]` error: casting `f64` to `f32` may truncate the value - --> tests/ui/cast.rs:49:5 + --> tests/ui/cast.rs:48:5 | LL | 1f64 as f32; | ^^^^^^^^^^^ @@ -73,7 +73,7 @@ LL | 1f64 as f32; = help: if this is intentional allow the lint with `#[allow(clippy::cast_possible_truncation)]` ... error: casting `i32` to `i8` may truncate the value - --> tests/ui/cast.rs:51:5 + --> tests/ui/cast.rs:50:5 | LL | 1i32 as i8; | ^^^^^^^^^^ @@ -85,7 +85,7 @@ LL | i8::try_from(1i32); | ~~~~~~~~~~~~~~~~~~ error: casting `i32` to `u8` may truncate the value - --> tests/ui/cast.rs:53:5 + --> tests/ui/cast.rs:52:5 | LL | 1i32 as u8; | ^^^^^^^^^^ @@ -97,7 +97,7 @@ LL | u8::try_from(1i32); | ~~~~~~~~~~~~~~~~~~ error: casting `f64` to `isize` may truncate the value - --> tests/ui/cast.rs:55:5 + --> tests/ui/cast.rs:54:5 | LL | 1f64 as isize; | ^^^^^^^^^^^^^ @@ -105,7 +105,7 @@ LL | 1f64 as isize; = help: if this is intentional allow the lint with `#[allow(clippy::cast_possible_truncation)]` ... error: casting `f64` to `usize` may truncate the value - --> tests/ui/cast.rs:57:5 + --> tests/ui/cast.rs:56:5 | LL | 1f64 as usize; | ^^^^^^^^^^^^^ @@ -113,13 +113,13 @@ LL | 1f64 as usize; = help: if this is intentional allow the lint with `#[allow(clippy::cast_possible_truncation)]` ... error: casting `f64` to `usize` may lose the sign of the value - --> tests/ui/cast.rs:57:5 + --> tests/ui/cast.rs:56:5 | LL | 1f64 as usize; | ^^^^^^^^^^^^^ error: casting `u32` to `u16` may truncate the value - --> tests/ui/cast.rs:60:5 + --> tests/ui/cast.rs:59:5 | LL | 1f32 as u32 as u16; | ^^^^^^^^^^^^^^^^^^ @@ -131,7 +131,7 @@ LL | u16::try_from(1f32 as u32); | ~~~~~~~~~~~~~~~~~~~~~~~~~~ error: casting `f32` to `u32` may truncate the value - --> tests/ui/cast.rs:60:5 + --> tests/ui/cast.rs:59:5 | LL | 1f32 as u32 as u16; | ^^^^^^^^^^^ @@ -139,13 +139,13 @@ LL | 1f32 as u32 as u16; = help: if this is intentional allow the lint with `#[allow(clippy::cast_possible_truncation)]` ... error: casting `f32` to `u32` may lose the sign of the value - --> tests/ui/cast.rs:60:5 + --> tests/ui/cast.rs:59:5 | LL | 1f32 as u32 as u16; | ^^^^^^^^^^^ error: casting `i32` to `i8` may truncate the value - --> tests/ui/cast.rs:65:22 + --> tests/ui/cast.rs:64:22 | LL | let _x: i8 = 1i32 as _; | ^^^^^^^^^ @@ -157,7 +157,7 @@ LL | let _x: i8 = 1i32.try_into(); | ~~~~~~~~~~~~~~~ error: casting `f32` to `i32` may truncate the value - --> tests/ui/cast.rs:67:9 + --> tests/ui/cast.rs:66:9 | LL | 1f32 as i32; | ^^^^^^^^^^^ @@ -165,7 +165,7 @@ LL | 1f32 as i32; = help: if this is intentional allow the lint with `#[allow(clippy::cast_possible_truncation)]` ... error: casting `f64` to `i32` may truncate the value - --> tests/ui/cast.rs:69:9 + --> tests/ui/cast.rs:68:9 | LL | 1f64 as i32; | ^^^^^^^^^^^ @@ -173,7 +173,7 @@ LL | 1f64 as i32; = help: if this is intentional allow the lint with `#[allow(clippy::cast_possible_truncation)]` ... error: casting `f32` to `u8` may truncate the value - --> tests/ui/cast.rs:71:9 + --> tests/ui/cast.rs:70:9 | LL | 1f32 as u8; | ^^^^^^^^^^ @@ -181,13 +181,13 @@ LL | 1f32 as u8; = help: if this is intentional allow the lint with `#[allow(clippy::cast_possible_truncation)]` ... error: casting `f32` to `u8` may lose the sign of the value - --> tests/ui/cast.rs:71:9 + --> tests/ui/cast.rs:70:9 | LL | 1f32 as u8; | ^^^^^^^^^^ error: casting `u8` to `i8` may wrap around the value - --> tests/ui/cast.rs:76:5 + --> tests/ui/cast.rs:75:5 | LL | 1u8 as i8; | ^^^^^^^^^ @@ -196,31 +196,31 @@ LL | 1u8 as i8; = help: to override `-D warnings` add `#[allow(clippy::cast_possible_wrap)]` error: casting `u16` to `i16` may wrap around the value - --> tests/ui/cast.rs:79:5 + --> tests/ui/cast.rs:78:5 | LL | 1u16 as i16; | ^^^^^^^^^^^ error: casting `u32` to `i32` may wrap around the value - --> tests/ui/cast.rs:81:5 + --> tests/ui/cast.rs:80:5 | LL | 1u32 as i32; | ^^^^^^^^^^^ error: casting `u64` to `i64` may wrap around the value - --> tests/ui/cast.rs:83:5 + --> tests/ui/cast.rs:82:5 | LL | 1u64 as i64; | ^^^^^^^^^^^ error: casting `usize` to `isize` may wrap around the value - --> tests/ui/cast.rs:85:5 + --> tests/ui/cast.rs:84:5 | LL | 1usize as isize; | ^^^^^^^^^^^^^^^ error: casting `usize` to `i8` may truncate the value - --> tests/ui/cast.rs:88:5 + --> tests/ui/cast.rs:87:5 | LL | 1usize as i8; | ^^^^^^^^^^^^ @@ -232,7 +232,7 @@ LL | i8::try_from(1usize); | ~~~~~~~~~~~~~~~~~~~~ error: casting `usize` to `i16` may truncate the value - --> tests/ui/cast.rs:91:5 + --> tests/ui/cast.rs:90:5 | LL | 1usize as i16; | ^^^^^^^^^^^^^ @@ -244,7 +244,7 @@ LL | i16::try_from(1usize); | ~~~~~~~~~~~~~~~~~~~~~ error: casting `usize` to `i16` may wrap around the value on targets with 16-bit wide pointers - --> tests/ui/cast.rs:91:5 + --> tests/ui/cast.rs:90:5 | LL | 1usize as i16; | ^^^^^^^^^^^^^ @@ -253,7 +253,7 @@ LL | 1usize as i16; = note: for more information see https://doc.rust-lang.org/reference/types/numeric.html#machine-dependent-integer-types error: casting `usize` to `i32` may truncate the value on targets with 64-bit wide pointers - --> tests/ui/cast.rs:96:5 + --> tests/ui/cast.rs:95:5 | LL | 1usize as i32; | ^^^^^^^^^^^^^ @@ -265,19 +265,19 @@ LL | i32::try_from(1usize); | ~~~~~~~~~~~~~~~~~~~~~ error: casting `usize` to `i32` may wrap around the value on targets with 32-bit wide pointers - --> tests/ui/cast.rs:96:5 + --> tests/ui/cast.rs:95:5 | LL | 1usize as i32; | ^^^^^^^^^^^^^ error: casting `usize` to `i64` may wrap around the value on targets with 64-bit wide pointers - --> tests/ui/cast.rs:100:5 + --> tests/ui/cast.rs:99:5 | LL | 1usize as i64; | ^^^^^^^^^^^^^ error: casting `u16` to `isize` may wrap around the value on targets with 16-bit wide pointers - --> tests/ui/cast.rs:105:5 + --> tests/ui/cast.rs:104:5 | LL | 1u16 as isize; | ^^^^^^^^^^^^^ @@ -286,13 +286,13 @@ LL | 1u16 as isize; = note: for more information see https://doc.rust-lang.org/reference/types/numeric.html#machine-dependent-integer-types error: casting `u32` to `isize` may wrap around the value on targets with 32-bit wide pointers - --> tests/ui/cast.rs:109:5 + --> tests/ui/cast.rs:108:5 | LL | 1u32 as isize; | ^^^^^^^^^^^^^ error: casting `u64` to `isize` may truncate the value on targets with 32-bit wide pointers - --> tests/ui/cast.rs:112:5 + --> tests/ui/cast.rs:111:5 | LL | 1u64 as isize; | ^^^^^^^^^^^^^ @@ -304,55 +304,55 @@ LL | isize::try_from(1u64); | ~~~~~~~~~~~~~~~~~~~~~ error: casting `u64` to `isize` may wrap around the value on targets with 64-bit wide pointers - --> tests/ui/cast.rs:112:5 + --> tests/ui/cast.rs:111:5 | LL | 1u64 as isize; | ^^^^^^^^^^^^^ error: casting `i32` to `u32` may lose the sign of the value - --> tests/ui/cast.rs:117:5 + --> tests/ui/cast.rs:116:5 | LL | -1i32 as u32; | ^^^^^^^^^^^^ error: casting `isize` to `usize` may lose the sign of the value - --> tests/ui/cast.rs:120:5 + --> tests/ui/cast.rs:119:5 | LL | -1isize as usize; | ^^^^^^^^^^^^^^^^ error: casting `i8` to `u8` may lose the sign of the value - --> tests/ui/cast.rs:131:5 + --> tests/ui/cast.rs:130:5 | LL | (i8::MIN).abs() as u8; | ^^^^^^^^^^^^^^^^^^^^^ error: casting `i64` to `u64` may lose the sign of the value - --> tests/ui/cast.rs:135:5 + --> tests/ui/cast.rs:134:5 | LL | (-1i64).abs() as u64; | ^^^^^^^^^^^^^^^^^^^^ error: casting `isize` to `usize` may lose the sign of the value - --> tests/ui/cast.rs:136:5 + --> tests/ui/cast.rs:135:5 | LL | (-1isize).abs() as usize; | ^^^^^^^^^^^^^^^^^^^^^^^^ error: casting `i64` to `u64` may lose the sign of the value - --> tests/ui/cast.rs:143:5 + --> tests/ui/cast.rs:142:5 | LL | (unsafe { (-1i64).checked_abs().unwrap_unchecked() }) as u64; | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ error: casting `i64` to `u64` may lose the sign of the value - --> tests/ui/cast.rs:158:5 + --> tests/ui/cast.rs:157:5 | LL | (unsafe { (-1i64).checked_isqrt().unwrap_unchecked() }) as u64; | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ error: casting `i64` to `i8` may truncate the value - --> tests/ui/cast.rs:209:5 + --> tests/ui/cast.rs:208:5 | LL | (-99999999999i64).min(1) as i8; | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ @@ -364,7 +364,7 @@ LL | i8::try_from((-99999999999i64).min(1)); | ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ error: casting `u64` to `u8` may truncate the value - --> tests/ui/cast.rs:223:5 + --> tests/ui/cast.rs:222:5 | LL | 999999u64.clamp(0, 256) as u8; | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ @@ -376,7 +376,7 @@ LL | u8::try_from(999999u64.clamp(0, 256)); | ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ error: casting `main::E2` to `u8` may truncate the value - --> tests/ui/cast.rs:246:21 + --> tests/ui/cast.rs:245:21 | LL | let _ = self as u8; | ^^^^^^^^^^ @@ -388,7 +388,7 @@ LL | let _ = u8::try_from(self); | ~~~~~~~~~~~~~~~~~~ error: casting `main::E2::B` to `u8` will truncate the value - --> tests/ui/cast.rs:248:21 + --> tests/ui/cast.rs:247:21 | LL | let _ = Self::B as u8; | ^^^^^^^^^^^^^ @@ -397,7 +397,7 @@ LL | let _ = Self::B as u8; = help: to override `-D warnings` add `#[allow(clippy::cast_enum_truncation)]` error: casting `main::E5` to `i8` may truncate the value - --> tests/ui/cast.rs:290:21 + --> tests/ui/cast.rs:289:21 | LL | let _ = self as i8; | ^^^^^^^^^^ @@ -409,13 +409,13 @@ LL | let _ = i8::try_from(self); | ~~~~~~~~~~~~~~~~~~ error: casting `main::E5::A` to `i8` will truncate the value - --> tests/ui/cast.rs:292:21 + --> tests/ui/cast.rs:291:21 | LL | let _ = Self::A as i8; | ^^^^^^^^^^^^^ error: casting `main::E6` to `i16` may truncate the value - --> tests/ui/cast.rs:309:21 + --> tests/ui/cast.rs:308:21 | LL | let _ = self as i16; | ^^^^^^^^^^^ @@ -427,7 +427,7 @@ LL | let _ = i16::try_from(self); | ~~~~~~~~~~~~~~~~~~~ error: casting `main::E7` to `usize` may truncate the value on targets with 32-bit wide pointers - --> tests/ui/cast.rs:328:21 + --> tests/ui/cast.rs:327:21 | LL | let _ = self as usize; | ^^^^^^^^^^^^^ @@ -439,7 +439,7 @@ LL | let _ = usize::try_from(self); | ~~~~~~~~~~~~~~~~~~~~~ error: casting `main::E10` to `u16` may truncate the value - --> tests/ui/cast.rs:375:21 + --> tests/ui/cast.rs:374:21 | LL | let _ = self as u16; | ^^^^^^^^^^^ @@ -451,7 +451,7 @@ LL | let _ = u16::try_from(self); | ~~~~~~~~~~~~~~~~~~~ error: casting `u32` to `u8` may truncate the value - --> tests/ui/cast.rs:386:13 + --> tests/ui/cast.rs:385:13 | LL | let c = (q >> 16) as u8; | ^^^^^^^^^^^^^^^ @@ -463,7 +463,7 @@ LL | let c = u8::try_from(q >> 16); | ~~~~~~~~~~~~~~~~~~~~~ error: casting `u32` to `u8` may truncate the value - --> tests/ui/cast.rs:390:13 + --> tests/ui/cast.rs:389:13 | LL | let c = (q / 1000) as u8; | ^^^^^^^^^^^^^^^^ @@ -475,85 +475,85 @@ LL | let c = u8::try_from(q / 1000); | ~~~~~~~~~~~~~~~~~~~~~~ error: casting `i32` to `u32` may lose the sign of the value - --> tests/ui/cast.rs:402:9 + --> tests/ui/cast.rs:401:9 | LL | (x * x) as u32; | ^^^^^^^^^^^^^^ error: casting `i32` to `u32` may lose the sign of the value - --> tests/ui/cast.rs:407:32 + --> tests/ui/cast.rs:406:32 | LL | let _a = |x: i32| -> u32 { (x * x * x * x) as u32 }; | ^^^^^^^^^^^^^^^^^^^^^^ error: casting `i32` to `u32` may lose the sign of the value - --> tests/ui/cast.rs:409:5 + --> tests/ui/cast.rs:408:5 | LL | (2_i32).checked_pow(3).unwrap() as u32; | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ error: casting `i32` to `u32` may lose the sign of the value - --> tests/ui/cast.rs:410:5 + --> tests/ui/cast.rs:409:5 | LL | (-2_i32).pow(3) as u32; | ^^^^^^^^^^^^^^^^^^^^^^ error: casting `i32` to `u32` may lose the sign of the value - --> tests/ui/cast.rs:415:5 + --> tests/ui/cast.rs:414:5 | LL | (-5_i32 % 2) as u32; | ^^^^^^^^^^^^^^^^^^^ error: casting `i32` to `u32` may lose the sign of the value - --> tests/ui/cast.rs:417:5 + --> tests/ui/cast.rs:416:5 | LL | (-5_i32 % -2) as u32; | ^^^^^^^^^^^^^^^^^^^^ error: casting `i32` to `u32` may lose the sign of the value - --> tests/ui/cast.rs:420:5 + --> tests/ui/cast.rs:419:5 | LL | (-2_i32 >> 1) as u32; | ^^^^^^^^^^^^^^^^^^^^ error: casting `i32` to `u32` may lose the sign of the value - --> tests/ui/cast.rs:424:5 + --> tests/ui/cast.rs:423:5 | LL | (x * x) as u32; | ^^^^^^^^^^^^^^ error: casting `i32` to `u32` may lose the sign of the value - --> tests/ui/cast.rs:425:5 + --> tests/ui/cast.rs:424:5 | LL | (x * x * x) as u32; | ^^^^^^^^^^^^^^^^^^ error: casting `i16` to `u16` may lose the sign of the value - --> tests/ui/cast.rs:429:5 + --> tests/ui/cast.rs:428:5 | LL | (y * y * y * y * -2) as u16; | ^^^^^^^^^^^^^^^^^^^^^^^^^^^ error: casting `i16` to `u16` may lose the sign of the value - --> tests/ui/cast.rs:431:5 + --> tests/ui/cast.rs:430:5 | LL | (y * y * y / y * 2) as u16; | ^^^^^^^^^^^^^^^^^^^^^^^^^^ error: casting `i16` to `u16` may lose the sign of the value - --> tests/ui/cast.rs:432:5 + --> tests/ui/cast.rs:431:5 | LL | (y * y / y * 2) as u16; | ^^^^^^^^^^^^^^^^^^^^^^ error: casting `i16` to `u16` may lose the sign of the value - --> tests/ui/cast.rs:434:5 + --> tests/ui/cast.rs:433:5 | LL | (y / y * y * -2) as u16; | ^^^^^^^^^^^^^^^^^^^^^^^ error: equal expressions as operands to `/` - --> tests/ui/cast.rs:434:6 + --> tests/ui/cast.rs:433:6 | LL | (y / y * y * -2) as u16; | ^^^^^ @@ -561,97 +561,97 @@ LL | (y / y * y * -2) as u16; = note: `#[deny(clippy::eq_op)]` on by default error: casting `i16` to `u16` may lose the sign of the value - --> tests/ui/cast.rs:437:5 + --> tests/ui/cast.rs:436:5 | LL | (y + y + y + -2) as u16; | ^^^^^^^^^^^^^^^^^^^^^^^ error: casting `i16` to `u16` may lose the sign of the value - --> tests/ui/cast.rs:439:5 + --> tests/ui/cast.rs:438:5 | LL | (y + y + y + 2) as u16; | ^^^^^^^^^^^^^^^^^^^^^^ error: casting `i16` to `u16` may lose the sign of the value - --> tests/ui/cast.rs:443:5 + --> tests/ui/cast.rs:442:5 | LL | (z + -2) as u16; | ^^^^^^^^^^^^^^^ error: casting `i16` to `u16` may lose the sign of the value - --> tests/ui/cast.rs:445:5 + --> tests/ui/cast.rs:444:5 | LL | (z + z + 2) as u16; | ^^^^^^^^^^^^^^^^^^ error: casting `i32` to `u32` may lose the sign of the value - --> tests/ui/cast.rs:448:9 + --> tests/ui/cast.rs:447:9 | LL | (a * a * b * b * c * c) as u32; | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ error: casting `i32` to `u32` may lose the sign of the value - --> tests/ui/cast.rs:449:9 + --> tests/ui/cast.rs:448:9 | LL | (a * b * c) as u32; | ^^^^^^^^^^^^^^^^^^ error: casting `i32` to `u32` may lose the sign of the value - --> tests/ui/cast.rs:451:9 + --> tests/ui/cast.rs:450:9 | LL | (a * -b * c) as u32; | ^^^^^^^^^^^^^^^^^^^ error: casting `i32` to `u32` may lose the sign of the value - --> tests/ui/cast.rs:453:9 + --> tests/ui/cast.rs:452:9 | LL | (a * b * c * c) as u32; | ^^^^^^^^^^^^^^^^^^^^^^ error: casting `i32` to `u32` may lose the sign of the value - --> tests/ui/cast.rs:454:9 + --> tests/ui/cast.rs:453:9 | LL | (a * -2) as u32; | ^^^^^^^^^^^^^^^ error: casting `i32` to `u32` may lose the sign of the value - --> tests/ui/cast.rs:456:9 + --> tests/ui/cast.rs:455:9 | LL | (a * b * c * -2) as u32; | ^^^^^^^^^^^^^^^^^^^^^^^ error: casting `i32` to `u32` may lose the sign of the value - --> tests/ui/cast.rs:458:9 + --> tests/ui/cast.rs:457:9 | LL | (a / b) as u32; | ^^^^^^^^^^^^^^ error: casting `i32` to `u32` may lose the sign of the value - --> tests/ui/cast.rs:459:9 + --> tests/ui/cast.rs:458:9 | LL | (a / b * c) as u32; | ^^^^^^^^^^^^^^^^^^ error: casting `i32` to `u32` may lose the sign of the value - --> tests/ui/cast.rs:461:9 + --> tests/ui/cast.rs:460:9 | LL | (a / b + b * c) as u32; | ^^^^^^^^^^^^^^^^^^^^^^ error: casting `i32` to `u32` may lose the sign of the value - --> tests/ui/cast.rs:463:9 + --> tests/ui/cast.rs:462:9 | LL | a.saturating_pow(3) as u32; | ^^^^^^^^^^^^^^^^^^^^^^^^^^ error: casting `i32` to `u32` may lose the sign of the value - --> tests/ui/cast.rs:465:9 + --> tests/ui/cast.rs:464:9 | LL | (a.abs() * b.pow(2) / c.abs()) as u32 | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ error: casting `i32` to `u32` may lose the sign of the value - --> tests/ui/cast.rs:473:21 + --> tests/ui/cast.rs:472:21 | LL | let _ = i32::MIN as u32; // cast_sign_loss | ^^^^^^^^^^^^^^^ @@ -662,7 +662,7 @@ LL | m!(); = note: this error originates in the macro `m` (in Nightly builds, run with -Z macro-backtrace for more info) error: casting `u32` to `u8` may truncate the value - --> tests/ui/cast.rs:474:21 + --> tests/ui/cast.rs:473:21 | LL | let _ = u32::MAX as u8; // cast_possible_truncation | ^^^^^^^^^^^^^^ @@ -678,7 +678,7 @@ LL | let _ = u8::try_from(u32::MAX); // cast_possible_truncation | ~~~~~~~~~~~~~~~~~~~~~~ error: casting `f64` to `f32` may truncate the value - --> tests/ui/cast.rs:475:21 + --> tests/ui/cast.rs:474:21 | LL | let _ = std::f64::consts::PI as f32; // cast_possible_truncation | ^^^^^^^^^^^^^^^^^^^^^^^^^^^ @@ -690,7 +690,7 @@ LL | m!(); = note: this error originates in the macro `m` (in Nightly builds, run with -Z macro-backtrace for more info) error: casting `i64` to `usize` may truncate the value on targets with 32-bit wide pointers - --> tests/ui/cast.rs:484:5 + --> tests/ui/cast.rs:483:5 | LL | bar.unwrap().unwrap() as usize | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ @@ -702,13 +702,13 @@ LL | usize::try_from(bar.unwrap().unwrap()) | error: casting `i64` to `usize` may lose the sign of the value - --> tests/ui/cast.rs:484:5 + --> tests/ui/cast.rs:483:5 | LL | bar.unwrap().unwrap() as usize | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ error: casting `u64` to `u8` may truncate the value - --> tests/ui/cast.rs:499:5 + --> tests/ui/cast.rs:498:5 | LL | (256 & 999999u64) as u8; | ^^^^^^^^^^^^^^^^^^^^^^^ @@ -720,7 +720,7 @@ LL | u8::try_from(256 & 999999u64); | ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ error: casting `u64` to `u8` may truncate the value - --> tests/ui/cast.rs:501:5 + --> tests/ui/cast.rs:500:5 | LL | (255 % 999999u64) as u8; | ^^^^^^^^^^^^^^^^^^^^^^^ diff --git a/src/tools/clippy/tests/ui/issue_4266.stderr b/src/tools/clippy/tests/ui/issue_4266.stderr index c0e81791589..63c568a153b 100644 --- a/src/tools/clippy/tests/ui/issue_4266.stderr +++ b/src/tools/clippy/tests/ui/issue_4266.stderr @@ -11,7 +11,7 @@ error: the following explicit lifetimes could be elided: 'a --> tests/ui/issue_4266.rs:10:21 | LL | async fn one_to_one<'a>(s: &'a str) -> &'a str { - | ^^ ^^ + | ^^ ^^ ^^ error: methods called `new` usually take no `self` --> tests/ui/issue_4266.rs:31:22 diff --git a/src/tools/clippy/tests/ui/rename.fixed b/src/tools/clippy/tests/ui/rename.fixed index b810fd8224f..0d6e07aa546 100644 --- a/src/tools/clippy/tests/ui/rename.fixed +++ b/src/tools/clippy/tests/ui/rename.fixed @@ -54,7 +54,7 @@ #![allow(enum_intrinsics_non_enums)] #![allow(non_fmt_panics)] #![allow(named_arguments_used_positionally)] -#![allow(temporary_cstring_as_ptr)] +#![allow(dangling_pointers_from_temporaries)] #![allow(undropped_manually_drops)] #![allow(unknown_lints)] #![allow(unused_labels)] @@ -120,7 +120,7 @@ #![warn(unexpected_cfgs)] //~ ERROR: lint `clippy::mismatched_target_os` #![warn(non_fmt_panics)] //~ ERROR: lint `clippy::panic_params` #![warn(named_arguments_used_positionally)] //~ ERROR: lint `clippy::positional_named_format_parameters` -#![warn(temporary_cstring_as_ptr)] //~ ERROR: lint `clippy::temporary_cstring_as_ptr` +#![warn(dangling_pointers_from_temporaries)] //~ ERROR: lint `clippy::temporary_cstring_as_ptr` #![warn(undropped_manually_drops)] //~ ERROR: lint `clippy::undropped_manually_drops` #![warn(unknown_lints)] //~ ERROR: lint `clippy::unknown_clippy_lints` #![warn(unused_labels)] //~ ERROR: lint `clippy::unused_label` diff --git a/src/tools/clippy/tests/ui/rename.stderr b/src/tools/clippy/tests/ui/rename.stderr index 46d9f0fac59..b906079d7df 100644 --- a/src/tools/clippy/tests/ui/rename.stderr +++ b/src/tools/clippy/tests/ui/rename.stderr @@ -1,11 +1,17 @@ +error: lint `temporary_cstring_as_ptr` has been renamed to `dangling_pointers_from_temporaries` + --> tests/ui/rename.rs:57:10 + | +LL | #![allow(temporary_cstring_as_ptr)] + | ^^^^^^^^^^^^^^^^^^^^^^^^ help: use the new name: `dangling_pointers_from_temporaries` + | + = note: `-D renamed-and-removed-lints` implied by `-D warnings` + = help: to override `-D warnings` add `#[allow(renamed_and_removed_lints)]` + error: lint `clippy::almost_complete_letter_range` has been renamed to `clippy::almost_complete_range` --> tests/ui/rename.rs:63:9 | LL | #![warn(clippy::almost_complete_letter_range)] | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: use the new name: `clippy::almost_complete_range` - | - = note: `-D renamed-and-removed-lints` implied by `-D warnings` - = help: to override `-D warnings` add `#[allow(renamed_and_removed_lints)]` error: lint `clippy::blacklisted_name` has been renamed to `clippy::disallowed_names` --> tests/ui/rename.rs:64:9 @@ -361,11 +367,11 @@ error: lint `clippy::positional_named_format_parameters` has been renamed to `na LL | #![warn(clippy::positional_named_format_parameters)] | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: use the new name: `named_arguments_used_positionally` -error: lint `clippy::temporary_cstring_as_ptr` has been renamed to `temporary_cstring_as_ptr` +error: lint `clippy::temporary_cstring_as_ptr` has been renamed to `dangling_pointers_from_temporaries` --> tests/ui/rename.rs:123:9 | LL | #![warn(clippy::temporary_cstring_as_ptr)] - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: use the new name: `temporary_cstring_as_ptr` + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: use the new name: `dangling_pointers_from_temporaries` error: lint `clippy::undropped_manually_drops` has been renamed to `undropped_manually_drops` --> tests/ui/rename.rs:124:9 @@ -397,5 +403,5 @@ error: lint `clippy::reverse_range_loop` has been renamed to `clippy::reversed_e LL | #![warn(clippy::reverse_range_loop)] | ^^^^^^^^^^^^^^^^^^^^^^^^^^ help: use the new name: `clippy::reversed_empty_ranges` -error: aborting due to 66 previous errors +error: aborting due to 67 previous errors diff --git a/src/tools/compiletest/Cargo.toml b/src/tools/compiletest/Cargo.toml index b6a89dd49e6..cef6b525a7b 100644 --- a/src/tools/compiletest/Cargo.toml +++ b/src/tools/compiletest/Cargo.toml @@ -18,6 +18,7 @@ build_helper = { path = "../build_helper" } tracing = "0.1" tracing-subscriber = { version = "0.3.3", default-features = false, features = ["fmt", "env-filter", "smallvec", "parking_lot", "ansi"] } regex = "1.0" +semver = { version = "1.0.23", features = ["serde"] } serde = { version = "1.0", features = ["derive"] } serde_json = "1.0" rustfix = "0.8.1" diff --git a/src/tools/compiletest/src/common.rs b/src/tools/compiletest/src/common.rs index 69ac4644941..e82b88eef79 100644 --- a/src/tools/compiletest/src/common.rs +++ b/src/tools/compiletest/src/common.rs @@ -7,6 +7,7 @@ use std::sync::OnceLock; use std::{fmt, iter}; use build_helper::git::GitConfig; +use semver::Version; use serde::de::{Deserialize, Deserializer, Error as _}; use test::{ColorConfig, OutputFormat}; @@ -298,7 +299,7 @@ pub struct Config { pub lldb_version: Option<u32>, /// Version of LLVM - pub llvm_version: Option<u32>, + pub llvm_version: Option<Version>, /// Is LLVM a system LLVM pub system_llvm: bool, diff --git a/src/tools/compiletest/src/command-list.rs b/src/tools/compiletest/src/directive-list.rs index 4d57907f26f..4d57907f26f 100644 --- a/src/tools/compiletest/src/command-list.rs +++ b/src/tools/compiletest/src/directive-list.rs diff --git a/src/tools/compiletest/src/header.rs b/src/tools/compiletest/src/header.rs index d75cdefe635..bfcdd747eb4 100644 --- a/src/tools/compiletest/src/header.rs +++ b/src/tools/compiletest/src/header.rs @@ -6,6 +6,7 @@ use std::io::prelude::*; use std::path::{Path, PathBuf}; use std::process::Command; +use semver::Version; use tracing::*; use crate::common::{Config, Debugger, FailMode, Mode, PassMode}; @@ -709,11 +710,11 @@ fn line_directive<'line>( Some(DirectiveLine { line_number, revision, raw_directive }) } -// To prevent duplicating the list of commmands between `compiletest`,`htmldocck` and `jsondocck`, +// To prevent duplicating the list of directives between `compiletest`,`htmldocck` and `jsondocck`, // we put it into a common file which is included in rust code and parsed here. // FIXME: This setup is temporary until we figure out how to improve this situation. // See <https://github.com/rust-lang/rust/issues/125813#issuecomment-2141953780>. -include!("command-list.rs"); +include!("directive-list.rs"); const KNOWN_HTMLDOCCK_DIRECTIVE_NAMES: &[&str] = &[ "count", @@ -1113,26 +1114,39 @@ fn parse_normalize_rule(header: &str) -> Option<(String, String)> { Some((regex, replacement)) } -pub fn extract_llvm_version(version: &str) -> Option<u32> { - let pat = |c: char| !c.is_ascii_digit() && c != '.'; - let version_without_suffix = match version.find(pat) { - Some(pos) => &version[..pos], +/// Given an llvm version string that looks like `1.2.3-rc1`, extract as semver. Note that this +/// accepts more than just strict `semver` syntax (as in `major.minor.patch`); this permits omitting +/// minor and patch version components so users can write e.g. `//@ min-llvm-version: 19` instead of +/// having to write `//@ min-llvm-version: 19.0.0`. +/// +/// Currently panics if the input string is malformed, though we really should not use panic as an +/// error handling strategy. +/// +/// FIXME(jieyouxu): improve error handling +pub fn extract_llvm_version(version: &str) -> Version { + // The version substring we're interested in usually looks like the `1.2.3`, without any of the + // fancy suffix like `-rc1` or `meow`. + let version = version.trim(); + let uninterested = |c: char| !c.is_ascii_digit() && c != '.'; + let version_without_suffix = match version.split_once(uninterested) { + Some((prefix, _suffix)) => prefix, None => version, }; - let components: Vec<u32> = version_without_suffix + + let components: Vec<u64> = version_without_suffix .split('.') - .map(|s| s.parse().expect("Malformed version component")) + .map(|s| s.parse().expect("llvm version component should consist of only digits")) .collect(); - let version = match *components { - [a] => a * 10_000, - [a, b] => a * 10_000 + b * 100, - [a, b, c] => a * 10_000 + b * 100 + c, - _ => panic!("Malformed version"), - }; - Some(version) + + match &components[..] { + [major] => Version::new(*major, 0, 0), + [major, minor] => Version::new(*major, *minor, 0), + [major, minor, patch] => Version::new(*major, *minor, *patch), + _ => panic!("malformed llvm version string, expected only 1-3 components: {version}"), + } } -pub fn extract_llvm_version_from_binary(binary_path: &str) -> Option<u32> { +pub fn extract_llvm_version_from_binary(binary_path: &str) -> Option<Version> { let output = Command::new(binary_path).arg("--version").output().ok()?; if !output.status.success() { return None; @@ -1140,7 +1154,7 @@ pub fn extract_llvm_version_from_binary(binary_path: &str) -> Option<u32> { let version = String::from_utf8(output.stdout).ok()?; for line in version.lines() { if let Some(version) = line.split("LLVM version ").nth(1) { - return extract_llvm_version(version); + return Some(extract_llvm_version(version)); } } None @@ -1247,15 +1261,17 @@ pub fn llvm_has_libzstd(config: &Config) -> bool { false } -/// Takes a directive of the form `"<version1> [- <version2>]"`, -/// returns the numeric representation of `<version1>` and `<version2>` as -/// tuple: `(<version1> as u32, <version2> as u32)`. +/// Takes a directive of the form `"<version1> [- <version2>]"`, returns the numeric representation +/// of `<version1>` and `<version2>` as tuple: `(<version1>, <version2>)`. /// -/// If the `<version2>` part is omitted, the second component of the tuple -/// is the same as `<version1>`. -fn extract_version_range<F>(line: &str, parse: F) -> Option<(u32, u32)> +/// If the `<version2>` part is omitted, the second component of the tuple is the same as +/// `<version1>`. +fn extract_version_range<'a, F, VersionTy: Clone>( + line: &'a str, + parse: F, +) -> Option<(VersionTy, VersionTy)> where - F: Fn(&str) -> Option<u32>, + F: Fn(&'a str) -> Option<VersionTy>, { let mut splits = line.splitn(2, "- ").map(str::trim); let min = splits.next().unwrap(); @@ -1273,7 +1289,7 @@ where let max = match max { Some("") => return None, Some(max) => parse(max)?, - _ => min, + _ => min.clone(), }; Some((min, max)) @@ -1489,43 +1505,55 @@ fn ignore_llvm(config: &Config, line: &str) -> IgnoreDecision { }; } } - if let Some(actual_version) = config.llvm_version { - if let Some(rest) = line.strip_prefix("min-llvm-version:").map(str::trim) { - let min_version = extract_llvm_version(rest).unwrap(); - // Ignore if actual version is smaller the minimum required - // version - if actual_version < min_version { + if let Some(actual_version) = &config.llvm_version { + // Note that these `min` versions will check for not just major versions. + + if let Some(version_string) = config.parse_name_value_directive(line, "min-llvm-version") { + let min_version = extract_llvm_version(&version_string); + // Ignore if actual version is smaller than the minimum required version. + if *actual_version < min_version { return IgnoreDecision::Ignore { - reason: format!("ignored when the LLVM version is older than {rest}"), + reason: format!( + "ignored when the LLVM version {actual_version} is older than {min_version}" + ), }; } - } else if let Some(rest) = line.strip_prefix("min-system-llvm-version:").map(str::trim) { - let min_version = extract_llvm_version(rest).unwrap(); + } else if let Some(version_string) = + config.parse_name_value_directive(line, "min-system-llvm-version") + { + let min_version = extract_llvm_version(&version_string); // Ignore if using system LLVM and actual version // is smaller the minimum required version - if config.system_llvm && actual_version < min_version { + if config.system_llvm && *actual_version < min_version { return IgnoreDecision::Ignore { - reason: format!("ignored when the system LLVM version is older than {rest}"), + reason: format!( + "ignored when the system LLVM version {actual_version} is older than {min_version}" + ), }; } - } else if let Some(rest) = line.strip_prefix("ignore-llvm-version:").map(str::trim) { + } else if let Some(version_range) = + config.parse_name_value_directive(line, "ignore-llvm-version") + { // Syntax is: "ignore-llvm-version: <version1> [- <version2>]" let (v_min, v_max) = - extract_version_range(rest, extract_llvm_version).unwrap_or_else(|| { - panic!("couldn't parse version range: {:?}", rest); - }); + extract_version_range(&version_range, |s| Some(extract_llvm_version(s))) + .unwrap_or_else(|| { + panic!("couldn't parse version range: \"{version_range}\""); + }); if v_max < v_min { - panic!("Malformed LLVM version range: max < min") + panic!("malformed LLVM version range where {v_max} < {v_min}") } // Ignore if version lies inside of range. - if actual_version >= v_min && actual_version <= v_max { + if *actual_version >= v_min && *actual_version <= v_max { if v_min == v_max { return IgnoreDecision::Ignore { - reason: format!("ignored when the LLVM version is {rest}"), + reason: format!("ignored when the LLVM version is {actual_version}"), }; } else { return IgnoreDecision::Ignore { - reason: format!("ignored when the LLVM version is between {rest}"), + reason: format!( + "ignored when the LLVM version is between {v_min} and {v_max}" + ), }; } } diff --git a/src/tools/compiletest/src/header/tests.rs b/src/tools/compiletest/src/header/tests.rs index c3c9496c4d2..2e6effcab98 100644 --- a/src/tools/compiletest/src/header/tests.rs +++ b/src/tools/compiletest/src/header/tests.rs @@ -1,9 +1,13 @@ use std::io::Read; use std::path::Path; -use super::iter_header; +use semver::Version; + +use super::{ + EarlyProps, HeadersCache, extract_llvm_version, extract_version_range, iter_header, + parse_normalize_rule, +}; use crate::common::{Config, Debugger, Mode}; -use crate::header::{EarlyProps, HeadersCache, parse_normalize_rule}; fn make_test_description<R: Read>( config: &Config, @@ -408,18 +412,66 @@ fn channel() { } #[test] +fn test_extract_llvm_version() { + // Note: officially, semver *requires* that versions at the minimum have all three + // `major.minor.patch` numbers, though for test-writer's convenience we allow omitting the minor + // and patch numbers (which will be stubbed out as 0). + assert_eq!(extract_llvm_version("0"), Version::new(0, 0, 0)); + assert_eq!(extract_llvm_version("0.0"), Version::new(0, 0, 0)); + assert_eq!(extract_llvm_version("0.0.0"), Version::new(0, 0, 0)); + assert_eq!(extract_llvm_version("1"), Version::new(1, 0, 0)); + assert_eq!(extract_llvm_version("1.2"), Version::new(1, 2, 0)); + assert_eq!(extract_llvm_version("1.2.3"), Version::new(1, 2, 3)); + assert_eq!(extract_llvm_version("4.5.6git"), Version::new(4, 5, 6)); + assert_eq!(extract_llvm_version("4.5.6-rc1"), Version::new(4, 5, 6)); + assert_eq!(extract_llvm_version("123.456.789-rc1"), Version::new(123, 456, 789)); + assert_eq!(extract_llvm_version("8.1.2-rust"), Version::new(8, 1, 2)); + assert_eq!(extract_llvm_version("9.0.1-rust-1.43.0-dev"), Version::new(9, 0, 1)); + assert_eq!(extract_llvm_version("9.3.1-rust-1.43.0-dev"), Version::new(9, 3, 1)); + assert_eq!(extract_llvm_version("10.0.0-rust"), Version::new(10, 0, 0)); + assert_eq!(extract_llvm_version("11.1.0"), Version::new(11, 1, 0)); + assert_eq!(extract_llvm_version("12.0.0libcxx"), Version::new(12, 0, 0)); + assert_eq!(extract_llvm_version("12.0.0-rc3"), Version::new(12, 0, 0)); + assert_eq!(extract_llvm_version("13.0.0git"), Version::new(13, 0, 0)); +} + +#[test] +#[should_panic] +fn test_llvm_version_invalid_components() { + extract_llvm_version("4.x.6"); +} + +#[test] +#[should_panic] +fn test_llvm_version_invalid_prefix() { + extract_llvm_version("meow4.5.6"); +} + +#[test] +#[should_panic] +fn test_llvm_version_too_many_components() { + extract_llvm_version("4.5.6.7"); +} + +#[test] fn test_extract_version_range() { - use super::{extract_llvm_version, extract_version_range}; - - assert_eq!(extract_version_range("1.2.3 - 4.5.6", extract_llvm_version), Some((10203, 40506))); - assert_eq!(extract_version_range("0 - 4.5.6", extract_llvm_version), Some((0, 40506))); - assert_eq!(extract_version_range("1.2.3 -", extract_llvm_version), None); - assert_eq!(extract_version_range("1.2.3 - ", extract_llvm_version), None); - assert_eq!(extract_version_range("- 4.5.6", extract_llvm_version), None); - assert_eq!(extract_version_range("-", extract_llvm_version), None); - assert_eq!(extract_version_range(" - 4.5.6", extract_llvm_version), None); - assert_eq!(extract_version_range(" - 4.5.6", extract_llvm_version), None); - assert_eq!(extract_version_range("0 -", extract_llvm_version), None); + let wrapped_extract = |s: &str| Some(extract_llvm_version(s)); + + assert_eq!( + extract_version_range("1.2.3 - 4.5.6", wrapped_extract), + Some((Version::new(1, 2, 3), Version::new(4, 5, 6))) + ); + assert_eq!( + extract_version_range("0 - 4.5.6", wrapped_extract), + Some((Version::new(0, 0, 0), Version::new(4, 5, 6))) + ); + assert_eq!(extract_version_range("1.2.3 -", wrapped_extract), None); + assert_eq!(extract_version_range("1.2.3 - ", wrapped_extract), None); + assert_eq!(extract_version_range("- 4.5.6", wrapped_extract), None); + assert_eq!(extract_version_range("-", wrapped_extract), None); + assert_eq!(extract_version_range(" - 4.5.6", wrapped_extract), None); + assert_eq!(extract_version_range(" - 4.5.6", wrapped_extract), None); + assert_eq!(extract_version_range("0 -", wrapped_extract), None); } #[test] diff --git a/src/tools/compiletest/src/lib.rs b/src/tools/compiletest/src/lib.rs index 490df313228..ccf8057bf5c 100644 --- a/src/tools/compiletest/src/lib.rs +++ b/src/tools/compiletest/src/lib.rs @@ -228,7 +228,7 @@ pub fn parse_config(args: Vec<String>) -> Config { Some(x) => panic!("argument for --color must be auto, always, or never, but found `{}`", x), }; let llvm_version = - matches.opt_str("llvm-version").as_deref().and_then(header::extract_llvm_version).or_else( + matches.opt_str("llvm-version").as_deref().map(header::extract_llvm_version).or_else( || header::extract_llvm_version_from_binary(&matches.opt_str("llvm-filecheck")?), ); diff --git a/src/tools/compiletest/src/runtest.rs b/src/tools/compiletest/src/runtest.rs index 3a6eca7dc5d..a8a71c196fc 100644 --- a/src/tools/compiletest/src/runtest.rs +++ b/src/tools/compiletest/src/runtest.rs @@ -1096,6 +1096,10 @@ impl<'test> TestCx<'test> { self.config.target.contains("vxworks") && !self.is_vxworks_pure_static() } + fn has_aux_dir(&self) -> bool { + !self.props.aux.builds.is_empty() || !self.props.aux.crates.is_empty() + } + fn aux_output_dir(&self) -> PathBuf { let aux_dir = self.aux_output_dir_name(); @@ -1649,7 +1653,11 @@ impl<'test> TestCx<'test> { } if let LinkToAux::Yes = link_to_aux { - rustc.arg("-L").arg(self.aux_output_dir_name()); + // if we pass an `-L` argument to a directory that doesn't exist, + // macOS ld emits warnings which disrupt the .stderr files + if self.has_aux_dir() { + rustc.arg("-L").arg(self.aux_output_dir_name()); + } } rustc.args(&self.props.compile_flags); diff --git a/src/tools/compiletest/src/runtest/run_make.rs b/src/tools/compiletest/src/runtest/run_make.rs index e7ae773ffa1..04bc2d7787d 100644 --- a/src/tools/compiletest/src/runtest/run_make.rs +++ b/src/tools/compiletest/src/runtest/run_make.rs @@ -329,6 +329,7 @@ impl TestCx<'_> { .arg(format!("run_make_support={}", &support_lib_path.to_string_lossy())) .arg("--edition=2021") .arg(&self.testpaths.file.join("rmake.rs")) + .arg("-Cprefer-dynamic") // Provide necessary library search paths for rustc. .env(dylib_env_var(), &env::join_paths(host_dylib_search_paths).unwrap()); diff --git a/src/tools/compiletest/src/tests.rs b/src/tools/compiletest/src/tests.rs index 680579c59ae..fec746904de 100644 --- a/src/tools/compiletest/src/tests.rs +++ b/src/tools/compiletest/src/tests.rs @@ -1,7 +1,6 @@ use std::ffi::OsString; use crate::debuggers::{extract_gdb_version, extract_lldb_version}; -use crate::header::extract_llvm_version; use crate::is_test; #[test] @@ -67,15 +66,3 @@ fn is_test_test() { assert!(!is_test(&OsString::from("#a_dog_gif"))); assert!(!is_test(&OsString::from("~a_temp_file"))); } - -#[test] -fn test_extract_llvm_version() { - assert_eq!(extract_llvm_version("8.1.2-rust"), Some(80102)); - assert_eq!(extract_llvm_version("9.0.1-rust-1.43.0-dev"), Some(90001)); - assert_eq!(extract_llvm_version("9.3.1-rust-1.43.0-dev"), Some(90301)); - assert_eq!(extract_llvm_version("10.0.0-rust"), Some(100000)); - assert_eq!(extract_llvm_version("11.1.0"), Some(110100)); - assert_eq!(extract_llvm_version("12.0.0libcxx"), Some(120000)); - assert_eq!(extract_llvm_version("12.0.0-rc3"), Some(120000)); - assert_eq!(extract_llvm_version("13.0.0git"), Some(130000)); -} diff --git a/src/tools/jsondocck/src/main.rs b/src/tools/jsondocck/src/main.rs index b264405ac3e..c08bbbc769a 100644 --- a/src/tools/jsondocck/src/main.rs +++ b/src/tools/jsondocck/src/main.rs @@ -123,7 +123,7 @@ fn print_err(msg: &str, lineno: usize) { // FIXME: This setup is temporary until we figure out how to improve this situation. // See <https://github.com/rust-lang/rust/issues/125813#issuecomment-2141953780>. -include!(concat!(env!("CARGO_MANIFEST_DIR"), "/../compiletest/src/command-list.rs")); +include!(concat!(env!("CARGO_MANIFEST_DIR"), "/../compiletest/src/directive-list.rs")); /// Get a list of commands from a file. Does the work of ensuring the commands /// are syntactically valid. diff --git a/src/tools/miri/.github/workflows/ci.yml b/src/tools/miri/.github/workflows/ci.yml index 8b0916f5111..2e491319822 100644 --- a/src/tools/miri/.github/workflows/ci.yml +++ b/src/tools/miri/.github/workflows/ci.yml @@ -1,11 +1,7 @@ name: CI on: - push: - # Run in PRs and for bors, but not on master. - branches: - - 'auto' - - 'try' + merge_group: pull_request: branches: - 'master' @@ -38,7 +34,7 @@ jobs: # The `style` job only runs on Linux; this makes sure the Windows-host-specific # code is also covered by clippy. - name: Check clippy - if: matrix.os == 'windows-latest' + if: ${{ matrix.os == 'windows-latest' }} run: ./miri clippy -- -D warnings - name: Test Miri @@ -62,27 +58,25 @@ jobs: - name: rustdoc run: RUSTDOCFLAGS="-Dwarnings" ./miri doc --document-private-items - # These jobs doesn't actually test anything, but they're only used to tell - # bors the build completed, as there is no practical way to detect when a - # workflow is successful listening to webhooks only. - # + # Summary job for the merge queue. # ALL THE PREVIOUS JOBS NEED TO BE ADDED TO THE `needs` SECTION OF THIS JOB! - end-success: - name: bors build finished - runs-on: ubuntu-latest + # And they should be added below in `cron-fail-notify` as well. + conclusion: needs: [build, style] - if: github.event.pusher.name == 'bors' && success() - steps: - - name: mark the job as a success - run: exit 0 - end-failure: - name: bors build finished + # We need to ensure this job does *not* get skipped if its dependencies fail, + # because a skipped job is considered a success by GitHub. So we have to + # overwrite `if:`. We use `!cancelled()` to ensure the job does still not get run + # when the workflow is canceled manually. + if: ${{ !cancelled() }} runs-on: ubuntu-latest - needs: [build, style] - if: github.event.pusher.name == 'bors' && (failure() || cancelled()) steps: - - name: mark the job as a failure - run: exit 1 + # Manually check the status of all dependencies. `if: failure()` does not work. + - name: Conclusion + run: | + # Print the dependent jobs to see them in the CI log + jq -C <<< '${{ toJson(needs) }}' + # Check if all jobs that we depend on (in the needs array) were successful. + jq --exit-status 'all(.result == "success")' <<< '${{ toJson(needs) }}' cron-fail-notify: name: cronjob failure notification @@ -93,7 +87,7 @@ jobs: # ... and create a PR. pull-requests: write needs: [build, style] - if: github.event_name == 'schedule' && failure() + if: ${{ github.event_name == 'schedule' && failure() }} steps: # Send a Zulip notification - name: Install zulip-send @@ -145,7 +139,7 @@ jobs: git push -u origin $BRANCH - name: Create Pull Request run: | - PR=$(gh pr create -B master --title 'Automatic Rustup' --body '') + PR=$(gh pr create -B master --title 'Automatic Rustup' --body 'Please close and re-open this PR to trigger CI, then enable auto-merge.') ~/.local/bin/zulip-send --user $ZULIP_BOT_EMAIL --api-key $ZULIP_API_TOKEN --site https://rust-lang.zulipchat.com \ --stream miri --subject "Miri Build Failure ($(date -u +%Y-%m))" \ --message "A PR doing a rustc-pull [has been automatically created]($PR) for your convenience." diff --git a/src/tools/miri/ci/ci.sh b/src/tools/miri/ci/ci.sh index ad1b2f4d0c3..4e7cbc50ca0 100755 --- a/src/tools/miri/ci/ci.sh +++ b/src/tools/miri/ci/ci.sh @@ -154,7 +154,7 @@ case $HOST_TARGET in TEST_TARGET=i686-unknown-freebsd run_tests_minimal $BASIC $UNIX time hashmap random threadname pthread fs libc-pipe TEST_TARGET=x86_64-unknown-illumos run_tests_minimal $BASIC $UNIX time hashmap random thread sync available-parallelism tls libc-pipe TEST_TARGET=x86_64-pc-solaris run_tests_minimal $BASIC $UNIX time hashmap random thread sync available-parallelism tls libc-pipe - TEST_TARGET=aarch64-linux-android run_tests_minimal $BASIC $UNIX time hashmap pthread --skip threadname + TEST_TARGET=aarch64-linux-android run_tests_minimal $BASIC $UNIX time hashmap threadname pthread TEST_TARGET=wasm32-wasip2 run_tests_minimal $BASIC wasm TEST_TARGET=wasm32-unknown-unknown run_tests_minimal no_std empty_main wasm # this target doesn't really have std TEST_TARGET=thumbv7em-none-eabihf run_tests_minimal no_std diff --git a/src/tools/miri/rust-version b/src/tools/miri/rust-version index 8b9e7efdff9..133edd3191d 100644 --- a/src/tools/miri/rust-version +++ b/src/tools/miri/rust-version @@ -1 +1 @@ -17a19e684cdf3ca088af8b4da6a6209d128913f4 +814df6e50eaf89b90793e7d9618bb60f1f18377a diff --git a/src/tools/miri/src/borrow_tracker/stacked_borrows/diagnostics.rs b/src/tools/miri/src/borrow_tracker/stacked_borrows/diagnostics.rs index 1684abeec6b..5624c4c479e 100644 --- a/src/tools/miri/src/borrow_tracker/stacked_borrows/diagnostics.rs +++ b/src/tools/miri/src/borrow_tracker/stacked_borrows/diagnostics.rs @@ -424,7 +424,11 @@ impl<'history, 'ecx, 'tcx> DiagnosticCx<'history, 'ecx, 'tcx> { } #[inline(never)] // This is only called on fatal code paths - pub(super) fn protector_error(&self, item: &Item, kind: ProtectorKind) -> InterpErrorKind<'tcx> { + pub(super) fn protector_error( + &self, + item: &Item, + kind: ProtectorKind, + ) -> InterpErrorKind<'tcx> { let protected = match kind { ProtectorKind::WeakProtector => "weakly protected", ProtectorKind::StrongProtector => "strongly protected", diff --git a/src/tools/miri/src/intrinsics/mod.rs b/src/tools/miri/src/intrinsics/mod.rs index 09ec2cb46b0..776d2561b43 100644 --- a/src/tools/miri/src/intrinsics/mod.rs +++ b/src/tools/miri/src/intrinsics/mod.rs @@ -145,6 +145,21 @@ pub trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> { this.write_scalar(Scalar::from_bool(branch), dest)?; } + "floorf16" | "ceilf16" | "truncf16" | "roundf16" | "rintf16" => { + let [f] = check_arg_count(args)?; + let f = this.read_scalar(f)?.to_f16()?; + let mode = match intrinsic_name { + "floorf16" => Round::TowardNegative, + "ceilf16" => Round::TowardPositive, + "truncf16" => Round::TowardZero, + "roundf16" => Round::NearestTiesToAway, + "rintf16" => Round::NearestTiesToEven, + _ => bug!(), + }; + let res = f.round_to_integral(mode).value; + let res = this.adjust_nan(res, &[f]); + this.write_scalar(res, dest)?; + } "floorf32" | "ceilf32" | "truncf32" | "roundf32" | "rintf32" => { let [f] = check_arg_count(args)?; let f = this.read_scalar(f)?.to_f32()?; @@ -175,6 +190,21 @@ pub trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> { let res = this.adjust_nan(res, &[f]); this.write_scalar(res, dest)?; } + "floorf128" | "ceilf128" | "truncf128" | "roundf128" | "rintf128" => { + let [f] = check_arg_count(args)?; + let f = this.read_scalar(f)?.to_f128()?; + let mode = match intrinsic_name { + "floorf128" => Round::TowardNegative, + "ceilf128" => Round::TowardPositive, + "truncf128" => Round::TowardZero, + "roundf128" => Round::NearestTiesToAway, + "rintf128" => Round::NearestTiesToEven, + _ => bug!(), + }; + let res = f.round_to_integral(mode).value; + let res = this.adjust_nan(res, &[f]); + this.write_scalar(res, dest)?; + } #[rustfmt::skip] | "sinf32" diff --git a/src/tools/miri/src/intrinsics/simd.rs b/src/tools/miri/src/intrinsics/simd.rs index 0799b93dbb0..f15b83a054f 100644 --- a/src/tools/miri/src/intrinsics/simd.rs +++ b/src/tools/miri/src/intrinsics/simd.rs @@ -1,7 +1,8 @@ use either::Either; use rustc_apfloat::{Float, Round}; +use rustc_middle::ty::FloatTy; use rustc_middle::ty::layout::LayoutOf; -use rustc_middle::{mir, ty, ty::FloatTy}; +use rustc_middle::{mir, ty}; use rustc_span::{Symbol, sym}; use rustc_target::abi::{Endian, HasDataLayout}; @@ -630,12 +631,8 @@ pub trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> { let (right, right_len) = this.project_to_simd(right)?; let (dest, dest_len) = this.project_to_simd(dest)?; - let index = generic_args[2] - .expect_const() - .try_to_valtree() - .unwrap() - .0 - .unwrap_branch(); + let index = + generic_args[2].expect_const().try_to_valtree().unwrap().0.unwrap_branch(); let index_len = index.len(); assert_eq!(left_len, right_len); diff --git a/src/tools/miri/src/lib.rs b/src/tools/miri/src/lib.rs index 660f2e493bc..938d1ca319e 100644 --- a/src/tools/miri/src/lib.rs +++ b/src/tools/miri/src/lib.rs @@ -147,7 +147,7 @@ pub use crate::range_map::RangeMap; pub use crate::shims::EmulateItemResult; pub use crate::shims::env::{EnvVars, EvalContextExt as _}; pub use crate::shims::foreign_items::{DynSym, EvalContextExt as _}; -pub use crate::shims::io_error::{EvalContextExt as _, LibcError}; +pub use crate::shims::io_error::{EvalContextExt as _, IoError, LibcError}; pub use crate::shims::os_str::EvalContextExt as _; pub use crate::shims::panic::{CatchUnwindData, EvalContextExt as _}; pub use crate::shims::time::EvalContextExt as _; diff --git a/src/tools/miri/src/shims/foreign_items.rs b/src/tools/miri/src/shims/foreign_items.rs index f6f91e58969..12f8facfd02 100644 --- a/src/tools/miri/src/shims/foreign_items.rs +++ b/src/tools/miri/src/shims/foreign_items.rs @@ -447,8 +447,7 @@ trait EvalContextExtPriv<'tcx>: crate::MiriInterpCxExt<'tcx> { } else { // If this does not fit in an isize, return null and, on Unix, set errno. if this.target_os_is_unix() { - let einval = this.eval_libc("ENOMEM"); - this.set_last_error(einval)?; + this.set_last_error(LibcError("ENOMEM"))?; } this.write_null(dest)?; } @@ -464,8 +463,7 @@ trait EvalContextExtPriv<'tcx>: crate::MiriInterpCxExt<'tcx> { } else { // On size overflow, return null and, on Unix, set errno. if this.target_os_is_unix() { - let einval = this.eval_libc("ENOMEM"); - this.set_last_error(einval)?; + this.set_last_error(LibcError("ENOMEM"))?; } this.write_null(dest)?; } @@ -486,8 +484,7 @@ trait EvalContextExtPriv<'tcx>: crate::MiriInterpCxExt<'tcx> { } else { // If this does not fit in an isize, return null and, on Unix, set errno. if this.target_os_is_unix() { - let einval = this.eval_libc("ENOMEM"); - this.set_last_error(einval)?; + this.set_last_error(LibcError("ENOMEM"))?; } this.write_null(dest)?; } diff --git a/src/tools/miri/src/shims/io_error.rs b/src/tools/miri/src/shims/io_error.rs index 38aa181cb4f..04491f0542b 100644 --- a/src/tools/miri/src/shims/io_error.rs +++ b/src/tools/miri/src/shims/io_error.rs @@ -141,6 +141,16 @@ pub trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> { interp_ok(Scalar::from_i32(-1)) } + /// Sets the last OS error and return `-1` as a `i64`-typed Scalar + fn set_last_error_and_return_i64( + &mut self, + err: impl Into<IoError>, + ) -> InterpResult<'tcx, Scalar> { + let this = self.eval_context_mut(); + this.set_last_error(err)?; + interp_ok(Scalar::from_i64(-1)) + } + /// Gets the last error variable. fn get_last_error(&mut self) -> InterpResult<'tcx, Scalar> { let this = self.eval_context_mut(); diff --git a/src/tools/miri/src/shims/time.rs b/src/tools/miri/src/shims/time.rs index 12c7679608d..6436823b0fd 100644 --- a/src/tools/miri/src/shims/time.rs +++ b/src/tools/miri/src/shims/time.rs @@ -81,9 +81,7 @@ pub trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> { } else if relative_clocks.contains(&clk_id) { this.machine.clock.now().duration_since(this.machine.clock.epoch()) } else { - let einval = this.eval_libc("EINVAL"); - this.set_last_error(einval)?; - return interp_ok(Scalar::from_i32(-1)); + return this.set_last_error_and_return_i32(LibcError("EINVAL")); }; let tv_sec = duration.as_secs(); @@ -109,9 +107,7 @@ pub trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> { // Using tz is obsolete and should always be null let tz = this.read_pointer(tz_op)?; if !this.ptr_is_null(tz)? { - let einval = this.eval_libc("EINVAL"); - this.set_last_error(einval)?; - return interp_ok(Scalar::from_i32(-1)); + return this.set_last_error_and_return_i32(LibcError("EINVAL")); } let duration = system_time_to_duration(&SystemTime::now())?; @@ -323,9 +319,7 @@ pub trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> { let duration = match this.read_timespec(&req)? { Some(duration) => duration, None => { - let einval = this.eval_libc("EINVAL"); - this.set_last_error(einval)?; - return interp_ok(Scalar::from_i32(-1)); + return this.set_last_error_and_return_i32(LibcError("EINVAL")); } }; diff --git a/src/tools/miri/src/shims/unix/android/foreign_items.rs b/src/tools/miri/src/shims/unix/android/foreign_items.rs index 583a1f65009..b6f04951fc7 100644 --- a/src/tools/miri/src/shims/unix/android/foreign_items.rs +++ b/src/tools/miri/src/shims/unix/android/foreign_items.rs @@ -1,6 +1,7 @@ use rustc_span::Symbol; use rustc_target::spec::abi::Abi; +use crate::shims::unix::android::thread::prctl; use crate::*; pub fn is_dyn_sym(_name: &str) -> bool { @@ -25,6 +26,9 @@ pub trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> { this.write_scalar(errno_place.to_ref(this).to_scalar(), dest)?; } + // Threading + "prctl" => prctl(this, link_name, abi, args, dest)?, + _ => return interp_ok(EmulateItemResult::NotSupported), } interp_ok(EmulateItemResult::NeedsReturn) diff --git a/src/tools/miri/src/shims/unix/android/mod.rs b/src/tools/miri/src/shims/unix/android/mod.rs index 09c6507b24f..1f2a74bac59 100644 --- a/src/tools/miri/src/shims/unix/android/mod.rs +++ b/src/tools/miri/src/shims/unix/android/mod.rs @@ -1 +1,2 @@ pub mod foreign_items; +pub mod thread; diff --git a/src/tools/miri/src/shims/unix/android/thread.rs b/src/tools/miri/src/shims/unix/android/thread.rs new file mode 100644 index 00000000000..6f5f0f74a22 --- /dev/null +++ b/src/tools/miri/src/shims/unix/android/thread.rs @@ -0,0 +1,57 @@ +use rustc_span::Symbol; +use rustc_target::abi::Size; +use rustc_target::spec::abi::Abi; + +use crate::helpers::check_min_arg_count; +use crate::shims::unix::thread::EvalContextExt as _; +use crate::*; + +const TASK_COMM_LEN: usize = 16; + +pub fn prctl<'tcx>( + this: &mut MiriInterpCx<'tcx>, + link_name: Symbol, + abi: Abi, + args: &[OpTy<'tcx>], + dest: &MPlaceTy<'tcx>, +) -> InterpResult<'tcx> { + // We do not use `check_shim` here because `prctl` is variadic. The argument + // count is checked bellow. + this.check_abi_and_shim_symbol_clash(abi, Abi::C { unwind: false }, link_name)?; + + // FIXME: Use constants once https://github.com/rust-lang/libc/pull/3941 backported to the 0.2 branch. + let pr_set_name = 15; + let pr_get_name = 16; + + let [op] = check_min_arg_count("prctl", args)?; + let res = match this.read_scalar(op)?.to_i32()? { + op if op == pr_set_name => { + let [_, name] = check_min_arg_count("prctl(PR_SET_NAME, ...)", args)?; + let name = this.read_scalar(name)?; + let thread = this.pthread_self()?; + // The Linux kernel silently truncates long names. + // https://www.man7.org/linux/man-pages/man2/PR_SET_NAME.2const.html + let res = + this.pthread_setname_np(thread, name, TASK_COMM_LEN, /* truncate */ true)?; + assert!(res); + Scalar::from_u32(0) + } + op if op == pr_get_name => { + let [_, name] = check_min_arg_count("prctl(PR_GET_NAME, ...)", args)?; + let name = this.read_scalar(name)?; + let thread = this.pthread_self()?; + let len = Scalar::from_target_usize(TASK_COMM_LEN as u64, this); + this.check_ptr_access( + name.to_pointer(this)?, + Size::from_bytes(TASK_COMM_LEN), + CheckInAllocMsg::MemoryAccessTest, + )?; + let res = this.pthread_getname_np(thread, name, len, /* truncate*/ false)?; + assert!(res); + Scalar::from_u32(0) + } + op => throw_unsup_format!("Miri does not support `prctl` syscall with op={}", op), + }; + this.write_scalar(res, dest)?; + interp_ok(()) +} diff --git a/src/tools/miri/src/shims/unix/fd.rs b/src/tools/miri/src/shims/unix/fd.rs index e3914640037..f3db56695fc 100644 --- a/src/tools/miri/src/shims/unix/fd.rs +++ b/src/tools/miri/src/shims/unix/fd.rs @@ -423,7 +423,7 @@ pub trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> { let this = self.eval_context_mut(); let Some(fd) = this.machine.fds.get(old_fd_num) else { - return interp_ok(Scalar::from_i32(this.fd_not_found()?)); + return this.set_last_error_and_return_i32(LibcError("EBADF")); }; interp_ok(Scalar::from_i32(this.machine.fds.insert(fd))) } @@ -432,7 +432,7 @@ pub trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> { let this = self.eval_context_mut(); let Some(fd) = this.machine.fds.get(old_fd_num) else { - return interp_ok(Scalar::from_i32(this.fd_not_found()?)); + return this.set_last_error_and_return_i32(LibcError("EBADF")); }; if new_fd_num != old_fd_num { // Close new_fd if it is previously opened. @@ -448,7 +448,7 @@ pub trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> { fn flock(&mut self, fd_num: i32, op: i32) -> InterpResult<'tcx, Scalar> { let this = self.eval_context_mut(); let Some(fd) = this.machine.fds.get(fd_num) else { - return interp_ok(Scalar::from_i32(this.fd_not_found()?)); + return this.set_last_error_and_return_i32(LibcError("EBADF")); }; // We need to check that there aren't unsupported options in `op`. @@ -498,11 +498,11 @@ pub trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> { // `FD_CLOEXEC` value without checking if the flag is set for the file because `std` // always sets this flag when opening a file. However we still need to check that the // file itself is open. - interp_ok(Scalar::from_i32(if this.machine.fds.is_fd_num(fd_num) { - this.eval_libc_i32("FD_CLOEXEC") + if !this.machine.fds.is_fd_num(fd_num) { + this.set_last_error_and_return_i32(LibcError("EBADF")) } else { - this.fd_not_found()? - })) + interp_ok(this.eval_libc("FD_CLOEXEC")) + } } cmd if cmd == f_dupfd || cmd == f_dupfd_cloexec => { // Note that we always assume the FD_CLOEXEC flag is set for every open file, in part @@ -521,7 +521,7 @@ pub trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> { if let Some(fd) = this.machine.fds.get(fd_num) { interp_ok(Scalar::from_i32(this.machine.fds.insert_with_min_num(fd, start))) } else { - interp_ok(Scalar::from_i32(this.fd_not_found()?)) + this.set_last_error_and_return_i32(LibcError("EBADF")) } } cmd if this.tcx.sess.target.os == "macos" @@ -547,7 +547,7 @@ pub trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> { let fd_num = this.read_scalar(fd_op)?.to_i32()?; let Some(fd) = this.machine.fds.remove(fd_num) else { - return interp_ok(Scalar::from_i32(this.fd_not_found()?)); + return this.set_last_error_and_return_i32(LibcError("EBADF")); }; let result = fd.close(this.machine.communicate(), this)?; // return `0` if close is successful @@ -555,17 +555,6 @@ pub trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> { interp_ok(Scalar::from_i32(this.try_unwrap_io_result(result)?)) } - /// Function used when a file descriptor does not exist. It returns `Ok(-1)`and sets - /// the last OS error to `libc::EBADF` (invalid file descriptor). This function uses - /// `T: From<i32>` instead of `i32` directly because some fs functions return different integer - /// types (like `read`, that returns an `i64`). - fn fd_not_found<T: From<i32>>(&mut self) -> InterpResult<'tcx, T> { - let this = self.eval_context_mut(); - let ebadf = this.eval_libc("EBADF"); - this.set_last_error(ebadf)?; - interp_ok((-1).into()) - } - /// Read data from `fd` into buffer specified by `buf` and `count`. /// /// If `offset` is `None`, reads data from current cursor position associated with `fd` @@ -599,9 +588,7 @@ pub trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> { // We temporarily dup the FD to be able to retain mutable access to `this`. let Some(fd) = this.machine.fds.get(fd_num) else { trace!("read: FD not found"); - let res: i32 = this.fd_not_found()?; - this.write_int(res, dest)?; - return interp_ok(()); + return this.set_last_error_and_return(LibcError("EBADF"), dest); }; trace!("read: FD mapped to {fd:?}"); @@ -646,9 +633,7 @@ pub trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> { // We temporarily dup the FD to be able to retain mutable access to `this`. let Some(fd) = this.machine.fds.get(fd_num) else { - let res: i32 = this.fd_not_found()?; - this.write_int(res, dest)?; - return interp_ok(()); + return this.set_last_error_and_return(LibcError("EBADF"), dest); }; match offset { diff --git a/src/tools/miri/src/shims/unix/foreign_items.rs b/src/tools/miri/src/shims/unix/foreign_items.rs index 7ba98981920..355c93c444c 100644 --- a/src/tools/miri/src/shims/unix/foreign_items.rs +++ b/src/tools/miri/src/shims/unix/foreign_items.rs @@ -362,8 +362,7 @@ pub trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> { // FreeBSD: https://man.freebsd.org/cgi/man.cgi?query=reallocarray match this.compute_size_in_bytes(Size::from_bytes(size), nmemb) { None => { - let enmem = this.eval_libc("ENOMEM"); - this.set_last_error(enmem)?; + this.set_last_error(LibcError("ENOMEM"))?; this.write_null(dest)?; } Some(len) => { @@ -653,13 +652,10 @@ pub trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> { let chunk_size = CpuAffinityMask::chunk_size(this); if this.ptr_is_null(mask)? { - let efault = this.eval_libc("EFAULT"); - this.set_last_error(efault)?; - this.write_int(-1, dest)?; + this.set_last_error_and_return(LibcError("EFAULT"), dest)?; } else if cpusetsize == 0 || cpusetsize.checked_rem(chunk_size).unwrap() != 0 { // we only copy whole chunks of size_of::<c_ulong>() - this.set_last_error(LibcError("EINVAL"))?; - this.write_int(-1, dest)?; + this.set_last_error_and_return(LibcError("EINVAL"), dest)?; } else if let Some(cpuset) = this.machine.thread_cpu_affinity.get(&thread_id) { let cpuset = cpuset.clone(); // we only copy whole chunks of size_of::<c_ulong>() @@ -668,9 +664,7 @@ pub trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> { this.write_null(dest)?; } else { // The thread whose ID is pid could not be found - let esrch = this.eval_libc("ESRCH"); - this.set_last_error(esrch)?; - this.write_int(-1, dest)?; + this.set_last_error_and_return(LibcError("ESRCH"), dest)?; } } "sched_setaffinity" => { @@ -695,9 +689,7 @@ pub trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> { }; if this.ptr_is_null(mask)? { - let efault = this.eval_libc("EFAULT"); - this.set_last_error(efault)?; - this.write_int(-1, dest)?; + this.set_last_error_and_return(LibcError("EFAULT"), dest)?; } else { // NOTE: cpusetsize might be smaller than `CpuAffinityMask::CPU_MASK_BYTES`. // Any unspecified bytes are treated as zero here (none of the CPUs are configured). @@ -713,8 +705,7 @@ pub trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> { } None => { // The intersection between the mask and the available CPUs was empty. - this.set_last_error(LibcError("EINVAL"))?; - this.write_int(-1, dest)?; + this.set_last_error_and_return(LibcError("EINVAL"), dest)?; } } } @@ -770,9 +761,7 @@ pub trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> { // macOS: https://keith.github.io/xcode-man-pages/getentropy.2.html // Solaris/Illumos: https://illumos.org/man/3C/getentropy if bufsize > 256 { - let err = this.eval_libc("EIO"); - this.set_last_error(err)?; - this.write_int(-1, dest)?; + this.set_last_error_and_return(LibcError("EIO"), dest)?; } else { this.gen_random(buf, bufsize)?; this.write_null(dest)?; diff --git a/src/tools/miri/src/shims/unix/freebsd/foreign_items.rs b/src/tools/miri/src/shims/unix/freebsd/foreign_items.rs index 5204e57705a..71953aca989 100644 --- a/src/tools/miri/src/shims/unix/freebsd/foreign_items.rs +++ b/src/tools/miri/src/shims/unix/freebsd/foreign_items.rs @@ -29,6 +29,7 @@ pub trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> { this.read_scalar(thread)?, this.read_scalar(name)?, max_len, + /* truncate */ false, )?; } "pthread_get_name_np" => { diff --git a/src/tools/miri/src/shims/unix/fs.rs b/src/tools/miri/src/shims/unix/fs.rs index 4b3ae8e0520..f7436d7f089 100644 --- a/src/tools/miri/src/shims/unix/fs.rs +++ b/src/tools/miri/src/shims/unix/fs.rs @@ -149,6 +149,7 @@ impl FileDescription for FileHandle { // to handle possible errors correctly. let result = self.file.sync_all(); // Now we actually close the file and return the result. + drop(*self); interp_ok(result) } else { // We drop the file, this closes it but ignores any errors @@ -157,6 +158,7 @@ impl FileDescription for FileHandle { // `/dev/urandom` which are read-only. Check // https://github.com/rust-lang/miri/issues/999#issuecomment-568920439 // for a deeper discussion. + drop(*self); interp_ok(Ok(())) } } @@ -229,6 +231,8 @@ impl FileDescription for FileHandle { TRUE => Ok(()), FALSE => { let mut err = io::Error::last_os_error(); + // This only runs on Windows hosts so we can use `raw_os_error`. + // We have to be careful not to forward that error code to target code. let code: u32 = err.raw_os_error().unwrap().try_into().unwrap(); if matches!(code, ERROR_IO_PENDING | ERROR_LOCK_VIOLATION) { if lock_nb { @@ -337,15 +341,10 @@ trait EvalContextExtPrivate<'tcx>: crate::MiriInterpCxExt<'tcx> { _ => interp_ok(this.eval_libc("DT_UNKNOWN").to_u8()?.into()), } } - Err(e) => - match e.raw_os_error() { - Some(error) => interp_ok(error), - None => - throw_unsup_format!( - "the error {} couldn't be converted to a return value", - e - ), - }, + Err(_) => { + // Fallback on error + interp_ok(this.eval_libc("DT_UNKNOWN").to_u8()?.into()) + } } } } @@ -528,8 +527,7 @@ pub trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> { let o_tmpfile = this.eval_libc_i32("O_TMPFILE"); if flag & o_tmpfile == o_tmpfile { // if the flag contains `O_TMPFILE` then we return a graceful error - this.set_last_error(LibcError("EOPNOTSUPP"))?; - return interp_ok(Scalar::from_i32(-1)); + return this.set_last_error_and_return_i32(LibcError("EOPNOTSUPP")); } } @@ -548,9 +546,7 @@ pub trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> { // O_NOFOLLOW only fails when the trailing component is a symlink; // the entire rest of the path can still contain symlinks. if path.is_symlink() { - let eloop = this.eval_libc("ELOOP"); - this.set_last_error(eloop)?; - return interp_ok(Scalar::from_i32(-1)); + return this.set_last_error_and_return_i32(LibcError("ELOOP")); } } mirror |= o_nofollow; @@ -565,8 +561,7 @@ pub trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> { // Reject if isolation is enabled. if let IsolatedOp::Reject(reject_with) = this.machine.isolated_op { this.reject_in_isolation("`open`", reject_with)?; - this.set_last_error(ErrorKind::PermissionDenied)?; - return interp_ok(Scalar::from_i32(-1)); + return this.set_last_error_and_return_i32(ErrorKind::PermissionDenied); } let fd = options @@ -584,8 +579,7 @@ pub trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> { let seek_from = if whence == this.eval_libc_i32("SEEK_SET") { if offset < 0 { // Negative offsets return `EINVAL`. - this.set_last_error(LibcError("EINVAL"))?; - return interp_ok(Scalar::from_i64(-1)); + return this.set_last_error_and_return_i64(LibcError("EINVAL")); } else { SeekFrom::Start(u64::try_from(offset).unwrap()) } @@ -594,14 +588,13 @@ pub trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> { } else if whence == this.eval_libc_i32("SEEK_END") { SeekFrom::End(i64::try_from(offset).unwrap()) } else { - this.set_last_error(LibcError("EINVAL"))?; - return interp_ok(Scalar::from_i64(-1)); + return this.set_last_error_and_return_i64(LibcError("EINVAL")); }; let communicate = this.machine.communicate(); let Some(fd) = this.machine.fds.get(fd_num) else { - return interp_ok(Scalar::from_i64(this.fd_not_found()?)); + return this.set_last_error_and_return_i64(LibcError("EBADF")); }; let result = fd.seek(communicate, seek_from)?.map(|offset| i64::try_from(offset).unwrap()); drop(fd); @@ -618,8 +611,7 @@ pub trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> { // Reject if isolation is enabled. if let IsolatedOp::Reject(reject_with) = this.machine.isolated_op { this.reject_in_isolation("`unlink`", reject_with)?; - this.set_last_error(ErrorKind::PermissionDenied)?; - return interp_ok(Scalar::from_i32(-1)); + return this.set_last_error_and_return_i32(ErrorKind::PermissionDenied); } let result = remove_file(path).map(|_| 0); @@ -649,8 +641,7 @@ pub trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> { // Reject if isolation is enabled. if let IsolatedOp::Reject(reject_with) = this.machine.isolated_op { this.reject_in_isolation("`symlink`", reject_with)?; - this.set_last_error(ErrorKind::PermissionDenied)?; - return interp_ok(Scalar::from_i32(-1)); + return this.set_last_error_and_return_i32(ErrorKind::PermissionDenied); } let result = create_link(&target, &linkpath).map(|_| 0); @@ -674,15 +665,13 @@ pub trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> { // Reject if isolation is enabled. if let IsolatedOp::Reject(reject_with) = this.machine.isolated_op { this.reject_in_isolation("`stat`", reject_with)?; - let eacc = this.eval_libc("EACCES"); - this.set_last_error(eacc)?; - return interp_ok(Scalar::from_i32(-1)); + return this.set_last_error_and_return_i32(LibcError("EACCES")); } // `stat` always follows symlinks. let metadata = match FileMetadata::from_path(this, &path, true)? { - Some(metadata) => metadata, - None => return interp_ok(Scalar::from_i32(-1)), // `FileMetadata` has set errno + Ok(metadata) => metadata, + Err(err) => return this.set_last_error_and_return_i32(err), }; interp_ok(Scalar::from_i32(this.macos_stat_write_buf(metadata, buf_op)?)) @@ -706,14 +695,12 @@ pub trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> { // Reject if isolation is enabled. if let IsolatedOp::Reject(reject_with) = this.machine.isolated_op { this.reject_in_isolation("`lstat`", reject_with)?; - let eacc = this.eval_libc("EACCES"); - this.set_last_error(eacc)?; - return interp_ok(Scalar::from_i32(-1)); + return this.set_last_error_and_return_i32(LibcError("EACCES")); } let metadata = match FileMetadata::from_path(this, &path, false)? { - Some(metadata) => metadata, - None => return interp_ok(Scalar::from_i32(-1)), // `FileMetadata` has set errno + Ok(metadata) => metadata, + Err(err) => return this.set_last_error_and_return_i32(err), }; interp_ok(Scalar::from_i32(this.macos_stat_write_buf(metadata, buf_op)?)) @@ -736,12 +723,12 @@ pub trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> { if let IsolatedOp::Reject(reject_with) = this.machine.isolated_op { this.reject_in_isolation("`fstat`", reject_with)?; // Set error code as "EBADF" (bad fd) - return interp_ok(Scalar::from_i32(this.fd_not_found()?)); + return this.set_last_error_and_return_i32(LibcError("EBADF")); } let metadata = match FileMetadata::from_fd_num(this, fd)? { - Some(metadata) => metadata, - None => return interp_ok(Scalar::from_i32(-1)), + Ok(metadata) => metadata, + Err(err) => return this.set_last_error_and_return_i32(err), }; interp_ok(Scalar::from_i32(this.macos_stat_write_buf(metadata, buf_op)?)) } @@ -766,9 +753,7 @@ pub trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> { // If the statxbuf or pathname pointers are null, the function fails with `EFAULT`. if this.ptr_is_null(statxbuf_ptr)? || this.ptr_is_null(pathname_ptr)? { - let efault = this.eval_libc("EFAULT"); - this.set_last_error(efault)?; - return interp_ok(Scalar::from_i32(-1)); + return this.set_last_error_and_return_i32(LibcError("EFAULT")); } let statxbuf = this.deref_pointer_as(statxbuf_op, this.libc_ty_layout("statx"))?; @@ -801,16 +786,15 @@ pub trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> { let ecode = if path.is_absolute() || dirfd == this.eval_libc_i32("AT_FDCWD") { // since `path` is provided, either absolute or // relative to CWD, `EACCES` is the most relevant. - this.eval_libc("EACCES") + LibcError("EACCES") } else { // `dirfd` is set to target file, and `path` is empty // (or we would have hit the `throw_unsup_format` // above). `EACCES` would violate the spec. assert!(empty_path_flag); - this.eval_libc("EBADF") + LibcError("EBADF") }; - this.set_last_error(ecode)?; - return interp_ok(Scalar::from_i32(-1)); + return this.set_last_error_and_return_i32(ecode); } // the `_mask_op` parameter specifies the file information that the caller requested. @@ -831,8 +815,8 @@ pub trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> { FileMetadata::from_path(this, &path, follow_symlink)? }; let metadata = match metadata { - Some(metadata) => metadata, - None => return interp_ok(Scalar::from_i32(-1)), + Ok(metadata) => metadata, + Err(err) => return this.set_last_error_and_return_i32(err), }; // The `mode` field specifies the type of the file and the permissions over the file for @@ -939,9 +923,7 @@ pub trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> { let newpath_ptr = this.read_pointer(newpath_op)?; if this.ptr_is_null(oldpath_ptr)? || this.ptr_is_null(newpath_ptr)? { - let efault = this.eval_libc("EFAULT"); - this.set_last_error(efault)?; - return interp_ok(Scalar::from_i32(-1)); + return this.set_last_error_and_return_i32(LibcError("EFAULT")); } let oldpath = this.read_path_from_c_str(oldpath_ptr)?; @@ -950,8 +932,7 @@ pub trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> { // Reject if isolation is enabled. if let IsolatedOp::Reject(reject_with) = this.machine.isolated_op { this.reject_in_isolation("`rename`", reject_with)?; - this.set_last_error(ErrorKind::PermissionDenied)?; - return interp_ok(Scalar::from_i32(-1)); + return this.set_last_error_and_return_i32(ErrorKind::PermissionDenied); } let result = rename(oldpath, newpath).map(|_| 0); @@ -974,8 +955,7 @@ pub trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> { // Reject if isolation is enabled. if let IsolatedOp::Reject(reject_with) = this.machine.isolated_op { this.reject_in_isolation("`mkdir`", reject_with)?; - this.set_last_error(ErrorKind::PermissionDenied)?; - return interp_ok(Scalar::from_i32(-1)); + return this.set_last_error_and_return_i32(ErrorKind::PermissionDenied); } #[cfg_attr(not(unix), allow(unused_mut))] @@ -1002,8 +982,7 @@ pub trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> { // Reject if isolation is enabled. if let IsolatedOp::Reject(reject_with) = this.machine.isolated_op { this.reject_in_isolation("`rmdir`", reject_with)?; - this.set_last_error(ErrorKind::PermissionDenied)?; - return interp_ok(Scalar::from_i32(-1)); + return this.set_last_error_and_return_i32(ErrorKind::PermissionDenied); } let result = remove_dir(path).map(|_| 0i32); @@ -1019,8 +998,7 @@ pub trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> { // Reject if isolation is enabled. if let IsolatedOp::Reject(reject_with) = this.machine.isolated_op { this.reject_in_isolation("`opendir`", reject_with)?; - let eacc = this.eval_libc("EACCES"); - this.set_last_error(eacc)?; + this.set_last_error(LibcError("EACCES"))?; return interp_ok(Scalar::null_ptr(this)); } @@ -1052,8 +1030,7 @@ pub trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> { // Reject if isolation is enabled. if let IsolatedOp::Reject(reject_with) = this.machine.isolated_op { this.reject_in_isolation("`readdir`", reject_with)?; - let eacc = this.eval_libc("EBADF"); - this.set_last_error(eacc)?; + this.set_last_error(LibcError("EBADF"))?; return interp_ok(Scalar::null_ptr(this)); } @@ -1152,14 +1129,14 @@ pub trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> { // Reject if isolation is enabled. if let IsolatedOp::Reject(reject_with) = this.machine.isolated_op { this.reject_in_isolation("`readdir_r`", reject_with)?; - // Set error code as "EBADF" (bad fd) - return interp_ok(Scalar::from_i32(this.fd_not_found()?)); + // Return error code, do *not* set `errno`. + return interp_ok(this.eval_libc("EBADF")); } let open_dir = this.machine.dirs.streams.get_mut(&dirp).ok_or_else(|| { err_unsup_format!("the DIR pointer passed to readdir_r did not come from opendir") })?; - interp_ok(Scalar::from_i32(match open_dir.read_dir.next() { + interp_ok(match open_dir.read_dir.next() { Some(Ok(dir_entry)) => { // Write into entry, write pointer to result, return 0 on success. // The name is written with write_os_str_to_c_str, while the rest of the @@ -1237,25 +1214,18 @@ pub trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> { let result_place = this.deref_pointer(result_op)?; this.write_scalar(this.read_scalar(entry_op)?, &result_place)?; - 0 + Scalar::from_i32(0) } None => { // end of stream: return 0, assign *result=NULL this.write_null(&this.deref_pointer(result_op)?)?; - 0 + Scalar::from_i32(0) } - Some(Err(e)) => - match e.raw_os_error() { - // return positive error number on error - Some(error) => error, - None => { - throw_unsup_format!( - "the error {} couldn't be converted to a return value", - e - ) - } - }, - })) + Some(Err(e)) => { + // return positive error number on error (do *not* set last error) + this.io_error_to_errnum(e)? + } + }) } fn closedir(&mut self, dirp_op: &OpTy<'tcx>) -> InterpResult<'tcx, Scalar> { @@ -1264,20 +1234,21 @@ pub trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> { let dirp = this.read_target_usize(dirp_op)?; // Reject if isolation is enabled. - interp_ok(Scalar::from_i32( - if let IsolatedOp::Reject(reject_with) = this.machine.isolated_op { - this.reject_in_isolation("`closedir`", reject_with)?; - this.fd_not_found()? - } else if let Some(open_dir) = this.machine.dirs.streams.remove(&dirp) { - if let Some(entry) = open_dir.entry { - this.deallocate_ptr(entry, None, MiriMemoryKind::Runtime.into())?; - } - drop(open_dir); - 0 - } else { - this.fd_not_found()? - }, - )) + if let IsolatedOp::Reject(reject_with) = this.machine.isolated_op { + this.reject_in_isolation("`closedir`", reject_with)?; + return this.set_last_error_and_return_i32(LibcError("EBADF")); + } + + let Some(mut open_dir) = this.machine.dirs.streams.remove(&dirp) else { + return this.set_last_error_and_return_i32(LibcError("EBADF")); + }; + if let Some(entry) = open_dir.entry.take() { + this.deallocate_ptr(entry, None, MiriMemoryKind::Runtime.into())?; + } + // We drop the `open_dir`, which will close the host dir handle. + drop(open_dir); + + interp_ok(Scalar::from_i32(0)) } fn ftruncate64(&mut self, fd_num: i32, length: i128) -> InterpResult<'tcx, Scalar> { @@ -1287,11 +1258,11 @@ pub trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> { if let IsolatedOp::Reject(reject_with) = this.machine.isolated_op { this.reject_in_isolation("`ftruncate64`", reject_with)?; // Set error code as "EBADF" (bad fd) - return interp_ok(Scalar::from_i32(this.fd_not_found()?)); + return this.set_last_error_and_return_i32(LibcError("EBADF")); } let Some(fd) = this.machine.fds.get(fd_num) else { - return interp_ok(Scalar::from_i32(this.fd_not_found()?)); + return this.set_last_error_and_return_i32(LibcError("EBADF")); }; // FIXME: Support ftruncate64 for all FDs @@ -1307,14 +1278,12 @@ pub trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> { interp_ok(Scalar::from_i32(result)) } else { drop(fd); - this.set_last_error(LibcError("EINVAL"))?; - interp_ok(Scalar::from_i32(-1)) + this.set_last_error_and_return_i32(LibcError("EINVAL")) } } else { drop(fd); // The file is not writable - this.set_last_error(LibcError("EINVAL"))?; - interp_ok(Scalar::from_i32(-1)) + this.set_last_error_and_return_i32(LibcError("EINVAL")) } } @@ -1332,7 +1301,7 @@ pub trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> { if let IsolatedOp::Reject(reject_with) = this.machine.isolated_op { this.reject_in_isolation("`fsync`", reject_with)?; // Set error code as "EBADF" (bad fd) - return interp_ok(Scalar::from_i32(this.fd_not_found()?)); + return this.set_last_error_and_return_i32(LibcError("EBADF")); } self.ffullsync_fd(fd) @@ -1341,7 +1310,7 @@ pub trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> { fn ffullsync_fd(&mut self, fd_num: i32) -> InterpResult<'tcx, Scalar> { let this = self.eval_context_mut(); let Some(fd) = this.machine.fds.get(fd_num) else { - return interp_ok(Scalar::from_i32(this.fd_not_found()?)); + return this.set_last_error_and_return_i32(LibcError("EBADF")); }; // Only regular files support synchronization. let FileHandle { file, writable } = fd.downcast::<FileHandle>().ok_or_else(|| { @@ -1361,11 +1330,11 @@ pub trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> { if let IsolatedOp::Reject(reject_with) = this.machine.isolated_op { this.reject_in_isolation("`fdatasync`", reject_with)?; // Set error code as "EBADF" (bad fd) - return interp_ok(Scalar::from_i32(this.fd_not_found()?)); + return this.set_last_error_and_return_i32(LibcError("EBADF")); } let Some(fd) = this.machine.fds.get(fd) else { - return interp_ok(Scalar::from_i32(this.fd_not_found()?)); + return this.set_last_error_and_return_i32(LibcError("EBADF")); }; // Only regular files support synchronization. let FileHandle { file, writable } = fd.downcast::<FileHandle>().ok_or_else(|| { @@ -1391,26 +1360,24 @@ pub trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> { let flags = this.read_scalar(flags_op)?.to_i32()?; if offset < 0 || nbytes < 0 { - this.set_last_error(LibcError("EINVAL"))?; - return interp_ok(Scalar::from_i32(-1)); + return this.set_last_error_and_return_i32(LibcError("EINVAL")); } let allowed_flags = this.eval_libc_i32("SYNC_FILE_RANGE_WAIT_BEFORE") | this.eval_libc_i32("SYNC_FILE_RANGE_WRITE") | this.eval_libc_i32("SYNC_FILE_RANGE_WAIT_AFTER"); if flags & allowed_flags != flags { - this.set_last_error(LibcError("EINVAL"))?; - return interp_ok(Scalar::from_i32(-1)); + return this.set_last_error_and_return_i32(LibcError("EINVAL")); } // Reject if isolation is enabled. if let IsolatedOp::Reject(reject_with) = this.machine.isolated_op { this.reject_in_isolation("`sync_file_range`", reject_with)?; // Set error code as "EBADF" (bad fd) - return interp_ok(Scalar::from_i32(this.fd_not_found()?)); + return this.set_last_error_and_return_i32(LibcError("EBADF")); } let Some(fd) = this.machine.fds.get(fd) else { - return interp_ok(Scalar::from_i32(this.fd_not_found()?)); + return this.set_last_error_and_return_i32(LibcError("EBADF")); }; // Only regular files support synchronization. let FileHandle { file, writable } = fd.downcast::<FileHandle>().ok_or_else(|| { @@ -1436,8 +1403,7 @@ pub trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> { // Reject if isolation is enabled. if let IsolatedOp::Reject(reject_with) = this.machine.isolated_op { this.reject_in_isolation("`readlink`", reject_with)?; - let eacc = this.eval_libc("EACCES"); - this.set_last_error(eacc)?; + this.set_last_error(LibcError("EACCES"))?; return interp_ok(-1); } @@ -1475,11 +1441,11 @@ pub trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> { if fd.is_tty(this.machine.communicate()) { return interp_ok(Scalar::from_i32(1)); } else { - this.eval_libc("ENOTTY") + LibcError("ENOTTY") } } else { // FD does not exist - this.eval_libc("EBADF") + LibcError("EBADF") }; this.set_last_error(error)?; interp_ok(Scalar::from_i32(0)) @@ -1499,8 +1465,7 @@ pub trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> { // Reject if isolation is enabled. if let IsolatedOp::Reject(reject_with) = this.machine.isolated_op { this.reject_in_isolation("`realpath`", reject_with)?; - let eacc = this.eval_libc("EACCES"); - this.set_last_error(eacc)?; + this.set_last_error(LibcError("EACCES"))?; return interp_ok(Scalar::from_target_usize(0, this)); } @@ -1530,8 +1495,7 @@ pub trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> { // Note that we do not explicitly handle `FILENAME_MAX` // (different from `PATH_MAX` above) as it is Linux-specific and // seems like a bit of a mess anyway: <https://eklitzke.org/path-max-is-tricky>. - let enametoolong = this.eval_libc("ENAMETOOLONG"); - this.set_last_error(enametoolong)?; + this.set_last_error(LibcError("ENAMETOOLONG"))?; return interp_ok(Scalar::from_target_usize(0, this)); } processed_ptr @@ -1574,9 +1538,7 @@ pub trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> { // Reject if isolation is enabled. if let IsolatedOp::Reject(reject_with) = this.machine.isolated_op { this.reject_in_isolation("`mkstemp`", reject_with)?; - let eacc = this.eval_libc("EACCES"); - this.set_last_error(eacc)?; - return interp_ok(Scalar::from_i32(-1)); + return this.set_last_error_and_return_i32(LibcError("EACCES")); } // Get the bytes of the suffix we expect in _target_ encoding. @@ -1592,8 +1554,7 @@ pub trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> { // If we don't find the suffix, it is an error. if last_six_char_bytes != suffix_bytes { - this.set_last_error(LibcError("EINVAL"))?; - return interp_ok(Scalar::from_i32(-1)); + return this.set_last_error_and_return_i32(LibcError("EINVAL")); } // At this point we know we have 6 ASCII 'X' characters as a suffix. @@ -1658,17 +1619,14 @@ pub trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> { _ => { // "On error, -1 is returned, and errno is set to // indicate the error" - this.set_last_error(e)?; - return interp_ok(Scalar::from_i32(-1)); + return this.set_last_error_and_return_i32(e); } }, } } // We ran out of attempts to create the file, return an error. - let eexist = this.eval_libc("EEXIST"); - this.set_last_error(eexist)?; - interp_ok(Scalar::from_i32(-1)) + this.set_last_error_and_return_i32(LibcError("EEXIST")) } } @@ -1702,7 +1660,7 @@ impl FileMetadata { ecx: &mut MiriInterpCx<'tcx>, path: &Path, follow_symlink: bool, - ) -> InterpResult<'tcx, Option<FileMetadata>> { + ) -> InterpResult<'tcx, Result<FileMetadata, IoError>> { let metadata = if follow_symlink { std::fs::metadata(path) } else { std::fs::symlink_metadata(path) }; @@ -1712,9 +1670,9 @@ impl FileMetadata { fn from_fd_num<'tcx>( ecx: &mut MiriInterpCx<'tcx>, fd_num: i32, - ) -> InterpResult<'tcx, Option<FileMetadata>> { + ) -> InterpResult<'tcx, Result<FileMetadata, IoError>> { let Some(fd) = ecx.machine.fds.get(fd_num) else { - return ecx.fd_not_found().map(|_: i32| None); + return interp_ok(Err(LibcError("EBADF"))); }; let file = &fd @@ -1734,12 +1692,11 @@ impl FileMetadata { fn from_meta<'tcx>( ecx: &mut MiriInterpCx<'tcx>, metadata: Result<std::fs::Metadata, std::io::Error>, - ) -> InterpResult<'tcx, Option<FileMetadata>> { + ) -> InterpResult<'tcx, Result<FileMetadata, IoError>> { let metadata = match metadata { Ok(metadata) => metadata, Err(e) => { - ecx.set_last_error(e)?; - return interp_ok(None); + return interp_ok(Err(e.into())); } }; @@ -1762,6 +1719,6 @@ impl FileMetadata { let modified = extract_sec_and_nsec(metadata.modified())?; // FIXME: Provide more fields using platform specific methods. - interp_ok(Some(FileMetadata { mode, size, created, accessed, modified })) + interp_ok(Ok(FileMetadata { mode, size, created, accessed, modified })) } } diff --git a/src/tools/miri/src/shims/unix/linux/epoll.rs b/src/tools/miri/src/shims/unix/linux/epoll.rs index cafc7161d26..de108665e9f 100644 --- a/src/tools/miri/src/shims/unix/linux/epoll.rs +++ b/src/tools/miri/src/shims/unix/linux/epoll.rs @@ -256,23 +256,14 @@ pub trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> { let epollhup = this.eval_libc_u32("EPOLLHUP"); let epollerr = this.eval_libc_u32("EPOLLERR"); - // Fail on unsupported operations. - if op & epoll_ctl_add != epoll_ctl_add - && op & epoll_ctl_mod != epoll_ctl_mod - && op & epoll_ctl_del != epoll_ctl_del - { - throw_unsup_format!("epoll_ctl: encountered unknown unsupported operation {:#x}", op); - } - // Throw EINVAL if epfd and fd have the same value. if epfd_value == fd { - this.set_last_error(LibcError("EINVAL"))?; - return interp_ok(Scalar::from_i32(-1)); + return this.set_last_error_and_return_i32(LibcError("EINVAL")); } // Check if epfd is a valid epoll file descriptor. let Some(epfd) = this.machine.fds.get(epfd_value) else { - return interp_ok(Scalar::from_i32(this.fd_not_found()?)); + return this.set_last_error_and_return_i32(LibcError("EBADF")); }; let epoll_file_description = epfd .downcast::<Epoll>() @@ -282,7 +273,7 @@ pub trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> { let ready_list = &epoll_file_description.ready_list; let Some(fd_ref) = this.machine.fds.get(fd) else { - return interp_ok(Scalar::from_i32(this.fd_not_found()?)); + return this.set_last_error_and_return_i32(LibcError("EBADF")); }; let id = fd_ref.get_id(); @@ -332,15 +323,11 @@ pub trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> { // Check the existence of fd in the interest list. if op == epoll_ctl_add { if interest_list.contains_key(&epoll_key) { - let eexist = this.eval_libc("EEXIST"); - this.set_last_error(eexist)?; - return interp_ok(Scalar::from_i32(-1)); + return this.set_last_error_and_return_i32(LibcError("EEXIST")); } } else { if !interest_list.contains_key(&epoll_key) { - let enoent = this.eval_libc("ENOENT"); - this.set_last_error(enoent)?; - return interp_ok(Scalar::from_i32(-1)); + return this.set_last_error_and_return_i32(LibcError("ENOENT")); } } @@ -368,15 +355,13 @@ pub trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> { // Notification will be returned for current epfd if there is event in the file // descriptor we registered. check_and_update_one_event_interest(&fd_ref, interest, id, this)?; - return interp_ok(Scalar::from_i32(0)); + interp_ok(Scalar::from_i32(0)) } else if op == epoll_ctl_del { let epoll_key = (id, fd); // Remove epoll_event_interest from interest_list. let Some(epoll_interest) = interest_list.remove(&epoll_key) else { - let enoent = this.eval_libc("ENOENT"); - this.set_last_error(enoent)?; - return interp_ok(Scalar::from_i32(-1)); + return this.set_last_error_and_return_i32(LibcError("ENOENT")); }; // All related Weak<EpollEventInterest> will fail to upgrade after the drop. drop(epoll_interest); @@ -394,9 +379,10 @@ pub trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> { .unwrap() .retain(|event| event.upgrade().is_some()); - return interp_ok(Scalar::from_i32(0)); + interp_ok(Scalar::from_i32(0)) + } else { + throw_unsup_format!("unsupported epoll_ctl operation: {op}"); } - interp_ok(Scalar::from_i32(-1)) } /// The `epoll_wait()` system call waits for events on the `Epoll` @@ -447,9 +433,7 @@ pub trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> { let timeout = this.read_scalar(timeout)?.to_i32()?; if epfd_value <= 0 || maxevents <= 0 { - this.set_last_error(LibcError("EINVAL"))?; - this.write_int(-1, dest)?; - return interp_ok(()); + return this.set_last_error_and_return(LibcError("EINVAL"), dest); } // This needs to come after the maxevents value check, or else maxevents.try_into().unwrap() @@ -460,9 +444,7 @@ pub trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> { )?; let Some(epfd) = this.machine.fds.get(epfd_value) else { - let result_value: i32 = this.fd_not_found()?; - this.write_int(result_value, dest)?; - return interp_ok(()); + return this.set_last_error_and_return(LibcError("EBADF"), dest); }; // Create a weak ref of epfd and pass it to callback so we will make sure that epfd // is not close after the thread unblocks. diff --git a/src/tools/miri/src/shims/unix/linux/foreign_items.rs b/src/tools/miri/src/shims/unix/linux/foreign_items.rs index e73bde1ddb6..6616a9845c0 100644 --- a/src/tools/miri/src/shims/unix/linux/foreign_items.rs +++ b/src/tools/miri/src/shims/unix/linux/foreign_items.rs @@ -84,6 +84,7 @@ pub trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> { this.read_scalar(thread)?, this.read_scalar(name)?, TASK_COMM_LEN, + /* truncate */ false, )?; let res = if res { Scalar::from_u32(0) } else { this.eval_libc("ERANGE") }; this.write_scalar(res, dest)?; diff --git a/src/tools/miri/src/shims/unix/linux/mem.rs b/src/tools/miri/src/shims/unix/linux/mem.rs index 4f2e17d50c8..d5f9669b360 100644 --- a/src/tools/miri/src/shims/unix/linux/mem.rs +++ b/src/tools/miri/src/shims/unix/linux/mem.rs @@ -24,7 +24,7 @@ pub trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> { // old_address must be a multiple of the page size #[allow(clippy::arithmetic_side_effects)] // PAGE_SIZE is nonzero if old_address.addr().bytes() % this.machine.page_size != 0 || new_size == 0 { - this.set_last_error(this.eval_libc("EINVAL"))?; + this.set_last_error(LibcError("EINVAL"))?; return interp_ok(this.eval_libc("MAP_FAILED")); } @@ -38,7 +38,7 @@ pub trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> { if flags & this.eval_libc_i32("MREMAP_MAYMOVE") == 0 { // We only support MREMAP_MAYMOVE, so not passing the flag is just a failure - this.set_last_error(this.eval_libc("EINVAL"))?; + this.set_last_error(LibcError("EINVAL"))?; return interp_ok(this.eval_libc("MAP_FAILED")); } diff --git a/src/tools/miri/src/shims/unix/linux/sync.rs b/src/tools/miri/src/shims/unix/linux/sync.rs index 941011bfac6..c258be78f76 100644 --- a/src/tools/miri/src/shims/unix/linux/sync.rs +++ b/src/tools/miri/src/shims/unix/linux/sync.rs @@ -63,8 +63,7 @@ pub fn futex<'tcx>( }; if bitset == 0 { - this.set_last_error(LibcError("EINVAL"))?; - this.write_scalar(Scalar::from_target_isize(-1, this), dest)?; + this.set_last_error_and_return(LibcError("EINVAL"), dest)?; return interp_ok(()); } @@ -75,9 +74,7 @@ pub fn futex<'tcx>( let duration = match this.read_timespec(&timeout)? { Some(duration) => duration, None => { - this.set_last_error(LibcError("EINVAL"))?; - this.write_scalar(Scalar::from_target_isize(-1, this), dest)?; - return interp_ok(()); + return this.set_last_error_and_return(LibcError("EINVAL"), dest); } }; let timeout_clock = if op & futex_realtime == futex_realtime { @@ -153,14 +150,12 @@ pub fn futex<'tcx>( Scalar::from_target_isize(0, this), // retval_succ Scalar::from_target_isize(-1, this), // retval_timeout dest.clone(), - this.eval_libc("ETIMEDOUT"), + this.eval_libc("ETIMEDOUT"), // errno_timeout ); } else { // The futex value doesn't match the expected value, so we return failure // right away without sleeping: -1 and errno set to EAGAIN. - let eagain = this.eval_libc("EAGAIN"); - this.set_last_error(eagain)?; - this.write_scalar(Scalar::from_target_isize(-1, this), dest)?; + return this.set_last_error_and_return(LibcError("EAGAIN"), dest); } } // FUTEX_WAKE: (int *addr, int op = FUTEX_WAKE, int val) @@ -180,9 +175,7 @@ pub fn futex<'tcx>( u32::MAX }; if bitset == 0 { - this.set_last_error(LibcError("EINVAL"))?; - this.write_scalar(Scalar::from_target_isize(-1, this), dest)?; - return interp_ok(()); + return this.set_last_error_and_return(LibcError("EINVAL"), dest); } // Together with the SeqCst fence in futex_wait, this makes sure that futex_wait // will see the latest value on addr which could be changed by our caller diff --git a/src/tools/miri/src/shims/unix/macos/foreign_items.rs b/src/tools/miri/src/shims/unix/macos/foreign_items.rs index b199992245c..cd07bc9e013 100644 --- a/src/tools/miri/src/shims/unix/macos/foreign_items.rs +++ b/src/tools/miri/src/shims/unix/macos/foreign_items.rs @@ -181,6 +181,7 @@ pub trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> { thread, this.read_scalar(name)?, this.eval_libc("MAXTHREADNAMESIZE").to_target_usize(this)?.try_into().unwrap(), + /* truncate */ false, )? { Scalar::from_u32(0) } else { diff --git a/src/tools/miri/src/shims/unix/mem.rs b/src/tools/miri/src/shims/unix/mem.rs index 9273748ef3b..9371edfc83d 100644 --- a/src/tools/miri/src/shims/unix/mem.rs +++ b/src/tools/miri/src/shims/unix/mem.rs @@ -57,11 +57,11 @@ pub trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> { // First, we do some basic argument validation as required by mmap if (flags & (map_private | map_shared)).count_ones() != 1 { - this.set_last_error(this.eval_libc("EINVAL"))?; + this.set_last_error(LibcError("EINVAL"))?; return interp_ok(this.eval_libc("MAP_FAILED")); } if length == 0 { - this.set_last_error(this.eval_libc("EINVAL"))?; + this.set_last_error(LibcError("EINVAL"))?; return interp_ok(this.eval_libc("MAP_FAILED")); } @@ -103,11 +103,11 @@ pub trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> { let align = this.machine.page_align(); let Some(map_length) = length.checked_next_multiple_of(this.machine.page_size) else { - this.set_last_error(this.eval_libc("EINVAL"))?; + this.set_last_error(LibcError("EINVAL"))?; return interp_ok(this.eval_libc("MAP_FAILED")); }; if map_length > this.target_usize_max() { - this.set_last_error(this.eval_libc("EINVAL"))?; + this.set_last_error(LibcError("EINVAL"))?; return interp_ok(this.eval_libc("MAP_FAILED")); } @@ -134,16 +134,14 @@ pub trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> { // as a dealloc. #[allow(clippy::arithmetic_side_effects)] // PAGE_SIZE is nonzero if addr.addr().bytes() % this.machine.page_size != 0 { - this.set_last_error(this.eval_libc("EINVAL"))?; - return interp_ok(Scalar::from_i32(-1)); + return this.set_last_error_and_return_i32(LibcError("EINVAL")); } let Some(length) = length.checked_next_multiple_of(this.machine.page_size) else { - this.set_last_error(this.eval_libc("EINVAL"))?; - return interp_ok(Scalar::from_i32(-1)); + return this.set_last_error_and_return_i32(LibcError("EINVAL")); }; if length > this.target_usize_max() { - this.set_last_error(this.eval_libc("EINVAL"))?; + this.set_last_error(LibcError("EINVAL"))?; return interp_ok(this.eval_libc("MAP_FAILED")); } diff --git a/src/tools/miri/src/shims/unix/solarish/foreign_items.rs b/src/tools/miri/src/shims/unix/solarish/foreign_items.rs index 7f3d0f07bdc..c9c1b01b8b1 100644 --- a/src/tools/miri/src/shims/unix/solarish/foreign_items.rs +++ b/src/tools/miri/src/shims/unix/solarish/foreign_items.rs @@ -30,6 +30,7 @@ pub trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> { this.read_scalar(thread)?, this.read_scalar(name)?, max_len, + /* truncate */ false, )?; let res = if res { Scalar::from_u32(0) } else { this.eval_libc("ERANGE") }; this.write_scalar(res, dest)?; diff --git a/src/tools/miri/src/shims/unix/thread.rs b/src/tools/miri/src/shims/unix/thread.rs index 7f97afc8e4b..51256d800a4 100644 --- a/src/tools/miri/src/shims/unix/thread.rs +++ b/src/tools/miri/src/shims/unix/thread.rs @@ -64,23 +64,29 @@ pub trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> { } /// Set the name of the specified thread. If the name including the null terminator - /// is longer than `name_max_len`, then `false` is returned. + /// is longer or equals to `name_max_len`, then if `truncate` is set the truncated name + /// is used as the thread name, otherwise `false` is returned. fn pthread_setname_np( &mut self, thread: Scalar, name: Scalar, name_max_len: usize, + truncate: bool, ) -> InterpResult<'tcx, bool> { let this = self.eval_context_mut(); let thread = thread.to_int(this.libc_ty_layout("pthread_t").size)?; let thread = ThreadId::try_from(thread).unwrap(); let name = name.to_pointer(this)?; - let name = this.read_c_str(name)?.to_owned(); + let mut name = this.read_c_str(name)?.to_owned(); // Comparing with `>=` to account for null terminator. if name.len() >= name_max_len { - return interp_ok(false); + if truncate { + name.truncate(name_max_len.saturating_sub(1)); + } else { + return interp_ok(false); + } } this.set_thread_name(thread, name); diff --git a/src/tools/miri/src/shims/windows/sync.rs b/src/tools/miri/src/shims/windows/sync.rs index f8861085fe5..f7566a8112d 100644 --- a/src/tools/miri/src/shims/windows/sync.rs +++ b/src/tools/miri/src/shims/windows/sync.rs @@ -202,7 +202,7 @@ pub trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> { Scalar::from_i32(1), // retval_succ Scalar::from_i32(0), // retval_timeout dest.clone(), - this.eval_windows("c", "ERROR_TIMEOUT"), + this.eval_windows("c", "ERROR_TIMEOUT"), // errno_timeout ); } diff --git a/src/tools/miri/test_dependencies/Cargo.lock b/src/tools/miri/test_dependencies/Cargo.lock index 64bfc84ef20..0a5e9f62dd9 100644 --- a/src/tools/miri/test_dependencies/Cargo.lock +++ b/src/tools/miri/test_dependencies/Cargo.lock @@ -1,6 +1,6 @@ # This file is automatically @generated by Cargo. # It is not intended for manual editing. -version = 3 +version = 4 [[package]] name = "addr2line" @@ -128,9 +128,9 @@ dependencies = [ [[package]] name = "libc" -version = "0.2.158" +version = "0.2.161" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d8adc4bb1803a324070e64a98ae98f38934d91957a99cfb3a43dcbc01bc56439" +checksum = "8e9489c2807c139ffd9c1794f4af0ebe86a828db53ecdc7fea2111d0fed085d1" [[package]] name = "linux-raw-sys" diff --git a/src/tools/miri/tests/fail-dep/libc/prctl-get-name-buffer-too-small.rs b/src/tools/miri/tests/fail-dep/libc/prctl-get-name-buffer-too-small.rs new file mode 100644 index 00000000000..4b731866aca --- /dev/null +++ b/src/tools/miri/tests/fail-dep/libc/prctl-get-name-buffer-too-small.rs @@ -0,0 +1,10 @@ +//! Ensure we report UB when the buffer is smaller than 16 bytes (even if the thread +//! name would fit in the smaller buffer). +//@only-target: android # Miri supports prctl for Android only + +fn main() { + let mut buf = vec![0u8; 15]; + unsafe { + libc::prctl(libc::PR_GET_NAME, buf.as_mut_ptr().cast::<libc::c_char>()); //~ ERROR: memory access failed: expected a pointer to 16 bytes of memory, but got alloc952 which is only 15 bytes from the end of the allocation + } +} diff --git a/src/tools/miri/tests/fail-dep/libc/prctl-get-name-buffer-too-small.stderr b/src/tools/miri/tests/fail-dep/libc/prctl-get-name-buffer-too-small.stderr new file mode 100644 index 00000000000..275a38e593c --- /dev/null +++ b/src/tools/miri/tests/fail-dep/libc/prctl-get-name-buffer-too-small.stderr @@ -0,0 +1,21 @@ +error: Undefined Behavior: memory access failed: expected a pointer to 16 bytes of memory, but got ALLOC which is only 15 bytes from the end of the allocation + --> tests/fail-dep/libc/prctl-threadname.rs:LL:CC + | +LL | libc::prctl(libc::PR_GET_NAME, buf.as_mut_ptr().cast::<libc::c_char>()); + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ memory access failed: expected a pointer to 16 bytes of memory, but got ALLOC which is only 15 bytes from the end of the allocation + | + = help: this indicates a bug in the program: it performed an invalid operation, and caused Undefined Behavior + = help: see https://doc.rust-lang.org/nightly/reference/behavior-considered-undefined.html for further information +help: ALLOC was allocated here: + --> tests/fail-dep/libc/prctl-threadname.rs:LL:CC + | +LL | let mut buf = vec![0u8; 15]; + | ^^^^^^^^^^^^^ + = note: BACKTRACE (of the first span): + = note: inside `main` at tests/fail-dep/libc/prctl-threadname.rs:LL:CC + = note: this error originates in the macro `vec` (in Nightly builds, run with -Z macro-backtrace for more info) + +note: some details are omitted, run with `MIRIFLAGS=-Zmiri-backtrace=full` for a verbose backtrace + +error: aborting due to 1 previous error + diff --git a/src/tools/miri/tests/fail-dep/libc/socketpair-data-race.rs b/src/tools/miri/tests/fail-dep/libc/socketpair-data-race.rs index f4c009456d2..55491da9f60 100644 --- a/src/tools/miri/tests/fail-dep/libc/socketpair-data-race.rs +++ b/src/tools/miri/tests/fail-dep/libc/socketpair-data-race.rs @@ -1,7 +1,7 @@ //! This is a regression test for <https://github.com/rust-lang/miri/issues/3947>: we had some //! faulty logic around `release_clock` that led to this code not reporting a data race. //@ignore-target: windows # no libc socketpair on Windows -//@compile-flags: -Zmiri-preemption-rate=0 +//@compile-flags: -Zmiri-preemption-rate=0 -Zmiri-address-reuse-rate=0 use std::thread; fn main() { diff --git a/src/tools/miri/tests/fail/coroutine-pinned-moved.stderr b/src/tools/miri/tests/fail/coroutine-pinned-moved.stderr index c2c6ce987e5..9b4890c7cc6 100644 --- a/src/tools/miri/tests/fail/coroutine-pinned-moved.stderr +++ b/src/tools/miri/tests/fail/coroutine-pinned-moved.stderr @@ -23,7 +23,7 @@ note: inside `<CoroutineIteratorAdapter<{static coroutine@tests/fail/coroutine-p | LL | match me.resume(()) { | ^^^^^^^^^^^^^ - = note: inside `<std::boxed::Box<CoroutineIteratorAdapter<{static coroutine@tests/fail/coroutine-pinned-moved.rs:LL:CC}>> as std::iter::Iterator>::next` at RUSTLIB/alloc/src/boxed.rs:LL:CC + = note: inside `std::boxed::iter::<impl std::iter::Iterator for std::boxed::Box<CoroutineIteratorAdapter<{static coroutine@tests/fail/coroutine-pinned-moved.rs:LL:CC}>>>::next` at RUSTLIB/alloc/src/boxed/iter.rs:LL:CC note: inside `main` --> tests/fail/coroutine-pinned-moved.rs:LL:CC | diff --git a/src/tools/miri/tests/fail/provenance/ptr_invalid.rs b/src/tools/miri/tests/fail/provenance/ptr_invalid.rs index d4479f32e56..c91f4ec158f 100644 --- a/src/tools/miri/tests/fail/provenance/ptr_invalid.rs +++ b/src/tools/miri/tests/fail/provenance/ptr_invalid.rs @@ -1,4 +1,3 @@ - // Ensure that a `ptr::without_provenance` ptr is truly invalid. fn main() { let x = 42; diff --git a/src/tools/miri/tests/fail/tail_calls/dangling-local-var.rs b/src/tools/miri/tests/fail/tail_calls/dangling-local-var.rs new file mode 100644 index 00000000000..b69f7ee9dff --- /dev/null +++ b/src/tools/miri/tests/fail/tail_calls/dangling-local-var.rs @@ -0,0 +1,16 @@ +#![feature(explicit_tail_calls)] +#![allow(incomplete_features)] + +fn g(x: *const i32) { + let _val = unsafe { *x }; //~ERROR: has been freed, so this pointer is dangling +} + +fn f(_x: *const i32) { + let local = 0; + let ptr = &local as *const i32; + become g(ptr) +} + +fn main() { + f(std::ptr::null()); +} diff --git a/src/tools/miri/tests/fail/tail_calls/dangling-local-var.stderr b/src/tools/miri/tests/fail/tail_calls/dangling-local-var.stderr new file mode 100644 index 00000000000..6acd69ab3f8 --- /dev/null +++ b/src/tools/miri/tests/fail/tail_calls/dangling-local-var.stderr @@ -0,0 +1,30 @@ +error: Undefined Behavior: memory access failed: ALLOC has been freed, so this pointer is dangling + --> tests/fail/tail_calls/dangling-local-var.rs:LL:CC + | +LL | let _val = unsafe { *x }; + | ^^ memory access failed: ALLOC has been freed, so this pointer is dangling + | + = help: this indicates a bug in the program: it performed an invalid operation, and caused Undefined Behavior + = help: see https://doc.rust-lang.org/nightly/reference/behavior-considered-undefined.html for further information +help: ALLOC was allocated here: + --> tests/fail/tail_calls/dangling-local-var.rs:LL:CC + | +LL | let local = 0; + | ^^^^^ +help: ALLOC was deallocated here: + --> tests/fail/tail_calls/dangling-local-var.rs:LL:CC + | +LL | } + | ^ + = note: BACKTRACE (of the first span): + = note: inside `g` at tests/fail/tail_calls/dangling-local-var.rs:LL:CC +note: inside `main` + --> tests/fail/tail_calls/dangling-local-var.rs:LL:CC + | +LL | f(std::ptr::null()); + | ^^^^^^^^^^^^^^^^^^^ + +note: some details are omitted, run with `MIRIFLAGS=-Zmiri-backtrace=full` for a verbose backtrace + +error: aborting due to 1 previous error + diff --git a/src/tools/miri/tests/pass-dep/libc/prctl-threadname.rs b/src/tools/miri/tests/pass-dep/libc/prctl-threadname.rs new file mode 100644 index 00000000000..87ae3753fea --- /dev/null +++ b/src/tools/miri/tests/pass-dep/libc/prctl-threadname.rs @@ -0,0 +1,74 @@ +//@only-target: android # Miri supports prctl for Android only +use std::ffi::{CStr, CString}; +use std::thread; + +// The Linux kernel all names 16 bytes long including the null terminator. +const MAX_THREAD_NAME_LEN: usize = 16; + +fn main() { + // The short name should be shorter than 16 bytes which POSIX promises + // for thread names. The length includes a null terminator. + let short_name = "test_named".to_owned(); + let long_name = std::iter::once("test_named_thread_truncation") + .chain(std::iter::repeat(" yada").take(100)) + .collect::<String>(); + + fn set_thread_name(name: &CStr) -> i32 { + unsafe { libc::prctl(libc::PR_SET_NAME, name.as_ptr().cast::<libc::c_char>()) } + } + + fn get_thread_name(name: &mut [u8]) -> i32 { + assert!(name.len() >= MAX_THREAD_NAME_LEN); + unsafe { libc::prctl(libc::PR_GET_NAME, name.as_mut_ptr().cast::<libc::c_char>()) } + } + + // Set name via Rust API, get it via prctl. + let long_name2 = long_name.clone(); + thread::Builder::new() + .name(long_name.clone()) + .spawn(move || { + let mut buf = vec![0u8; MAX_THREAD_NAME_LEN]; + assert_eq!(get_thread_name(&mut buf), 0); + let cstr = CStr::from_bytes_until_nul(&buf).unwrap(); + let truncated_name = &long_name2[..long_name2.len().min(MAX_THREAD_NAME_LEN - 1)]; + assert_eq!(cstr.to_bytes(), truncated_name.as_bytes()); + }) + .unwrap() + .join() + .unwrap(); + + // Set name via prctl and get it again (short name). + thread::Builder::new() + .spawn(move || { + // Set short thread name. + let cstr = CString::new(short_name.clone()).unwrap(); + assert!(cstr.to_bytes_with_nul().len() <= MAX_THREAD_NAME_LEN); // this should fit + assert_eq!(set_thread_name(&cstr), 0); + + let mut buf = vec![0u8; MAX_THREAD_NAME_LEN]; + assert_eq!(get_thread_name(&mut buf), 0); + let cstr = CStr::from_bytes_until_nul(&buf).unwrap(); + assert_eq!(cstr.to_bytes(), short_name.as_bytes()); + }) + .unwrap() + .join() + .unwrap(); + + // Set name via prctl and get it again (long name). + thread::Builder::new() + .spawn(move || { + // Set full thread name. + let cstr = CString::new(long_name.clone()).unwrap(); + assert!(cstr.to_bytes_with_nul().len() > MAX_THREAD_NAME_LEN); + // Names are truncated by the Linux kernel. + assert_eq!(set_thread_name(&cstr), 0); + + let mut buf = vec![0u8; MAX_THREAD_NAME_LEN]; + assert_eq!(get_thread_name(&mut buf), 0); + let cstr = CStr::from_bytes_until_nul(&buf).unwrap(); + assert_eq!(cstr.to_bytes(), &long_name.as_bytes()[..(MAX_THREAD_NAME_LEN - 1)]); + }) + .unwrap() + .join() + .unwrap(); +} diff --git a/src/tools/miri/tests/pass-dep/libc/pthread-threadname.rs b/src/tools/miri/tests/pass-dep/libc/pthread-threadname.rs index 404ef7cc42d..0e5b501bbcc 100644 --- a/src/tools/miri/tests/pass-dep/libc/pthread-threadname.rs +++ b/src/tools/miri/tests/pass-dep/libc/pthread-threadname.rs @@ -1,4 +1,5 @@ //@ignore-target: windows # No pthreads on Windows +//@ignore-target: android # No pthread_{get,set}_name on Android use std::ffi::{CStr, CString}; use std::thread; @@ -65,6 +66,22 @@ fn main() { } } + // Set name via Rust API, get it via pthreads. + let long_name2 = long_name.clone(); + thread::Builder::new() + .name(long_name.clone()) + .spawn(move || { + let mut buf = vec![0u8; long_name2.len() + 1]; + assert_eq!(get_thread_name(&mut buf), 0); + let cstr = CStr::from_bytes_until_nul(&buf).unwrap(); + let truncated_name = &long_name2[..long_name2.len().min(MAX_THREAD_NAME_LEN - 1)]; + assert_eq!(cstr.to_bytes(), truncated_name.as_bytes()); + }) + .unwrap() + .join() + .unwrap(); + + // Set name via pthread and get it again (short name). thread::Builder::new() .spawn(move || { // Set short thread name. @@ -130,6 +147,7 @@ fn main() { .join() .unwrap(); + // Set name via pthread and get it again (long name). thread::Builder::new() .spawn(move || { // Set full thread name. diff --git a/src/tools/miri/tests/pass/dyn-upcast.rs b/src/tools/miri/tests/pass/dyn-upcast.rs index 306e9ab9c67..61410f7c4e0 100644 --- a/src/tools/miri/tests/pass/dyn-upcast.rs +++ b/src/tools/miri/tests/pass/dyn-upcast.rs @@ -433,7 +433,8 @@ fn replace_vptr() { } fn drop_principal() { - use std::{alloc::Layout, any::Any}; + use std::alloc::Layout; + use std::any::Any; const fn yeet_principal(x: Box<dyn Any + Send>) -> Box<dyn Send> { x diff --git a/src/tools/miri/tests/pass/float.rs b/src/tools/miri/tests/pass/float.rs index 853d3e80517..66843ca584b 100644 --- a/src/tools/miri/tests/pass/float.rs +++ b/src/tools/miri/tests/pass/float.rs @@ -157,13 +157,18 @@ fn basic() { assert_eq(-{ 5.0_f128 }, -5.0_f128); // infinities, NaN - // FIXME(f16_f128): add when constants and `is_infinite` are available + assert!((5.0_f16 / 0.0).is_infinite()); + assert_ne!({ 5.0_f16 / 0.0 }, { -5.0_f16 / 0.0 }); assert!((5.0_f32 / 0.0).is_infinite()); assert_ne!({ 5.0_f32 / 0.0 }, { -5.0_f32 / 0.0 }); assert!((5.0_f64 / 0.0).is_infinite()); assert_ne!({ 5.0_f64 / 0.0 }, { 5.0_f64 / -0.0 }); + assert!((5.0_f128 / 0.0).is_infinite()); + assert_ne!({ 5.0_f128 / 0.0 }, { 5.0_f128 / -0.0 }); + assert_ne!(f16::NAN, f16::NAN); assert_ne!(f32::NAN, f32::NAN); assert_ne!(f64::NAN, f64::NAN); + assert_ne!(f128::NAN, f128::NAN); // negative zero let posz = 0.0f16; @@ -215,9 +220,14 @@ fn basic() { assert!((black_box(-1.0f128) % 1.0).is_sign_negative()); assert!((black_box(-1.0f128) % -1.0).is_sign_negative()); - // FIXME(f16_f128): add when `abs` is available + assert_eq!((-1.0f16).abs(), 1.0f16); + assert_eq!(34.2f16.abs(), 34.2f16); assert_eq!((-1.0f32).abs(), 1.0f32); + assert_eq!(34.2f32.abs(), 34.2f32); + assert_eq!((-1.0f64).abs(), 1.0f64); assert_eq!(34.2f64.abs(), 34.2f64); + assert_eq!((-1.0f128).abs(), 1.0f128); + assert_eq!(34.2f128.abs(), 34.2f128); } /// Test casts from floats to ints and back @@ -654,6 +664,14 @@ fn casts() { } fn ops() { + // f16 min/max + assert_eq((1.0_f16).max(-1.0), 1.0); + assert_eq((1.0_f16).min(-1.0), -1.0); + assert_eq(f16::NAN.min(9.0), 9.0); + assert_eq(f16::NAN.max(-9.0), -9.0); + assert_eq((9.0_f16).min(f16::NAN), 9.0); + assert_eq((-9.0_f16).max(f16::NAN), -9.0); + // f32 min/max assert_eq((1.0 as f32).max(-1.0), 1.0); assert_eq((1.0 as f32).min(-1.0), -1.0); @@ -670,6 +688,21 @@ fn ops() { assert_eq((9.0 as f64).min(f64::NAN), 9.0); assert_eq((-9.0 as f64).max(f64::NAN), -9.0); + // f128 min/max + assert_eq((1.0_f128).max(-1.0), 1.0); + assert_eq((1.0_f128).min(-1.0), -1.0); + assert_eq(f128::NAN.min(9.0), 9.0); + assert_eq(f128::NAN.max(-9.0), -9.0); + assert_eq((9.0_f128).min(f128::NAN), 9.0); + assert_eq((-9.0_f128).max(f128::NAN), -9.0); + + // f16 copysign + assert_eq(3.5_f16.copysign(0.42), 3.5_f16); + assert_eq(3.5_f16.copysign(-0.42), -3.5_f16); + assert_eq((-3.5_f16).copysign(0.42), 3.5_f16); + assert_eq((-3.5_f16).copysign(-0.42), -3.5_f16); + assert!(f16::NAN.copysign(1.0).is_nan()); + // f32 copysign assert_eq(3.5_f32.copysign(0.42), 3.5_f32); assert_eq(3.5_f32.copysign(-0.42), -3.5_f32); @@ -683,6 +716,13 @@ fn ops() { assert_eq((-3.5_f64).copysign(0.42), 3.5_f64); assert_eq((-3.5_f64).copysign(-0.42), -3.5_f64); assert!(f64::NAN.copysign(1.0).is_nan()); + + // f128 copysign + assert_eq(3.5_f128.copysign(0.42), 3.5_f128); + assert_eq(3.5_f128.copysign(-0.42), -3.5_f128); + assert_eq((-3.5_f128).copysign(0.42), 3.5_f128); + assert_eq((-3.5_f128).copysign(-0.42), -3.5_f128); + assert!(f128::NAN.copysign(1.0).is_nan()); } /// Tests taken from rustc test suite. @@ -807,6 +847,18 @@ fn nan_casts() { fn rounding() { // Test cases taken from the library's tests for this feature + // f16 + assert_eq(2.5f16.round_ties_even(), 2.0f16); + assert_eq(1.0f16.round_ties_even(), 1.0f16); + assert_eq(1.3f16.round_ties_even(), 1.0f16); + assert_eq(1.5f16.round_ties_even(), 2.0f16); + assert_eq(1.7f16.round_ties_even(), 2.0f16); + assert_eq(0.0f16.round_ties_even(), 0.0f16); + assert_eq((-0.0f16).round_ties_even(), -0.0f16); + assert_eq((-1.0f16).round_ties_even(), -1.0f16); + assert_eq((-1.3f16).round_ties_even(), -1.0f16); + assert_eq((-1.5f16).round_ties_even(), -2.0f16); + assert_eq((-1.7f16).round_ties_even(), -2.0f16); // f32 assert_eq(2.5f32.round_ties_even(), 2.0f32); assert_eq(1.0f32.round_ties_even(), 1.0f32); @@ -831,23 +883,59 @@ fn rounding() { assert_eq((-1.3f64).round_ties_even(), -1.0f64); assert_eq((-1.5f64).round_ties_even(), -2.0f64); assert_eq((-1.7f64).round_ties_even(), -2.0f64); - + // f128 + assert_eq(2.5f128.round_ties_even(), 2.0f128); + assert_eq(1.0f128.round_ties_even(), 1.0f128); + assert_eq(1.3f128.round_ties_even(), 1.0f128); + assert_eq(1.5f128.round_ties_even(), 2.0f128); + assert_eq(1.7f128.round_ties_even(), 2.0f128); + assert_eq(0.0f128.round_ties_even(), 0.0f128); + assert_eq((-0.0f128).round_ties_even(), -0.0f128); + assert_eq((-1.0f128).round_ties_even(), -1.0f128); + assert_eq((-1.3f128).round_ties_even(), -1.0f128); + assert_eq((-1.5f128).round_ties_even(), -2.0f128); + assert_eq((-1.7f128).round_ties_even(), -2.0f128); + + assert_eq!(3.8f16.floor(), 3.0f16); + assert_eq!((-1.1f16).floor(), -2.0f16); assert_eq!(3.8f32.floor(), 3.0f32); + assert_eq!((-1.1f32).floor(), -2.0f32); + assert_eq!(3.8f64.floor(), 3.0f64); assert_eq!((-1.1f64).floor(), -2.0f64); + assert_eq!(3.8f128.floor(), 3.0f128); + assert_eq!((-1.1f128).floor(), -2.0f128); + assert_eq!(3.8f16.ceil(), 4.0f16); + assert_eq!((-2.3f16).ceil(), -2.0f16); + assert_eq!(3.8f32.ceil(), 4.0f32); assert_eq!((-2.3f32).ceil(), -2.0f32); assert_eq!(3.8f64.ceil(), 4.0f64); + assert_eq!((-2.3f64).ceil(), -2.0f64); + assert_eq!(3.8f128.ceil(), 4.0f128); + assert_eq!((-2.3f128).ceil(), -2.0f128); + assert_eq!(0.1f16.trunc(), 0.0f16); + assert_eq!((-0.1f16).trunc(), 0.0f16); assert_eq!(0.1f32.trunc(), 0.0f32); + assert_eq!((-0.1f32).trunc(), 0.0f32); + assert_eq!(0.1f64.trunc(), 0.0f64); assert_eq!((-0.1f64).trunc(), 0.0f64); + assert_eq!(0.1f128.trunc(), 0.0f128); + assert_eq!((-0.1f128).trunc(), 0.0f128); + assert_eq!(3.3_f16.round(), 3.0); + assert_eq!(2.5_f16.round(), 3.0); assert_eq!(3.3_f32.round(), 3.0); assert_eq!(2.5_f32.round(), 3.0); assert_eq!(3.9_f64.round(), 4.0); assert_eq!(2.5_f64.round(), 3.0); + assert_eq!(3.9_f128.round(), 4.0); + assert_eq!(2.5_f128.round(), 3.0); } fn mul_add() { + // FIXME(f16_f128): add when supported + assert_eq!(3.0f32.mul_add(2.0f32, 5.0f32), 11.0); assert_eq!(0.0f32.mul_add(-2.0, f32::consts::E), f32::consts::E); assert_eq!(3.0f64.mul_add(2.0, 5.0), 11.0); @@ -983,7 +1071,7 @@ fn test_fast() { use std::intrinsics::{fadd_fast, fdiv_fast, fmul_fast, frem_fast, fsub_fast}; #[inline(never)] - pub fn test_operations_f64(a: f64, b: f64) { + pub fn test_operations_f16(a: f16, b: f16) { // make sure they all map to the correct operation unsafe { assert_eq!(fadd_fast(a, b), a + b); @@ -1006,10 +1094,38 @@ fn test_fast() { } } - test_operations_f64(1., 2.); - test_operations_f64(10., 5.); + #[inline(never)] + pub fn test_operations_f64(a: f64, b: f64) { + // make sure they all map to the correct operation + unsafe { + assert_eq!(fadd_fast(a, b), a + b); + assert_eq!(fsub_fast(a, b), a - b); + assert_eq!(fmul_fast(a, b), a * b); + assert_eq!(fdiv_fast(a, b), a / b); + assert_eq!(frem_fast(a, b), a % b); + } + } + + #[inline(never)] + pub fn test_operations_f128(a: f128, b: f128) { + // make sure they all map to the correct operation + unsafe { + assert_eq!(fadd_fast(a, b), a + b); + assert_eq!(fsub_fast(a, b), a - b); + assert_eq!(fmul_fast(a, b), a * b); + assert_eq!(fdiv_fast(a, b), a / b); + assert_eq!(frem_fast(a, b), a % b); + } + } + + test_operations_f16(11., 2.); + test_operations_f16(10., 15.); test_operations_f32(11., 2.); test_operations_f32(10., 15.); + test_operations_f64(1., 2.); + test_operations_f64(10., 5.); + test_operations_f128(1., 2.); + test_operations_f128(10., 5.); } fn test_algebraic() { @@ -1018,7 +1134,7 @@ fn test_algebraic() { }; #[inline(never)] - pub fn test_operations_f64(a: f64, b: f64) { + pub fn test_operations_f16(a: f16, b: f16) { // make sure they all map to the correct operation assert_eq!(fadd_algebraic(a, b), a + b); assert_eq!(fsub_algebraic(a, b), a - b); @@ -1037,15 +1153,41 @@ fn test_algebraic() { assert_eq!(frem_algebraic(a, b), a % b); } - test_operations_f64(1., 2.); - test_operations_f64(10., 5.); + #[inline(never)] + pub fn test_operations_f64(a: f64, b: f64) { + // make sure they all map to the correct operation + assert_eq!(fadd_algebraic(a, b), a + b); + assert_eq!(fsub_algebraic(a, b), a - b); + assert_eq!(fmul_algebraic(a, b), a * b); + assert_eq!(fdiv_algebraic(a, b), a / b); + assert_eq!(frem_algebraic(a, b), a % b); + } + + #[inline(never)] + pub fn test_operations_f128(a: f128, b: f128) { + // make sure they all map to the correct operation + assert_eq!(fadd_algebraic(a, b), a + b); + assert_eq!(fsub_algebraic(a, b), a - b); + assert_eq!(fmul_algebraic(a, b), a * b); + assert_eq!(fdiv_algebraic(a, b), a / b); + assert_eq!(frem_algebraic(a, b), a % b); + } + + test_operations_f16(11., 2.); + test_operations_f16(10., 15.); test_operations_f32(11., 2.); test_operations_f32(10., 15.); + test_operations_f64(1., 2.); + test_operations_f64(10., 5.); + test_operations_f128(1., 2.); + test_operations_f128(10., 5.); } fn test_fmuladd() { use std::intrinsics::{fmuladdf32, fmuladdf64}; + // FIXME(f16_f128): add when supported + #[inline(never)] pub fn test_operations_f32(a: f32, b: f32, c: f32) { assert_approx_eq!(unsafe { fmuladdf32(a, b, c) }, a * b + c); diff --git a/src/tools/run-make-support/Cargo.toml b/src/tools/run-make-support/Cargo.toml index d3605cd3dce..3affa199fa5 100644 --- a/src/tools/run-make-support/Cargo.toml +++ b/src/tools/run-make-support/Cargo.toml @@ -13,3 +13,6 @@ gimli = "0.31.0" build_helper = { path = "../build_helper" } serde_json = "1.0" libc = "0.2" + +[lib] +crate-type = ["lib", "dylib"] diff --git a/src/tools/rust-analyzer/.github/workflows/ci.yaml b/src/tools/rust-analyzer/.github/workflows/ci.yaml index 5cf4a8fd439..d82e46016dc 100644 --- a/src/tools/rust-analyzer/.github/workflows/ci.yaml +++ b/src/tools/rust-analyzer/.github/workflows/ci.yaml @@ -1,14 +1,10 @@ -# Please make sure that the `needs` fields for both `end-success` and `end-failure` +# Please make sure that the `needs` field for the `conclusion` job # are updated when adding new jobs! name: CI on: pull_request: - push: - branches: - - auto - - try - - automation/bors/try + merge_group: env: CARGO_INCREMENTAL: 0 @@ -237,20 +233,21 @@ jobs: - name: check for typos run: typos - end-success: - name: bors build finished - if: github.event.pusher.name == 'bors' && success() - runs-on: ubuntu-latest + conclusion: needs: [rust, rust-cross, typescript, typo-check] - steps: - - name: Mark the job as successful - run: exit 0 - - end-failure: - name: bors build finished - if: github.event.pusher.name == 'bors' && !success() + # We need to ensure this job does *not* get skipped if its dependencies fail, + # because a skipped job is considered a success by GitHub. So we have to + # overwrite `if:`. We use `!cancelled()` to ensure the job does still not get run + # when the workflow is canceled manually. + # + # ALL THE PREVIOUS JOBS NEED TO BE ADDED TO THE `needs` SECTION OF THIS JOB! + if: ${{ !cancelled() }} runs-on: ubuntu-latest - needs: [rust, rust-cross, typescript, typo-check] steps: - - name: Mark the job as a failure - run: exit 1 + # Manually check the status of all dependencies. `if: failure()` does not work. + - name: Conclusion + run: | + # Print the dependent jobs to see them in the CI log + jq -C <<< '${{ toJson(needs) }}' + # Check if all jobs that we depend on (in the needs array) were successful. + jq --exit-status 'all(.result == "success")' <<< '${{ toJson(needs) }}' diff --git a/src/tools/rust-analyzer/.gitignore b/src/tools/rust-analyzer/.gitignore index 68c87a6b1ed..c4470a45078 100644 --- a/src/tools/rust-analyzer/.gitignore +++ b/src/tools/rust-analyzer/.gitignore @@ -1,6 +1,5 @@ -/target/ +target/ /dist/ -crates/*/target **/*.rs.bk **/*.rs.pending-snap .idea/* diff --git a/src/tools/rust-analyzer/Cargo.lock b/src/tools/rust-analyzer/Cargo.lock index fd569571b38..695c37f6d7b 100644 --- a/src/tools/rust-analyzer/Cargo.lock +++ b/src/tools/rust-analyzer/Cargo.lock @@ -164,6 +164,7 @@ dependencies = [ "rustc-hash 2.0.0", "syntax", "syntax-bridge", + "tracing", "tt", ] @@ -556,6 +557,7 @@ dependencies = [ "syntax-bridge", "test-fixture", "test-utils", + "text-size", "tracing", "triomphe", "tt", @@ -670,7 +672,6 @@ dependencies = [ "syntax", "test-fixture", "test-utils", - "text-edit", "toolchain", "tracing", "triomphe", @@ -692,7 +693,6 @@ dependencies = [ "syntax", "test-fixture", "test-utils", - "text-edit", "tracing", ] @@ -711,7 +711,6 @@ dependencies = [ "syntax", "test-fixture", "test-utils", - "text-edit", "tracing", ] @@ -743,7 +742,6 @@ dependencies = [ "syntax", "test-fixture", "test-utils", - "text-edit", "tracing", "triomphe", ] @@ -765,7 +763,6 @@ dependencies = [ "syntax", "test-fixture", "test-utils", - "text-edit", "tracing", ] @@ -784,7 +781,6 @@ dependencies = [ "syntax", "test-fixture", "test-utils", - "text-edit", "triomphe", ] @@ -1497,9 +1493,9 @@ dependencies = [ [[package]] name = "ra-ap-rustc_abi" -version = "0.73.0" +version = "0.75.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "879ece0781e3c1cb670b9f29775c81a43a16db789d1296fad6bc5c74065b2fac" +checksum = "d5bc2cfc7264d84215a08875ef90a1d35f76b5c9ad1993515d2da7e4e40b2b4b" dependencies = [ "bitflags 2.6.0", "ra-ap-rustc_index", @@ -1508,9 +1504,9 @@ dependencies = [ [[package]] name = "ra-ap-rustc_index" -version = "0.73.0" +version = "0.75.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "6910087ff89bb9f3db114bfcd86b5139042731fe7278d3ff4ceaa69a140154a7" +checksum = "e8929140697812e5dd09e19cf446d85146332363f0dbc125d4214834c34ead96" dependencies = [ "arrayvec", "ra-ap-rustc_index_macros", @@ -1519,9 +1515,9 @@ dependencies = [ [[package]] name = "ra-ap-rustc_index_macros" -version = "0.73.0" +version = "0.75.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3b6f7bd12b678fbb37444ba77f3b0cfc13b7394a6dc7b0c799491fc9df0a9997" +checksum = "514a3f5d04c8b4a2750f29746cc9abb1f78deb7e72e4ad1dc95bbc608f3db157" dependencies = [ "proc-macro2", "quote", @@ -1530,9 +1526,9 @@ dependencies = [ [[package]] name = "ra-ap-rustc_lexer" -version = "0.73.0" +version = "0.75.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "119bc05b5b6bc3e7f5b67ce8b8080e185da94bd83c447f91b6b3f3ecf60cbab1" +checksum = "276fcb1205da071a0cd64416f3f0e198043c11f176c5b501a45dbf0cb33979f2" dependencies = [ "unicode-properties", "unicode-xid", @@ -1540,9 +1536,9 @@ dependencies = [ [[package]] name = "ra-ap-rustc_parse_format" -version = "0.73.0" +version = "0.75.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "70ed6150ae71d905c064dc88d7824ebb0fa81083f45d7477cba7b57176f2f635" +checksum = "961b30b22cfac296b14b72e9f95e79c16cebc8c926872755fb1568a6c4243a62" dependencies = [ "ra-ap-rustc_index", "ra-ap-rustc_lexer", @@ -1550,9 +1546,9 @@ dependencies = [ [[package]] name = "ra-ap-rustc_pattern_analysis" -version = "0.73.0" +version = "0.75.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "6e830862a0ec85fce211d34735315686bb8d6a12d418d6d735fb534aa1cd3293" +checksum = "614232513814a4b714fea7f11345d31c0c277bca3089bb6ca1ec20870bfc022a" dependencies = [ "ra-ap-rustc_index", "rustc-hash 2.0.0", @@ -1884,9 +1880,9 @@ checksum = "3c5e1a9a646d36c3599cd173a41282daf47c44583ad367b8e6837255952e5c67" [[package]] name = "smol_str" -version = "0.3.1" +version = "0.3.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "66eaf762c5af19db3108300515c8aa7a50efc90ff745f4c62288052ebf9fdd25" +checksum = "9676b89cd56310a87b93dec47b11af744f34d5fc9f367b829474eec0a891350d" dependencies = [ "borsh", "serde", @@ -1978,7 +1974,6 @@ dependencies = [ "smol_str", "stdx", "test-utils", - "text-edit", "tracing", "triomphe", ] @@ -2027,14 +2022,6 @@ dependencies = [ ] [[package]] -name = "text-edit" -version = "0.0.0" -dependencies = [ - "itertools", - "text-size", -] - -[[package]] name = "text-size" version = "1.1.1" source = "registry+https://github.com/rust-lang/crates.io-index" diff --git a/src/tools/rust-analyzer/Cargo.toml b/src/tools/rust-analyzer/Cargo.toml index 9db62de9abf..3aa93b7b7b4 100644 --- a/src/tools/rust-analyzer/Cargo.toml +++ b/src/tools/rust-analyzer/Cargo.toml @@ -4,7 +4,7 @@ exclude = ["crates/proc-macro-srv/proc-macro-test/imp"] resolver = "2" [workspace.package] -rust-version = "1.81" +rust-version = "1.82" edition = "2021" license = "MIT OR Apache-2.0" authors = ["rust-analyzer team"] @@ -79,17 +79,16 @@ span = { path = "./crates/span", version = "0.0.0" } stdx = { path = "./crates/stdx", version = "0.0.0" } syntax = { path = "./crates/syntax", version = "0.0.0" } syntax-bridge = { path = "./crates/syntax-bridge", version = "0.0.0" } -text-edit = { path = "./crates/text-edit", version = "0.0.0" } toolchain = { path = "./crates/toolchain", version = "0.0.0" } tt = { path = "./crates/tt", version = "0.0.0" } vfs-notify = { path = "./crates/vfs-notify", version = "0.0.0" } vfs = { path = "./crates/vfs", version = "0.0.0" } -ra-ap-rustc_lexer = { version = "0.73", default-features = false } -ra-ap-rustc_parse_format = { version = "0.73", default-features = false } -ra-ap-rustc_index = { version = "0.73", default-features = false } -ra-ap-rustc_abi = { version = "0.73", default-features = false } -ra-ap-rustc_pattern_analysis = { version = "0.73", default-features = false } +ra-ap-rustc_lexer = { version = "0.75", default-features = false } +ra-ap-rustc_parse_format = { version = "0.75", default-features = false } +ra-ap-rustc_index = { version = "0.75", default-features = false } +ra-ap-rustc_abi = { version = "0.75", default-features = false } +ra-ap-rustc_pattern_analysis = { version = "0.75", default-features = false } # local crates that aren't published to crates.io. These should not have versions. test-fixture = { path = "./crates/test-fixture" } @@ -145,7 +144,7 @@ smallvec = { version = "1.10.0", features = [ "union", "const_generics", ] } -smol_str = "0.3.1" +smol_str = "0.3.2" snap = "1.1.0" text-size = "1.1.1" tracing = "0.1.40" diff --git a/src/tools/rust-analyzer/crates/cfg/Cargo.toml b/src/tools/rust-analyzer/crates/cfg/Cargo.toml index 29b7ad6f8fe..040bddbd7fd 100644 --- a/src/tools/rust-analyzer/crates/cfg/Cargo.toml +++ b/src/tools/rust-analyzer/crates/cfg/Cargo.toml @@ -14,6 +14,7 @@ doctest = false [dependencies] rustc-hash.workspace = true +tracing.workspace = true # locals deps tt = { workspace = true, optional = true } diff --git a/src/tools/rust-analyzer/crates/cfg/src/lib.rs b/src/tools/rust-analyzer/crates/cfg/src/lib.rs index c2d40086056..6a6213a871f 100644 --- a/src/tools/rust-analyzer/crates/cfg/src/lib.rs +++ b/src/tools/rust-analyzer/crates/cfg/src/lib.rs @@ -9,7 +9,7 @@ use std::fmt; use rustc_hash::FxHashSet; -use intern::Symbol; +use intern::{sym, Symbol}; pub use cfg_expr::{CfgAtom, CfgExpr}; pub use dnf::DnfExpr; @@ -24,11 +24,17 @@ pub use dnf::DnfExpr; /// of key and value in `key_values`. /// /// See: <https://doc.rust-lang.org/reference/conditional-compilation.html#set-configuration-options> -#[derive(Clone, PartialEq, Eq, Default)] +#[derive(Clone, PartialEq, Eq)] pub struct CfgOptions { enabled: FxHashSet<CfgAtom>, } +impl Default for CfgOptions { + fn default() -> Self { + Self { enabled: FxHashSet::from_iter([CfgAtom::Flag(sym::true_.clone())]) } + } +} + impl fmt::Debug for CfgOptions { fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { let mut items = self @@ -54,23 +60,37 @@ impl CfgOptions { } pub fn insert_atom(&mut self, key: Symbol) { - self.enabled.insert(CfgAtom::Flag(key)); + self.insert_any_atom(CfgAtom::Flag(key)); } pub fn insert_key_value(&mut self, key: Symbol, value: Symbol) { - self.enabled.insert(CfgAtom::KeyValue { key, value }); + self.insert_any_atom(CfgAtom::KeyValue { key, value }); } pub fn apply_diff(&mut self, diff: CfgDiff) { for atom in diff.enable { - self.enabled.insert(atom); + self.insert_any_atom(atom); } for atom in diff.disable { + let (CfgAtom::Flag(sym) | CfgAtom::KeyValue { key: sym, .. }) = &atom; + if *sym == sym::true_ || *sym == sym::false_ { + tracing::error!("cannot remove `true` or `false` from cfg"); + continue; + } self.enabled.remove(&atom); } } + fn insert_any_atom(&mut self, atom: CfgAtom) { + let (CfgAtom::Flag(sym) | CfgAtom::KeyValue { key: sym, .. }) = &atom; + if *sym == sym::true_ || *sym == sym::false_ { + tracing::error!("cannot insert `true` or `false` to cfg"); + return; + } + self.enabled.insert(atom); + } + pub fn get_cfg_keys(&self) -> impl Iterator<Item = &Symbol> { self.enabled.iter().map(|it| match it { CfgAtom::Flag(key) => key, @@ -88,7 +108,7 @@ impl CfgOptions { impl Extend<CfgAtom> for CfgOptions { fn extend<T: IntoIterator<Item = CfgAtom>>(&mut self, iter: T) { - iter.into_iter().for_each(|cfg_flag| _ = self.enabled.insert(cfg_flag)); + iter.into_iter().for_each(|cfg_flag| self.insert_any_atom(cfg_flag)); } } diff --git a/src/tools/rust-analyzer/crates/hir-def/Cargo.toml b/src/tools/rust-analyzer/crates/hir-def/Cargo.toml index c8ba5da449e..375f18d9fe1 100644 --- a/src/tools/rust-analyzer/crates/hir-def/Cargo.toml +++ b/src/tools/rust-analyzer/crates/hir-def/Cargo.toml @@ -29,6 +29,7 @@ smallvec.workspace = true hashbrown.workspace = true triomphe.workspace = true rustc_apfloat = "0.2.0" +text-size.workspace = true ra-ap-rustc_parse_format.workspace = true ra-ap-rustc_abi.workspace = true diff --git a/src/tools/rust-analyzer/crates/hir-def/src/body.rs b/src/tools/rust-analyzer/crates/hir-def/src/body.rs index 9535b5aea7c..5a386f6cf8d 100644 --- a/src/tools/rust-analyzer/crates/hir-def/src/body.rs +++ b/src/tools/rust-analyzer/crates/hir-def/src/body.rs @@ -10,6 +10,7 @@ use std::ops::{Deref, Index}; use base_db::CrateId; use cfg::{CfgExpr, CfgOptions}; +use either::Either; use hir_expand::{name::Name, ExpandError, InFile}; use la_arena::{Arena, ArenaMap, Idx, RawIdx}; use rustc_hash::FxHashMap; @@ -22,15 +23,33 @@ use crate::{ db::DefDatabase, expander::Expander, hir::{ - dummy_expr_id, Binding, BindingId, Expr, ExprId, Label, LabelId, Pat, PatId, RecordFieldPat, + dummy_expr_id, Array, AsmOperand, Binding, BindingId, Expr, ExprId, ExprOrPatId, Label, + LabelId, Pat, PatId, RecordFieldPat, Statement, }, item_tree::AttrOwner, nameres::DefMap, path::{ModPath, Path}, src::HasSource, + type_ref::{TypeRef, TypeRefId, TypesMap, TypesSourceMap}, BlockId, DefWithBodyId, HasModule, Lookup, }; +/// A wrapper around [`span::SyntaxContextId`] that is intended only for comparisons. +#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)] +pub struct HygieneId(pub(crate) span::SyntaxContextId); + +impl HygieneId { + pub const ROOT: Self = Self(span::SyntaxContextId::ROOT); + + pub fn new(ctx: span::SyntaxContextId) -> Self { + Self(ctx) + } + + pub(crate) fn is_root(self) -> bool { + self.0.is_root() + } +} + /// The body of an item (function, const etc.). #[derive(Debug, Eq, PartialEq)] pub struct Body { @@ -51,8 +70,25 @@ pub struct Body { pub self_param: Option<BindingId>, /// The `ExprId` of the actual body expression. pub body_expr: ExprId, + pub types: TypesMap, /// Block expressions in this body that may contain inner items. block_scopes: Vec<BlockId>, + + /// A map from binding to its hygiene ID. + /// + /// Bindings that don't come from macro expansion are not allocated to save space, so not all bindings appear here. + /// If a binding does not appear here it has `SyntaxContextId::ROOT`. + /// + /// Note that this may not be the direct `SyntaxContextId` of the binding's expansion, because transparent + /// expansions are attributed to their parent expansion (recursively). + binding_hygiene: FxHashMap<BindingId, HygieneId>, + /// A map from an variable usages to their hygiene ID. + /// + /// Expressions that can be recorded here are single segment path, although not all single segments path refer + /// to variables and have hygiene (some refer to items, we don't know at this stage). + expr_hygiene: FxHashMap<ExprId, HygieneId>, + /// A map from a destructuring assignment possible variable usages to their hygiene ID. + pat_hygiene: FxHashMap<PatId, HygieneId>, } pub type ExprPtr = AstPtr<ast::Expr>; @@ -67,9 +103,12 @@ pub type LabelSource = InFile<LabelPtr>; pub type FieldPtr = AstPtr<ast::RecordExprField>; pub type FieldSource = InFile<FieldPtr>; -pub type PatFieldPtr = AstPtr<ast::RecordPatField>; +pub type PatFieldPtr = AstPtr<Either<ast::RecordExprField, ast::RecordPatField>>; pub type PatFieldSource = InFile<PatFieldPtr>; +pub type ExprOrPatPtr = AstPtr<Either<ast::Expr, ast::Pat>>; +pub type ExprOrPatSource = InFile<ExprOrPatPtr>; + /// An item body together with the mapping from syntax nodes to HIR expression /// IDs. This is needed to go from e.g. a position in a file to the HIR /// expression containing it; but for type inference etc., we want to operate on @@ -83,11 +122,13 @@ pub type PatFieldSource = InFile<PatFieldPtr>; /// this properly for macros. #[derive(Default, Debug, Eq, PartialEq)] pub struct BodySourceMap { - expr_map: FxHashMap<ExprSource, ExprId>, + // AST expressions can create patterns in destructuring assignments. Therefore, `ExprSource` can also map + // to `PatId`, and `PatId` can also map to `ExprSource` (the other way around is unaffected). + expr_map: FxHashMap<ExprSource, ExprOrPatId>, expr_map_back: ArenaMap<ExprId, ExprSource>, pat_map: FxHashMap<PatSource, PatId>, - pat_map_back: ArenaMap<PatId, PatSource>, + pat_map_back: ArenaMap<PatId, ExprOrPatSource>, label_map: FxHashMap<LabelSource, LabelId>, label_map_back: ArenaMap<LabelId, LabelSource>, @@ -100,10 +141,13 @@ pub struct BodySourceMap { field_map_back: FxHashMap<ExprId, FieldSource>, pat_field_map_back: FxHashMap<PatId, PatFieldSource>, + types: TypesSourceMap, + + // FIXME: Make this a sane struct. template_map: Option< Box<( // format_args! - FxHashMap<ExprId, Vec<(syntax::TextRange, Name)>>, + FxHashMap<ExprId, (HygieneId, Vec<(syntax::TextRange, Name)>)>, // asm! FxHashMap<ExprId, Vec<Vec<(syntax::TextRange, usize)>>>, )>, @@ -261,6 +305,10 @@ impl Body { pats, bindings, binding_owners, + binding_hygiene, + expr_hygiene, + pat_hygiene, + types, } = self; block_scopes.shrink_to_fit(); exprs.shrink_to_fit(); @@ -268,6 +316,10 @@ impl Body { pats.shrink_to_fit(); bindings.shrink_to_fit(); binding_owners.shrink_to_fit(); + binding_hygiene.shrink_to_fit(); + expr_hygiene.shrink_to_fit(); + pat_hygiene.shrink_to_fit(); + types.shrink_to_fit(); } pub fn walk_bindings_in_pat(&self, pat_id: PatId, mut f: impl FnMut(BindingId)) { @@ -286,7 +338,8 @@ impl Body { | Pat::Path(..) | Pat::ConstBlock(..) | Pat::Wild - | Pat::Missing => {} + | Pat::Missing + | Pat::Expr(_) => {} &Pat::Bind { subpat, .. } => { if let Some(subpat) = subpat { f(subpat); @@ -322,6 +375,162 @@ impl Body { None => true, } } + + pub fn walk_child_exprs(&self, expr_id: ExprId, mut f: impl FnMut(ExprId)) { + let expr = &self[expr_id]; + match expr { + Expr::Continue { .. } + | Expr::Const(_) + | Expr::Missing + | Expr::Path(_) + | Expr::OffsetOf(_) + | Expr::Literal(_) + | Expr::Underscore => {} + Expr::InlineAsm(it) => it.operands.iter().for_each(|(_, op)| match op { + AsmOperand::In { expr, .. } + | AsmOperand::Out { expr: Some(expr), .. } + | AsmOperand::InOut { expr, .. } => f(*expr), + AsmOperand::SplitInOut { in_expr, out_expr, .. } => { + f(*in_expr); + if let Some(out_expr) = out_expr { + f(*out_expr); + } + } + AsmOperand::Out { expr: None, .. } + | AsmOperand::Const(_) + | AsmOperand::Label(_) + | AsmOperand::Sym(_) => (), + }), + Expr::If { condition, then_branch, else_branch } => { + f(*condition); + f(*then_branch); + if let &Some(else_branch) = else_branch { + f(else_branch); + } + } + Expr::Let { expr, .. } => { + f(*expr); + } + Expr::Block { statements, tail, .. } + | Expr::Unsafe { statements, tail, .. } + | Expr::Async { statements, tail, .. } => { + for stmt in statements.iter() { + match stmt { + Statement::Let { initializer, else_branch, pat, .. } => { + if let &Some(expr) = initializer { + f(expr); + } + if let &Some(expr) = else_branch { + f(expr); + } + self.walk_exprs_in_pat(*pat, &mut f); + } + Statement::Expr { expr: expression, .. } => f(*expression), + Statement::Item(_) => (), + } + } + if let &Some(expr) = tail { + f(expr); + } + } + Expr::Loop { body, .. } => f(*body), + Expr::Call { callee, args, .. } => { + f(*callee); + args.iter().copied().for_each(f); + } + Expr::MethodCall { receiver, args, .. } => { + f(*receiver); + args.iter().copied().for_each(f); + } + Expr::Match { expr, arms } => { + f(*expr); + arms.iter().map(|arm| arm.expr).for_each(f); + } + Expr::Break { expr, .. } + | Expr::Return { expr } + | Expr::Yield { expr } + | Expr::Yeet { expr } => { + if let &Some(expr) = expr { + f(expr); + } + } + Expr::Become { expr } => f(*expr), + Expr::RecordLit { fields, spread, .. } => { + for field in fields.iter() { + f(field.expr); + } + if let &Some(expr) = spread { + f(expr); + } + } + Expr::Closure { body, .. } => { + f(*body); + } + Expr::BinaryOp { lhs, rhs, .. } => { + f(*lhs); + f(*rhs); + } + Expr::Range { lhs, rhs, .. } => { + if let &Some(lhs) = rhs { + f(lhs); + } + if let &Some(rhs) = lhs { + f(rhs); + } + } + Expr::Index { base, index, .. } => { + f(*base); + f(*index); + } + Expr::Field { expr, .. } + | Expr::Await { expr } + | Expr::Cast { expr, .. } + | Expr::Ref { expr, .. } + | Expr::UnaryOp { expr, .. } + | Expr::Box { expr } => { + f(*expr); + } + Expr::Tuple { exprs, .. } => exprs.iter().copied().for_each(f), + Expr::Array(a) => match a { + Array::ElementList { elements, .. } => elements.iter().copied().for_each(f), + Array::Repeat { initializer, repeat } => { + f(*initializer); + f(*repeat) + } + }, + &Expr::Assignment { target, value } => { + self.walk_exprs_in_pat(target, &mut f); + f(value); + } + } + } + + pub fn walk_exprs_in_pat(&self, pat_id: PatId, f: &mut impl FnMut(ExprId)) { + self.walk_pats(pat_id, &mut |pat| { + if let Pat::Expr(expr) | Pat::ConstBlock(expr) = self[pat] { + f(expr); + } + }); + } + + fn binding_hygiene(&self, binding: BindingId) -> HygieneId { + self.binding_hygiene.get(&binding).copied().unwrap_or(HygieneId::ROOT) + } + + pub fn expr_path_hygiene(&self, expr: ExprId) -> HygieneId { + self.expr_hygiene.get(&expr).copied().unwrap_or(HygieneId::ROOT) + } + + pub fn pat_path_hygiene(&self, pat: PatId) -> HygieneId { + self.pat_hygiene.get(&pat).copied().unwrap_or(HygieneId::ROOT) + } + + pub fn expr_or_pat_path_hygiene(&self, id: ExprOrPatId) -> HygieneId { + match id { + ExprOrPatId::ExprId(id) => self.expr_path_hygiene(id), + ExprOrPatId::PatId(id) => self.pat_path_hygiene(id), + } + } } impl Default for Body { @@ -336,6 +545,10 @@ impl Default for Body { block_scopes: Default::default(), binding_owners: Default::default(), self_param: Default::default(), + binding_hygiene: Default::default(), + expr_hygiene: Default::default(), + pat_hygiene: Default::default(), + types: Default::default(), } } } @@ -372,14 +585,29 @@ impl Index<BindingId> for Body { } } +impl Index<TypeRefId> for Body { + type Output = TypeRef; + + fn index(&self, b: TypeRefId) -> &TypeRef { + &self.types[b] + } +} + // FIXME: Change `node_` prefix to something more reasonable. // Perhaps `expr_syntax` and `expr_id`? impl BodySourceMap { + pub fn expr_or_pat_syntax(&self, id: ExprOrPatId) -> Result<ExprOrPatSource, SyntheticSyntax> { + match id { + ExprOrPatId::ExprId(id) => self.expr_syntax(id).map(|it| it.map(AstPtr::wrap_left)), + ExprOrPatId::PatId(id) => self.pat_syntax(id), + } + } + pub fn expr_syntax(&self, expr: ExprId) -> Result<ExprSource, SyntheticSyntax> { self.expr_map_back.get(expr).cloned().ok_or(SyntheticSyntax) } - pub fn node_expr(&self, node: InFile<&ast::Expr>) -> Option<ExprId> { + pub fn node_expr(&self, node: InFile<&ast::Expr>) -> Option<ExprOrPatId> { let src = node.map(AstPtr::new); self.expr_map.get(&src).cloned() } @@ -395,7 +623,7 @@ impl BodySourceMap { self.expansions.iter().map(|(&a, &b)| (a, b)) } - pub fn pat_syntax(&self, pat: PatId) -> Result<PatSource, SyntheticSyntax> { + pub fn pat_syntax(&self, pat: PatId) -> Result<ExprOrPatSource, SyntheticSyntax> { self.pat_map_back.get(pat).cloned().ok_or(SyntheticSyntax) } @@ -428,7 +656,7 @@ impl BodySourceMap { self.pat_field_map_back[&pat] } - pub fn macro_expansion_expr(&self, node: InFile<&ast::MacroExpr>) -> Option<ExprId> { + pub fn macro_expansion_expr(&self, node: InFile<&ast::MacroExpr>) -> Option<ExprOrPatId> { let src = node.map(AstPtr::new).map(AstPtr::upcast::<ast::MacroExpr>).map(AstPtr::upcast); self.expr_map.get(&src).copied() } @@ -442,9 +670,11 @@ impl BodySourceMap { pub fn implicit_format_args( &self, node: InFile<&ast::FormatArgsExpr>, - ) -> Option<&[(syntax::TextRange, Name)]> { + ) -> Option<(HygieneId, &[(syntax::TextRange, Name)])> { let src = node.map(AstPtr::new).map(AstPtr::upcast::<ast::Expr>); - self.template_map.as_ref()?.0.get(self.expr_map.get(&src)?).map(std::ops::Deref::deref) + let (hygiene, names) = + self.template_map.as_ref()?.0.get(&self.expr_map.get(&src)?.as_expr()?)?; + Some((*hygiene, &**names)) } pub fn asm_template_args( @@ -452,8 +682,8 @@ impl BodySourceMap { node: InFile<&ast::AsmExpr>, ) -> Option<(ExprId, &[Vec<(syntax::TextRange, usize)>])> { let src = node.map(AstPtr::new).map(AstPtr::upcast::<ast::Expr>); - let expr = self.expr_map.get(&src)?; - Some(*expr).zip(self.template_map.as_ref()?.1.get(expr).map(std::ops::Deref::deref)) + let expr = self.expr_map.get(&src)?.as_expr()?; + Some(expr).zip(self.template_map.as_ref()?.1.get(&expr).map(std::ops::Deref::deref)) } /// Get a reference to the body source map's diagnostics. @@ -476,6 +706,7 @@ impl BodySourceMap { template_map, diagnostics, binding_definitions, + types, } = self; if let Some(template_map) = template_map { template_map.0.shrink_to_fit(); @@ -492,14 +723,6 @@ impl BodySourceMap { expansions.shrink_to_fit(); diagnostics.shrink_to_fit(); binding_definitions.shrink_to_fit(); - } - - pub fn template_map( - &self, - ) -> Option<&( - FxHashMap<Idx<Expr>, Vec<(tt::TextRange, Name)>>, - FxHashMap<Idx<Expr>, Vec<Vec<(tt::TextRange, usize)>>>, - )> { - self.template_map.as_deref() + types.shrink_to_fit(); } } diff --git a/src/tools/rust-analyzer/crates/hir-def/src/body/lower.rs b/src/tools/rust-analyzer/crates/hir-def/src/body/lower.rs index 9c547574ecb..0b108b54e67 100644 --- a/src/tools/rust-analyzer/crates/hir-def/src/body/lower.rs +++ b/src/tools/rust-analyzer/crates/hir-def/src/body/lower.rs @@ -9,9 +9,10 @@ use base_db::CrateId; use either::Either; use hir_expand::{ name::{AsName, Name}, - InFile, + span_map::{ExpansionSpanMap, SpanMap}, + InFile, MacroDefId, }; -use intern::{sym, Interned, Symbol}; +use intern::{sym, Symbol}; use rustc_hash::FxHashMap; use span::AstIdMap; use stdx::never; @@ -22,10 +23,11 @@ use syntax::{ }, AstNode, AstPtr, AstToken as _, SyntaxNodePtr, }; +use text_size::TextSize; use triomphe::Arc; use crate::{ - body::{Body, BodyDiagnostic, BodySourceMap, ExprPtr, LabelPtr, PatPtr}, + body::{Body, BodyDiagnostic, BodySourceMap, ExprPtr, HygieneId, LabelPtr, PatPtr}, builtin_type::BuiltinUint, data::adt::StructKind, db::DefDatabase, @@ -37,8 +39,8 @@ use crate::{ FormatPlaceholder, FormatSign, FormatTrait, }, Array, Binding, BindingAnnotation, BindingId, BindingProblems, CaptureBy, ClosureKind, - Expr, ExprId, Label, LabelId, Literal, LiteralOrConst, MatchArm, Movability, OffsetOf, Pat, - PatId, RecordFieldPat, RecordLitField, Statement, + Expr, ExprId, Item, Label, LabelId, Literal, LiteralOrConst, MatchArm, Movability, + OffsetOf, Pat, PatId, RecordFieldPat, RecordLitField, Statement, }, item_scope::BuiltinShadowMode, lang_item::LangItem, @@ -46,7 +48,7 @@ use crate::{ nameres::{DefMap, MacroSubNs}, path::{GenericArgs, Path}, type_ref::{Mutability, Rawness, TypeRef}, - AdtId, BlockId, BlockLoc, ConstBlockLoc, DefWithBodyId, ModuleDefId, UnresolvedMacro, + AdtId, BlockId, BlockLoc, ConstBlockLoc, DefWithBodyId, MacroId, ModuleDefId, UnresolvedMacro, }; type FxIndexSet<K> = indexmap::IndexSet<K, std::hash::BuildHasherDefault<rustc_hash::FxHasher>>; @@ -60,6 +62,17 @@ pub(super) fn lower( krate: CrateId, is_async_fn: bool, ) -> (Body, BodySourceMap) { + // We cannot leave the root span map empty and let any identifier from it be treated as root, + // because when inside nested macros `SyntaxContextId`s from the outer macro will be interleaved + // with the inner macro, and that will cause confusion because they won't be the same as `ROOT` + // even though they should be the same. Also, when the body comes from multiple expansions, their + // hygiene is different. + let span_map = expander.current_file_id().macro_file().map(|_| { + let SpanMap::ExpansionSpanMap(span_map) = expander.span_map(db) else { + panic!("in a macro file there should be `ExpansionSpanMap`"); + }; + Arc::clone(span_map) + }); ExprCollector { db, owner, @@ -70,11 +83,12 @@ pub(super) fn lower( body: Body::default(), expander, current_try_block_label: None, - is_lowering_assignee_expr: false, is_lowering_coroutine: false, label_ribs: Vec::new(), current_binding_owner: None, awaitable_context: None, + current_span_map: span_map, + current_block_legacy_macro_defs_count: FxHashMap::default(), } .collect(params, body, is_async_fn) } @@ -89,9 +103,14 @@ struct ExprCollector<'a> { body: Body, source_map: BodySourceMap, - is_lowering_assignee_expr: bool, is_lowering_coroutine: bool, + /// Legacy (`macro_rules!`) macros can have multiple definitions and shadow each other, + /// and we need to find the current definition. So we track the number of definitions we saw. + current_block_legacy_macro_defs_count: FxHashMap<Name, usize>, + + current_span_map: Option<Arc<ExpansionSpanMap>>, + current_try_block_label: Option<LabelId>, // points to the expression that a try expression will target (replaces current_try_block_label) // catch_scope: Option<ExprId>, @@ -110,31 +129,27 @@ struct ExprCollector<'a> { #[derive(Clone, Debug)] struct LabelRib { kind: RibKind, - // Once we handle macro hygiene this will need to be a map - label: Option<(Name, LabelId)>, } impl LabelRib { fn new(kind: RibKind) -> Self { - LabelRib { kind, label: None } - } - fn new_normal(label: (Name, LabelId)) -> Self { - LabelRib { kind: RibKind::Normal, label: Some(label) } + LabelRib { kind } } } -#[derive(Copy, Clone, Debug, PartialEq, Eq)] +#[derive(Clone, Debug, PartialEq, Eq)] enum RibKind { - Normal, + Normal(Name, LabelId, HygieneId), Closure, Constant, + MacroDef(Box<MacroDefId>), } impl RibKind { /// This rib forbids referring to labels defined in upwards ribs. - fn is_label_barrier(self) -> bool { + fn is_label_barrier(&self) -> bool { match self { - RibKind::Normal => false, + RibKind::Normal(..) | RibKind::MacroDef(_) => false, RibKind::Closure | RibKind::Constant => true, } } @@ -147,7 +162,7 @@ enum Awaitable { #[derive(Debug, Default)] struct BindingList { - map: FxHashMap<Name, BindingId>, + map: FxHashMap<(Name, HygieneId), BindingId>, is_used: FxHashMap<BindingId, bool>, reject_new: bool, } @@ -157,9 +172,16 @@ impl BindingList { &mut self, ec: &mut ExprCollector<'_>, name: Name, + hygiene: HygieneId, mode: BindingAnnotation, ) -> BindingId { - let id = *self.map.entry(name).or_insert_with_key(|n| ec.alloc_binding(n.clone(), mode)); + let id = *self.map.entry((name, hygiene)).or_insert_with_key(|(name, _)| { + let id = ec.alloc_binding(name.clone(), mode); + if !hygiene.is_root() { + ec.body.binding_hygiene.insert(id, hygiene); + } + id + }); if ec.body.bindings[id].mode != mode { ec.body.bindings[id].problems = Some(BindingProblems::BoundInconsistently); } @@ -213,6 +235,13 @@ impl ExprCollector<'_> { Name::new_symbol_root(sym::self_.clone()), BindingAnnotation::new(is_mutable, false), ); + let hygiene = self_param + .name() + .map(|name| self.hygiene_id_for(name.syntax().text_range().start())) + .unwrap_or(HygieneId::ROOT); + if !hygiene.is_root() { + self.body.binding_hygiene.insert(binding_id, hygiene); + } self.body.self_param = Some(binding_id); self.source_map.self_param = Some(self.expander.in_file(AstPtr::new(&self_param))); } @@ -245,8 +274,8 @@ impl ExprCollector<'_> { (self.body, self.source_map) } - fn ctx(&self) -> LowerCtx<'_> { - self.expander.ctx(self.db) + fn ctx(&mut self) -> LowerCtx<'_> { + self.expander.ctx(self.db, &mut self.body.types, &mut self.source_map.types) } fn collect_expr(&mut self, expr: ast::Expr) -> ExprId { @@ -290,13 +319,14 @@ impl ExprCollector<'_> { }) } Some(ast::BlockModifier::Label(label)) => { - let label = self.collect_label(label); - self.with_labeled_rib(label, |this| { + let label_hygiene = self.hygiene_id_for(label.syntax().text_range().start()); + let label_id = self.collect_label(label); + self.with_labeled_rib(label_id, label_hygiene, |this| { this.collect_block_(e, |id, statements, tail| Expr::Block { id, statements, tail, - label: Some(label), + label: Some(label_id), }) }) } @@ -338,9 +368,14 @@ impl ExprCollector<'_> { None => self.collect_block(e), }, ast::Expr::LoopExpr(e) => { - let label = e.label().map(|label| self.collect_label(label)); + let label = e.label().map(|label| { + ( + self.hygiene_id_for(label.syntax().text_range().start()), + self.collect_label(label), + ) + }); let body = self.collect_labelled_block_opt(label, e.loop_body()); - self.alloc_expr(Expr::Loop { body, label }, syntax_ptr) + self.alloc_expr(Expr::Loop { body, label: label.map(|it| it.1) }, syntax_ptr) } ast::Expr::WhileExpr(e) => self.collect_while_loop(syntax_ptr, e), ast::Expr::ForExpr(e) => self.collect_for_loop(syntax_ptr, e), @@ -359,14 +394,7 @@ impl ExprCollector<'_> { } else { Box::default() }; - self.alloc_expr( - Expr::Call { - callee, - args, - is_assignee_expr: self.is_lowering_assignee_expr, - }, - syntax_ptr, - ) + self.alloc_expr(Expr::Call { callee, args }, syntax_ptr) } } ast::Expr::MethodCallExpr(e) => { @@ -407,12 +435,15 @@ impl ExprCollector<'_> { self.alloc_expr(Expr::Match { expr, arms }, syntax_ptr) } ast::Expr::PathExpr(e) => { - let path = e - .path() - .and_then(|path| self.expander.parse_path(self.db, path)) - .map(Expr::Path) - .unwrap_or(Expr::Missing); - self.alloc_expr(path, syntax_ptr) + let (path, hygiene) = self + .collect_expr_path(e) + .map(|(path, hygiene)| (Expr::Path(path), hygiene)) + .unwrap_or((Expr::Missing, HygieneId::ROOT)); + let expr_id = self.alloc_expr(path, syntax_ptr); + if !hygiene.is_root() { + self.body.expr_hygiene.insert(expr_id, hygiene); + } + expr_id } ast::Expr::ContinueExpr(e) => { let label = self.resolve_label(e.lifetime()).unwrap_or_else(|e| { @@ -433,7 +464,7 @@ impl ExprCollector<'_> { let inner = self.collect_expr_opt(e.expr()); // make the paren expr point to the inner expression as well for IDE resolution let src = self.expander.in_file(syntax_ptr); - self.source_map.expr_map.insert(src, inner); + self.source_map.expr_map.insert(src, inner.into()); inner } ast::Expr::ReturnExpr(e) => { @@ -455,9 +486,7 @@ impl ExprCollector<'_> { self.alloc_expr(Expr::Yeet { expr }, syntax_ptr) } ast::Expr::RecordExpr(e) => { - let path = - e.path().and_then(|path| self.expander.parse_path(self.db, path)).map(Box::new); - let is_assignee_expr = self.is_lowering_assignee_expr; + let path = e.path().and_then(|path| self.parse_path(path)).map(Box::new); let record_lit = if let Some(nfl) = e.record_expr_field_list() { let fields = nfl .fields() @@ -476,16 +505,9 @@ impl ExprCollector<'_> { }) .collect(); let spread = nfl.spread().map(|s| self.collect_expr(s)); - let ellipsis = nfl.dotdot_token().is_some(); - Expr::RecordLit { path, fields, spread, ellipsis, is_assignee_expr } + Expr::RecordLit { path, fields, spread } } else { - Expr::RecordLit { - path, - fields: Box::default(), - spread: None, - ellipsis: false, - is_assignee_expr, - } + Expr::RecordLit { path, fields: Box::default(), spread: None } }; self.alloc_expr(record_lit, syntax_ptr) @@ -511,7 +533,7 @@ impl ExprCollector<'_> { ast::Expr::TryExpr(e) => self.collect_try_operator(syntax_ptr, e), ast::Expr::CastExpr(e) => { let expr = self.collect_expr_opt(e.expr()); - let type_ref = Interned::new(TypeRef::from_ast_opt(&self.ctx(), e.ty())); + let type_ref = TypeRef::from_ast_opt(&self.ctx(), e.ty()); self.alloc_expr(Expr::Cast { expr, type_ref }, syntax_ptr) } ast::Expr::RefExpr(e) => { @@ -550,16 +572,13 @@ impl ExprCollector<'_> { arg_types.reserve_exact(num_params); for param in pl.params() { let pat = this.collect_pat_top(param.pat()); - let type_ref = - param.ty().map(|it| Interned::new(TypeRef::from_ast(&this.ctx(), it))); + let type_ref = param.ty().map(|it| TypeRef::from_ast(&this.ctx(), it)); args.push(pat); arg_types.push(type_ref); } } - let ret_type = e - .ret_type() - .and_then(|r| r.ty()) - .map(|it| Interned::new(TypeRef::from_ast(&this.ctx(), it))); + let ret_type = + e.ret_type().and_then(|r| r.ty()).map(|it| TypeRef::from_ast(&this.ctx(), it)); let prev_is_lowering_coroutine = mem::take(&mut this.is_lowering_coroutine); let prev_try_block_label = this.current_try_block_label.take(); @@ -602,12 +621,14 @@ impl ExprCollector<'_> { ast::Expr::BinExpr(e) => { let op = e.op_kind(); if let Some(ast::BinaryOp::Assignment { op: None }) = op { - self.is_lowering_assignee_expr = true; + let target = self.collect_expr_as_pat_opt(e.lhs()); + let value = self.collect_expr_opt(e.rhs()); + self.alloc_expr(Expr::Assignment { target, value }, syntax_ptr) + } else { + let lhs = self.collect_expr_opt(e.lhs()); + let rhs = self.collect_expr_opt(e.rhs()); + self.alloc_expr(Expr::BinaryOp { lhs, rhs, op }, syntax_ptr) } - let lhs = self.collect_expr_opt(e.lhs()); - self.is_lowering_assignee_expr = false; - let rhs = self.collect_expr_opt(e.rhs()); - self.alloc_expr(Expr::BinaryOp { lhs, rhs, op }, syntax_ptr) } ast::Expr::TupleExpr(e) => { let mut exprs: Vec<_> = e.fields().map(|expr| self.collect_expr(expr)).collect(); @@ -617,13 +638,7 @@ impl ExprCollector<'_> { exprs.insert(0, self.missing_expr()); } - self.alloc_expr( - Expr::Tuple { - exprs: exprs.into_boxed_slice(), - is_assignee_expr: self.is_lowering_assignee_expr, - }, - syntax_ptr, - ) + self.alloc_expr(Expr::Tuple { exprs: exprs.into_boxed_slice() }, syntax_ptr) } ast::Expr::ArrayExpr(e) => { let kind = e.kind(); @@ -631,13 +646,7 @@ impl ExprCollector<'_> { match kind { ArrayExprKind::ElementList(e) => { let elements = e.map(|expr| self.collect_expr(expr)).collect(); - self.alloc_expr( - Expr::Array(Array::ElementList { - elements, - is_assignee_expr: self.is_lowering_assignee_expr, - }), - syntax_ptr, - ) + self.alloc_expr(Expr::Array(Array::ElementList { elements }), syntax_ptr) } ArrayExprKind::Repeat { initializer, repeat } => { let initializer = self.collect_expr_opt(initializer); @@ -664,8 +673,7 @@ impl ExprCollector<'_> { ast::Expr::IndexExpr(e) => { let base = self.collect_expr_opt(e.base()); let index = self.collect_expr_opt(e.index()); - let is_assignee_expr = self.is_lowering_assignee_expr; - self.alloc_expr(Expr::Index { base, index, is_assignee_expr }, syntax_ptr) + self.alloc_expr(Expr::Index { base, index }, syntax_ptr) } ast::Expr::RangeExpr(e) => { let lhs = e.start().map(|lhs| self.collect_expr(lhs)); @@ -688,7 +696,7 @@ impl ExprCollector<'_> { // Make the macro-call point to its expanded expression so we can query // semantics on syntax pointers to the macro let src = self.expander.in_file(syntax_ptr); - self.source_map.expr_map.insert(src, id); + self.source_map.expr_map.insert(src, id.into()); id } None => self.alloc_expr(Expr::Missing, syntax_ptr), @@ -697,7 +705,7 @@ impl ExprCollector<'_> { ast::Expr::UnderscoreExpr(_) => self.alloc_expr(Expr::Underscore, syntax_ptr), ast::Expr::AsmExpr(e) => self.lower_inline_asm(e, syntax_ptr), ast::Expr::OffsetOfExpr(e) => { - let container = Interned::new(TypeRef::from_ast_opt(&self.ctx(), e.ty())); + let container = TypeRef::from_ast_opt(&self.ctx(), e.ty()); let fields = e.fields().map(|it| it.as_name()).collect(); self.alloc_expr(Expr::OffsetOf(OffsetOf { container, fields }), syntax_ptr) } @@ -705,6 +713,200 @@ impl ExprCollector<'_> { }) } + fn parse_path(&mut self, path: ast::Path) -> Option<Path> { + self.expander.parse_path(self.db, path, &mut self.body.types, &mut self.source_map.types) + } + + fn collect_expr_path(&mut self, e: ast::PathExpr) -> Option<(Path, HygieneId)> { + e.path().and_then(|path| { + let path = self.parse_path(path)?; + // Need to enable `mod_path.len() < 1` for `self`. + let may_be_variable = matches!(&path, Path::BarePath(mod_path) if mod_path.len() <= 1); + let hygiene = if may_be_variable { + self.hygiene_id_for(e.syntax().text_range().start()) + } else { + HygieneId::ROOT + }; + Some((path, hygiene)) + }) + } + + fn collect_expr_as_pat_opt(&mut self, expr: Option<ast::Expr>) -> PatId { + match expr { + Some(expr) => self.collect_expr_as_pat(expr), + _ => self.missing_pat(), + } + } + + fn collect_expr_as_pat(&mut self, expr: ast::Expr) -> PatId { + self.maybe_collect_expr_as_pat(&expr).unwrap_or_else(|| { + let src = self.expander.in_file(AstPtr::new(&expr).wrap_left()); + let expr = self.collect_expr(expr); + // Do not use `alloc_pat_from_expr()` here, it will override the entry in `expr_map`. + let id = self.body.pats.alloc(Pat::Expr(expr)); + self.source_map.pat_map_back.insert(id, src); + id + }) + } + + fn maybe_collect_expr_as_pat(&mut self, expr: &ast::Expr) -> Option<PatId> { + self.check_cfg(expr)?; + let syntax_ptr = AstPtr::new(expr); + + let result = match expr { + ast::Expr::UnderscoreExpr(_) => self.alloc_pat_from_expr(Pat::Wild, syntax_ptr), + ast::Expr::ParenExpr(e) => { + // We special-case `(..)` for consistency with patterns. + if let Some(ast::Expr::RangeExpr(range)) = e.expr() { + if range.is_range_full() { + return Some(self.alloc_pat_from_expr( + Pat::Tuple { args: Box::default(), ellipsis: Some(0) }, + syntax_ptr, + )); + } + } + return e.expr().and_then(|expr| self.maybe_collect_expr_as_pat(&expr)); + } + ast::Expr::TupleExpr(e) => { + let (ellipsis, args) = collect_tuple(self, e.fields()); + self.alloc_pat_from_expr(Pat::Tuple { args, ellipsis }, syntax_ptr) + } + ast::Expr::ArrayExpr(e) => { + if e.semicolon_token().is_some() { + return None; + } + + let mut elements = e.exprs(); + let prefix = elements + .by_ref() + .map_while(|elem| collect_possibly_rest(self, elem).left()) + .collect(); + let suffix = elements.map(|elem| self.collect_expr_as_pat(elem)).collect(); + self.alloc_pat_from_expr(Pat::Slice { prefix, slice: None, suffix }, syntax_ptr) + } + ast::Expr::CallExpr(e) => { + let path = collect_path(self, e.expr()?)?; + let path = path.path().and_then(|path| self.parse_path(path)).map(Box::new); + let (ellipsis, args) = collect_tuple(self, e.arg_list()?.args()); + self.alloc_pat_from_expr(Pat::TupleStruct { path, args, ellipsis }, syntax_ptr) + } + ast::Expr::PathExpr(e) => { + let (path, hygiene) = self + .collect_expr_path(e.clone()) + .map(|(path, hygiene)| (Pat::Path(path), hygiene)) + .unwrap_or((Pat::Missing, HygieneId::ROOT)); + let pat_id = self.alloc_pat_from_expr(path, syntax_ptr); + if !hygiene.is_root() { + self.body.pat_hygiene.insert(pat_id, hygiene); + } + pat_id + } + ast::Expr::MacroExpr(e) => { + let e = e.macro_call()?; + let macro_ptr = AstPtr::new(&e); + let src = self.expander.in_file(AstPtr::new(expr)); + let id = self.collect_macro_call(e, macro_ptr, true, |this, expansion| { + this.collect_expr_as_pat_opt(expansion) + }); + self.source_map.expr_map.insert(src, id.into()); + id + } + ast::Expr::RecordExpr(e) => { + let path = e.path().and_then(|path| self.parse_path(path)).map(Box::new); + let record_field_list = e.record_expr_field_list()?; + let ellipsis = record_field_list.dotdot_token().is_some(); + // FIXME: Report an error here if `record_field_list.spread().is_some()`. + let args = record_field_list + .fields() + .filter_map(|f| { + self.check_cfg(&f)?; + let field_expr = f.expr()?; + let pat = self.collect_expr_as_pat(field_expr); + let name = f.field_name()?.as_name(); + let src = self.expander.in_file(AstPtr::new(&f).wrap_left()); + self.source_map.pat_field_map_back.insert(pat, src); + Some(RecordFieldPat { name, pat }) + }) + .collect(); + self.alloc_pat_from_expr(Pat::Record { path, args, ellipsis }, syntax_ptr) + } + _ => return None, + }; + return Some(result); + + fn collect_path(this: &mut ExprCollector<'_>, expr: ast::Expr) -> Option<ast::PathExpr> { + match expr { + ast::Expr::PathExpr(e) => Some(e), + ast::Expr::MacroExpr(mac) => { + let call = mac.macro_call()?; + { + let macro_ptr = AstPtr::new(&call); + this.collect_macro_call(call, macro_ptr, true, |this, expanded_path| { + collect_path(this, expanded_path?) + }) + } + } + _ => None, + } + } + + fn collect_possibly_rest( + this: &mut ExprCollector<'_>, + expr: ast::Expr, + ) -> Either<PatId, ()> { + match &expr { + ast::Expr::RangeExpr(e) if e.is_range_full() => Either::Right(()), + ast::Expr::MacroExpr(mac) => match mac.macro_call() { + Some(call) => { + let macro_ptr = AstPtr::new(&call); + let pat = this.collect_macro_call( + call, + macro_ptr, + true, + |this, expanded_expr| match expanded_expr { + Some(expanded_pat) => collect_possibly_rest(this, expanded_pat), + None => Either::Left(this.missing_pat()), + }, + ); + if let Either::Left(pat) = pat { + let src = this.expander.in_file(AstPtr::new(&expr).wrap_left()); + this.source_map.pat_map_back.insert(pat, src); + } + pat + } + None => { + let ptr = AstPtr::new(&expr); + Either::Left(this.alloc_pat_from_expr(Pat::Missing, ptr)) + } + }, + _ => Either::Left(this.collect_expr_as_pat(expr)), + } + } + + fn collect_tuple( + this: &mut ExprCollector<'_>, + fields: ast::AstChildren<ast::Expr>, + ) -> (Option<u32>, Box<[la_arena::Idx<Pat>]>) { + let mut ellipsis = None; + let args = fields + .enumerate() + .filter_map(|(idx, elem)| { + match collect_possibly_rest(this, elem) { + Either::Left(pat) => Some(pat), + Either::Right(()) => { + if ellipsis.is_none() { + ellipsis = Some(idx as u32); + } + // FIXME: Report an error here otherwise. + None + } + } + }) + .collect(); + (ellipsis, args) + } + } + fn initialize_binding_owner( &mut self, syntax_ptr: AstPtr<ast::Expr>, @@ -744,7 +946,7 @@ impl ExprCollector<'_> { let old_label = self.current_try_block_label.replace(label); let ptr = AstPtr::new(&e).upcast(); - let (btail, expr_id) = self.with_labeled_rib(label, |this| { + let (btail, expr_id) = self.with_labeled_rib(label, HygieneId::ROOT, |this| { let mut btail = None; let block = this.collect_block_(e, |id, statements, tail| { btail = tail; @@ -755,17 +957,13 @@ impl ExprCollector<'_> { let callee = self.alloc_expr_desugared_with_ptr(Expr::Path(try_from_output), ptr); let next_tail = match btail { - Some(tail) => self.alloc_expr_desugared_with_ptr( - Expr::Call { callee, args: Box::new([tail]), is_assignee_expr: false }, - ptr, - ), + Some(tail) => self + .alloc_expr_desugared_with_ptr(Expr::Call { callee, args: Box::new([tail]) }, ptr), None => { - let unit = self.alloc_expr_desugared_with_ptr( - Expr::Tuple { exprs: Box::new([]), is_assignee_expr: false }, - ptr, - ); + let unit = + self.alloc_expr_desugared_with_ptr(Expr::Tuple { exprs: Box::new([]) }, ptr); self.alloc_expr_desugared_with_ptr( - Expr::Call { callee, args: Box::new([unit]), is_assignee_expr: false }, + Expr::Call { callee, args: Box::new([unit]) }, ptr, ) } @@ -792,7 +990,9 @@ impl ExprCollector<'_> { /// FIXME: Rustc wraps the condition in a construct equivalent to `{ let _t = <cond>; _t }` /// to preserve drop semantics. We should probably do the same in future. fn collect_while_loop(&mut self, syntax_ptr: AstPtr<ast::Expr>, e: ast::WhileExpr) -> ExprId { - let label = e.label().map(|label| self.collect_label(label)); + let label = e.label().map(|label| { + (self.hygiene_id_for(label.syntax().text_range().start()), self.collect_label(label)) + }); let body = self.collect_labelled_block_opt(label, e.loop_body()); // Labels can also be used in the condition expression, like this: @@ -809,9 +1009,9 @@ impl ExprCollector<'_> { // } // ``` let condition = match label { - Some(label) => { - self.with_labeled_rib(label, |this| this.collect_expr_opt(e.condition())) - } + Some((label_hygiene, label)) => self.with_labeled_rib(label, label_hygiene, |this| { + this.collect_expr_opt(e.condition()) + }), None => self.collect_expr_opt(e.condition()), }; @@ -820,7 +1020,7 @@ impl ExprCollector<'_> { Expr::If { condition, then_branch: body, else_branch: Some(break_expr) }, syntax_ptr, ); - self.alloc_expr(Expr::Loop { body: if_expr, label }, syntax_ptr) + self.alloc_expr(Expr::Loop { body: if_expr, label: label.map(|it| it.1) }, syntax_ptr) } /// Desugar `ast::ForExpr` from: `[opt_ident]: for <pat> in <head> <body>` into: @@ -851,15 +1051,11 @@ impl ExprCollector<'_> { let head = self.collect_expr_opt(e.iterable()); let into_iter_fn_expr = self.alloc_expr(Expr::Path(into_iter_fn), syntax_ptr); let iterator = self.alloc_expr( - Expr::Call { - callee: into_iter_fn_expr, - args: Box::new([head]), - is_assignee_expr: false, - }, + Expr::Call { callee: into_iter_fn_expr, args: Box::new([head]) }, syntax_ptr, ); let none_arm = MatchArm { - pat: self.alloc_pat_desugared(Pat::Path(Box::new(option_none))), + pat: self.alloc_pat_desugared(Pat::Path(option_none)), guard: None, expr: self.alloc_expr(Expr::Break { expr: None, label: None }, syntax_ptr), }; @@ -868,7 +1064,9 @@ impl ExprCollector<'_> { args: Box::new([self.collect_pat_top(e.pat())]), ellipsis: None, }; - let label = e.label().map(|label| self.collect_label(label)); + let label = e.label().map(|label| { + (self.hygiene_id_for(label.syntax().text_range().start()), self.collect_label(label)) + }); let some_arm = MatchArm { pat: self.alloc_pat_desugared(some_pat), guard: None, @@ -884,11 +1082,7 @@ impl ExprCollector<'_> { ); let iter_next_fn_expr = self.alloc_expr(Expr::Path(iter_next_fn), syntax_ptr); let iter_next_expr = self.alloc_expr( - Expr::Call { - callee: iter_next_fn_expr, - args: Box::new([iter_expr_mut]), - is_assignee_expr: false, - }, + Expr::Call { callee: iter_next_fn_expr, args: Box::new([iter_expr_mut]) }, syntax_ptr, ); let loop_inner = self.alloc_expr( @@ -904,7 +1098,8 @@ impl ExprCollector<'_> { }, syntax_ptr, ); - let loop_outer = self.alloc_expr(Expr::Loop { body: loop_inner, label }, syntax_ptr); + let loop_outer = self + .alloc_expr(Expr::Loop { body: loop_inner, label: label.map(|it| it.1) }, syntax_ptr); let iter_binding = self.alloc_binding(iter_name, BindingAnnotation::Mutable); let iter_pat = self.alloc_pat_desugared(Pat::Bind { id: iter_binding, subpat: None }); self.add_definition_to_binding(iter_binding, iter_pat); @@ -942,10 +1137,8 @@ impl ExprCollector<'_> { }; let operand = self.collect_expr_opt(e.expr()); let try_branch = self.alloc_expr(Expr::Path(try_branch), syntax_ptr); - let expr = self.alloc_expr( - Expr::Call { callee: try_branch, args: Box::new([operand]), is_assignee_expr: false }, - syntax_ptr, - ); + let expr = self + .alloc_expr(Expr::Call { callee: try_branch, args: Box::new([operand]) }, syntax_ptr); let continue_name = Name::generate_new_name(self.body.bindings.len()); let continue_binding = self.alloc_binding(continue_name.clone(), BindingAnnotation::Unannotated); @@ -975,10 +1168,8 @@ impl ExprCollector<'_> { expr: { let it = self.alloc_expr(Expr::Path(Path::from(break_name)), syntax_ptr); let callee = self.alloc_expr(Expr::Path(try_from_residual), syntax_ptr); - let result = self.alloc_expr( - Expr::Call { callee, args: Box::new([it]), is_assignee_expr: false }, - syntax_ptr, - ); + let result = + self.alloc_expr(Expr::Call { callee, args: Box::new([it]) }, syntax_ptr); self.alloc_expr( match self.current_try_block_label { Some(label) => Expr::Break { expr: Some(result), label: Some(label) }, @@ -1065,7 +1256,14 @@ impl ExprCollector<'_> { // FIXME: Report parse errors here } + let SpanMap::ExpansionSpanMap(new_span_map) = self.expander.span_map(self.db) + else { + panic!("just expanded a macro, ExpansionSpanMap should be available"); + }; + let old_span_map = + mem::replace(&mut self.current_span_map, Some(new_span_map.clone())); let id = collector(self, Some(expansion.tree())); + self.current_span_map = old_span_map; self.ast_id_map = prev_ast_id_map; self.expander.exit(mark); id @@ -1108,7 +1306,7 @@ impl ExprCollector<'_> { // Make the macro-call point to its expanded expression so we can query // semantics on syntax pointers to the macro let src = self.expander.in_file(syntax_ptr); - self.source_map.expr_map.insert(src, tail); + self.source_map.expr_map.insert(src, tail.into()); }) } @@ -1119,8 +1317,7 @@ impl ExprCollector<'_> { return; } let pat = self.collect_pat_top(stmt.pat()); - let type_ref = - stmt.ty().map(|it| Interned::new(TypeRef::from_ast(&self.ctx(), it))); + let type_ref = stmt.ty().map(|it| TypeRef::from_ast(&self.ctx(), it)); let initializer = stmt.initializer().map(|e| self.collect_expr(e)); let else_branch = stmt .let_else() @@ -1145,10 +1342,46 @@ impl ExprCollector<'_> { statements.push(Statement::Expr { expr, has_semi }); } } - ast::Stmt::Item(_item) => statements.push(Statement::Item), + ast::Stmt::Item(ast::Item::MacroDef(macro_)) => { + let Some(name) = macro_.name() else { + statements.push(Statement::Item(Item::Other)); + return; + }; + let name = name.as_name(); + let macro_id = self.def_map.modules[DefMap::ROOT].scope.get(&name).take_macros(); + self.collect_macro_def(statements, macro_id); + } + ast::Stmt::Item(ast::Item::MacroRules(macro_)) => { + let Some(name) = macro_.name() else { + statements.push(Statement::Item(Item::Other)); + return; + }; + let name = name.as_name(); + let macro_defs_count = + self.current_block_legacy_macro_defs_count.entry(name.clone()).or_insert(0); + let macro_id = self.def_map.modules[DefMap::ROOT] + .scope + .get_legacy_macro(&name) + .and_then(|it| it.get(*macro_defs_count)) + .copied(); + *macro_defs_count += 1; + self.collect_macro_def(statements, macro_id); + } + ast::Stmt::Item(_item) => statements.push(Statement::Item(Item::Other)), } } + fn collect_macro_def(&mut self, statements: &mut Vec<Statement>, macro_id: Option<MacroId>) { + let Some(macro_id) = macro_id else { + never!("def map should have macro definition, but it doesn't"); + statements.push(Statement::Item(Item::Other)); + return; + }; + let macro_id = self.db.macro_def(macro_id); + statements.push(Statement::Item(Item::MacroDef(Box::new(macro_id)))); + self.label_ribs.push(LabelRib::new(RibKind::MacroDef(Box::new(macro_id)))); + } + fn collect_block(&mut self, block: ast::BlockExpr) -> ExprId { self.collect_block_(block, |id, statements, tail| Expr::Block { id, @@ -1194,6 +1427,7 @@ impl ExprCollector<'_> { }; let prev_def_map = mem::replace(&mut self.def_map, def_map); let prev_local_module = mem::replace(&mut self.expander.module, module); + let prev_legacy_macros_count = mem::take(&mut self.current_block_legacy_macro_defs_count); let mut statements = Vec::new(); block.statements().for_each(|s| self.collect_stmt(&mut statements, s)); @@ -1216,6 +1450,7 @@ impl ExprCollector<'_> { self.def_map = prev_def_map; self.expander.module = prev_local_module; + self.current_block_legacy_macro_defs_count = prev_legacy_macros_count; expr_id } @@ -1228,11 +1463,13 @@ impl ExprCollector<'_> { fn collect_labelled_block_opt( &mut self, - label: Option<LabelId>, + label: Option<(HygieneId, LabelId)>, expr: Option<ast::BlockExpr>, ) -> ExprId { match label { - Some(label) => self.with_labeled_rib(label, |this| this.collect_block_opt(expr)), + Some((hygiene, label)) => { + self.with_labeled_rib(label, hygiene, |this| this.collect_block_opt(expr)) + } None => self.collect_block_opt(expr), } } @@ -1250,6 +1487,10 @@ impl ExprCollector<'_> { let pattern = match &pat { ast::Pat::IdentPat(bp) => { let name = bp.name().map(|nr| nr.as_name()).unwrap_or_else(Name::missing); + let hygiene = bp + .name() + .map(|name| self.hygiene_id_for(name.syntax().text_range().start())) + .unwrap_or(HygieneId::ROOT); let annotation = BindingAnnotation::new(bp.mut_token().is_some(), bp.ref_token().is_some()); @@ -1285,12 +1526,12 @@ impl ExprCollector<'_> { } // shadowing statics is an error as well, so we just ignore that case here _ => { - let id = binding_list.find(self, name, annotation); + let id = binding_list.find(self, name, hygiene, annotation); (Some(id), Pat::Bind { id, subpat }) } } } else { - let id = binding_list.find(self, name, annotation); + let id = binding_list.find(self, name, hygiene, annotation); (Some(id), Pat::Bind { id, subpat }) }; @@ -1302,8 +1543,7 @@ impl ExprCollector<'_> { return pat; } ast::Pat::TupleStructPat(p) => { - let path = - p.path().and_then(|path| self.expander.parse_path(self.db, path)).map(Box::new); + let path = p.path().and_then(|path| self.parse_path(path)).map(Box::new); let (args, ellipsis) = self.collect_tuple_pat( p.fields(), comma_follows_token(p.l_paren_token()), @@ -1317,8 +1557,7 @@ impl ExprCollector<'_> { Pat::Ref { pat, mutability } } ast::Pat::PathPat(p) => { - let path = - p.path().and_then(|path| self.expander.parse_path(self.db, path)).map(Box::new); + let path = p.path().and_then(|path| self.parse_path(path)); path.map(Pat::Path).unwrap_or(Pat::Missing) } ast::Pat::OrPat(p) => 'b: { @@ -1348,6 +1587,10 @@ impl ExprCollector<'_> { for (id, _) in current_is_used.into_iter() { binding_list.check_is_used(self, id); } + if let &[pat] = &*pats { + // Leading pipe without real OR pattern. Leaving an one-item OR pattern may confuse later stages. + return pat; + } Pat::Or(pats.into()) } ast::Pat::ParenPat(p) => return self.collect_pat_opt(p.pat(), binding_list), @@ -1361,8 +1604,7 @@ impl ExprCollector<'_> { } ast::Pat::WildcardPat(_) => Pat::Wild, ast::Pat::RecordPat(p) => { - let path = - p.path().and_then(|path| self.expander.parse_path(self.db, path)).map(Box::new); + let path = p.path().and_then(|path| self.parse_path(path)).map(Box::new); let record_pat_field_list = &p.record_pat_field_list().expect("every struct should have a field list"); let args = record_pat_field_list @@ -1372,7 +1614,7 @@ impl ExprCollector<'_> { let ast_pat = f.pat()?; let pat = self.collect_pat(ast_pat, binding_list); let name = f.field_name()?.as_name(); - let src = self.expander.in_file(AstPtr::new(&f)); + let src = self.expander.in_file(AstPtr::new(&f).wrap_right()); self.source_map.pat_field_map_back.insert(pat, src); Some(RecordFieldPat { name, pat }) }) @@ -1569,20 +1811,51 @@ impl ExprCollector<'_> { lifetime: Option<ast::Lifetime>, ) -> Result<Option<LabelId>, BodyDiagnostic> { let Some(lifetime) = lifetime else { return Ok(None) }; + let (mut hygiene_id, mut hygiene_info) = match &self.current_span_map { + None => (HygieneId::ROOT, None), + Some(span_map) => { + let span = span_map.span_at(lifetime.syntax().text_range().start()); + let ctx = self.db.lookup_intern_syntax_context(span.ctx); + let hygiene_id = HygieneId::new(ctx.opaque_and_semitransparent); + let hygiene_info = ctx.outer_expn.map(|expansion| { + let expansion = self.db.lookup_intern_macro_call(expansion); + (ctx.parent, expansion.def) + }); + (hygiene_id, hygiene_info) + } + }; let name = Name::new_lifetime(&lifetime); for (rib_idx, rib) in self.label_ribs.iter().enumerate().rev() { - if let Some((label_name, id)) = &rib.label { - if *label_name == name { - return if self.is_label_valid_from_rib(rib_idx) { - Ok(Some(*id)) - } else { - Err(BodyDiagnostic::UnreachableLabel { - name, - node: self.expander.in_file(AstPtr::new(&lifetime)), - }) - }; + match &rib.kind { + RibKind::Normal(label_name, id, label_hygiene) => { + if *label_name == name && *label_hygiene == hygiene_id { + return if self.is_label_valid_from_rib(rib_idx) { + Ok(Some(*id)) + } else { + Err(BodyDiagnostic::UnreachableLabel { + name, + node: self.expander.in_file(AstPtr::new(&lifetime)), + }) + }; + } } + RibKind::MacroDef(macro_id) => { + if let Some((parent_ctx, label_macro_id)) = hygiene_info { + if label_macro_id == **macro_id { + // A macro is allowed to refer to labels from before its declaration. + // Therefore, if we got to the rib of its declaration, give up its hygiene + // and use its parent expansion. + let parent_ctx = self.db.lookup_intern_syntax_context(parent_ctx); + hygiene_id = HygieneId::new(parent_ctx.opaque_and_semitransparent); + hygiene_info = parent_ctx.outer_expn.map(|expansion| { + let expansion = self.db.lookup_intern_macro_call(expansion); + (parent_ctx.parent, expansion.def) + }); + } + } + } + _ => {} } } @@ -1596,28 +1869,44 @@ impl ExprCollector<'_> { !self.label_ribs[rib_index + 1..].iter().any(|rib| rib.kind.is_label_barrier()) } + fn pop_label_rib(&mut self) { + // We need to pop all macro defs, plus one rib. + while let Some(LabelRib { kind: RibKind::MacroDef(_) }) = self.label_ribs.pop() { + // Do nothing. + } + } + fn with_label_rib<T>(&mut self, kind: RibKind, f: impl FnOnce(&mut Self) -> T) -> T { self.label_ribs.push(LabelRib::new(kind)); let res = f(self); - self.label_ribs.pop(); + self.pop_label_rib(); res } - fn with_labeled_rib<T>(&mut self, label: LabelId, f: impl FnOnce(&mut Self) -> T) -> T { - self.label_ribs.push(LabelRib::new_normal((self.body[label].name.clone(), label))); + fn with_labeled_rib<T>( + &mut self, + label: LabelId, + hygiene: HygieneId, + f: impl FnOnce(&mut Self) -> T, + ) -> T { + self.label_ribs.push(LabelRib::new(RibKind::Normal( + self.body[label].name.clone(), + label, + hygiene, + ))); let res = f(self); - self.label_ribs.pop(); + self.pop_label_rib(); res } fn with_opt_labeled_rib<T>( &mut self, - label: Option<LabelId>, + label: Option<(HygieneId, LabelId)>, f: impl FnOnce(&mut Self) -> T, ) -> T { match label { None => f(self), - Some(label) => self.with_labeled_rib(label, f), + Some((hygiene, label)) => self.with_labeled_rib(label, hygiene, f), } } // endregion: labels @@ -1666,28 +1955,39 @@ impl ExprCollector<'_> { _ => None, }); let mut mappings = vec![]; - let fmt = match template.and_then(|it| self.expand_macros_to_string(it)) { + let (fmt, hygiene) = match template.and_then(|it| self.expand_macros_to_string(it)) { Some((s, is_direct_literal)) => { let call_ctx = self.expander.syntax_context(); - format_args::parse( + let hygiene = self.hygiene_id_for(s.syntax().text_range().start()); + let fmt = format_args::parse( &s, fmt_snippet, args, is_direct_literal, - |name| self.alloc_expr_desugared(Expr::Path(Path::from(name))), + |name| { + let expr_id = self.alloc_expr_desugared(Expr::Path(Path::from(name))); + if !hygiene.is_root() { + self.body.expr_hygiene.insert(expr_id, hygiene); + } + expr_id + }, |name, span| { if let Some(span) = span { mappings.push((span, name)) } }, call_ctx, - ) + ); + (fmt, hygiene) } - None => FormatArgs { - template: Default::default(), - arguments: args.finish(), - orphans: Default::default(), - }, + None => ( + FormatArgs { + template: Default::default(), + arguments: args.finish(), + orphans: Default::default(), + }, + HygieneId::ROOT, + ), }; // Create a list of all _unique_ (argument, format trait) combinations. @@ -1723,10 +2023,8 @@ impl ExprCollector<'_> { } }) .collect(); - let lit_pieces = self.alloc_expr_desugared(Expr::Array(Array::ElementList { - elements: lit_pieces, - is_assignee_expr: false, - })); + let lit_pieces = + self.alloc_expr_desugared(Expr::Array(Array::ElementList { elements: lit_pieces })); let lit_pieces = self.alloc_expr_desugared(Expr::Ref { expr: lit_pieces, rawness: Rawness::Ref, @@ -1743,10 +2041,7 @@ impl ExprCollector<'_> { Some(self.make_format_spec(placeholder, &mut argmap)) }) .collect(); - let array = self.alloc_expr_desugared(Expr::Array(Array::ElementList { - elements, - is_assignee_expr: false, - })); + let array = self.alloc_expr_desugared(Expr::Array(Array::ElementList { elements })); self.alloc_expr_desugared(Expr::Ref { expr: array, rawness: Rawness::Ref, @@ -1756,10 +2051,8 @@ impl ExprCollector<'_> { let arguments = &*fmt.arguments.arguments; let args = if arguments.is_empty() { - let expr = self.alloc_expr_desugared(Expr::Array(Array::ElementList { - elements: Box::default(), - is_assignee_expr: false, - })); + let expr = self + .alloc_expr_desugared(Expr::Array(Array::ElementList { elements: Box::default() })); self.alloc_expr_desugared(Expr::Ref { expr, rawness: Rawness::Ref, @@ -1786,10 +2079,8 @@ impl ExprCollector<'_> { self.make_argument(arg, ty) }) .collect(); - let array = self.alloc_expr_desugared(Expr::Array(Array::ElementList { - elements: args, - is_assignee_expr: false, - })); + let array = + self.alloc_expr_desugared(Expr::Array(Array::ElementList { elements: args })); self.alloc_expr_desugared(Expr::Ref { expr: array, rawness: Rawness::Ref, @@ -1822,11 +2113,8 @@ impl ExprCollector<'_> { let new_v1_formatted = self.alloc_expr_desugared(Expr::Path(new_v1_formatted)); let unsafe_arg_new = self.alloc_expr_desugared(Expr::Path(unsafe_arg_new)); - let unsafe_arg_new = self.alloc_expr_desugared(Expr::Call { - callee: unsafe_arg_new, - args: Box::default(), - is_assignee_expr: false, - }); + let unsafe_arg_new = + self.alloc_expr_desugared(Expr::Call { callee: unsafe_arg_new, args: Box::default() }); let unsafe_arg_new = self.alloc_expr_desugared(Expr::Unsafe { id: None, // We collect the unused expressions here so that we still infer them instead of @@ -1843,11 +2131,14 @@ impl ExprCollector<'_> { Expr::Call { callee: new_v1_formatted, args: Box::new([lit_pieces, args, format_options, unsafe_arg_new]), - is_assignee_expr: false, }, syntax_ptr, ); - self.source_map.template_map.get_or_insert_with(Default::default).0.insert(idx, mappings); + self.source_map + .template_map + .get_or_insert_with(Default::default) + .0 + .insert(idx, (hygiene, mappings)); idx } @@ -1938,7 +2229,6 @@ impl ExprCollector<'_> { self.alloc_expr_desugared(Expr::Call { callee: format_placeholder_new, args: Box::new([position, fill, align, flags, precision, width]), - is_assignee_expr: false, }) } @@ -1980,11 +2270,7 @@ impl ExprCollector<'_> { Some(count_is) => self.alloc_expr_desugared(Expr::Path(count_is)), None => self.missing_expr(), }; - self.alloc_expr_desugared(Expr::Call { - callee: count_is, - args: Box::new([args]), - is_assignee_expr: false, - }) + self.alloc_expr_desugared(Expr::Call { callee: count_is, args: Box::new([args]) }) } Some(FormatCount::Argument(arg)) => { if let Ok(arg_index) = arg.index { @@ -2005,7 +2291,6 @@ impl ExprCollector<'_> { self.alloc_expr_desugared(Expr::Call { callee: count_param, args: Box::new([args]), - is_assignee_expr: false, }) } else { // FIXME: This drops arg causing it to potentially not be resolved/type checked @@ -2054,11 +2339,7 @@ impl ExprCollector<'_> { Some(new_fn) => self.alloc_expr_desugared(Expr::Path(new_fn)), None => self.missing_expr(), }; - self.alloc_expr_desugared(Expr::Call { - callee: new_fn, - args: Box::new([arg]), - is_assignee_expr: false, - }) + self.alloc_expr_desugared(Expr::Call { callee: new_fn, args: Box::new([arg]) }) } // endregion: format @@ -2082,7 +2363,7 @@ impl ExprCollector<'_> { let src = self.expander.in_file(ptr); let id = self.body.exprs.alloc(expr); self.source_map.expr_map_back.insert(id, src); - self.source_map.expr_map.insert(src, id); + self.source_map.expr_map.insert(src, id.into()); id } // FIXME: desugared exprs don't have ptr, that's wrong and should be fixed. @@ -2110,10 +2391,17 @@ impl ExprCollector<'_> { binding } + fn alloc_pat_from_expr(&mut self, pat: Pat, ptr: ExprPtr) -> PatId { + let src = self.expander.in_file(ptr); + let id = self.body.pats.alloc(pat); + self.source_map.expr_map.insert(src, id.into()); + self.source_map.pat_map_back.insert(id, src.map(AstPtr::wrap_left)); + id + } fn alloc_pat(&mut self, pat: Pat, ptr: PatPtr) -> PatId { let src = self.expander.in_file(ptr); let id = self.body.pats.alloc(pat); - self.source_map.pat_map_back.insert(id, src); + self.source_map.pat_map_back.insert(id, src.map(AstPtr::wrap_right)); self.source_map.pat_map.insert(src, id); id } @@ -2151,6 +2439,17 @@ impl ExprCollector<'_> { self.awaitable_context = orig; res } + + /// If this returns `HygieneId::ROOT`, do not allocate to save space. + fn hygiene_id_for(&self, span_start: TextSize) -> HygieneId { + match &self.current_span_map { + None => HygieneId::ROOT, + Some(span_map) => { + let ctx = span_map.span_at(span_start).ctx; + HygieneId(self.db.lookup_intern_syntax_context(ctx).opaque_and_semitransparent) + } + } + } } fn comma_follows_token(t: Option<syntax::SyntaxToken>) -> bool { diff --git a/src/tools/rust-analyzer/crates/hir-def/src/body/lower/asm.rs b/src/tools/rust-analyzer/crates/hir-def/src/body/lower/asm.rs index 4213370ac19..c1b58dbdd0c 100644 --- a/src/tools/rust-analyzer/crates/hir-def/src/body/lower/asm.rs +++ b/src/tools/rust-analyzer/crates/hir-def/src/body/lower/asm.rs @@ -158,9 +158,7 @@ impl ExprCollector<'_> { AsmOperand::Const(self.collect_expr_opt(c.expr())) } ast::AsmOperand::AsmSym(s) => { - let Some(path) = - s.path().and_then(|p| self.expander.parse_path(self.db, p)) - else { + let Some(path) = s.path().and_then(|p| self.parse_path(p)) else { continue; }; AsmOperand::Sym(path) diff --git a/src/tools/rust-analyzer/crates/hir-def/src/body/pretty.rs b/src/tools/rust-analyzer/crates/hir-def/src/body/pretty.rs index 37167fcb815..f8b6eef3422 100644 --- a/src/tools/rust-analyzer/crates/hir-def/src/body/pretty.rs +++ b/src/tools/rust-analyzer/crates/hir-def/src/body/pretty.rs @@ -11,7 +11,6 @@ use crate::{ Statement, }, pretty::{print_generic_args, print_path, print_type_ref}, - type_ref::TypeRef, }; use super::*; @@ -69,20 +68,20 @@ pub(super) fn print_body_hir( }; if let DefWithBodyId::FunctionId(it) = owner { p.buf.push('('); - let function_data = &db.function_data(it); + let function_data = db.function_data(it); let (mut params, ret_type) = (function_data.params.iter(), &function_data.ret_type); if let Some(self_param) = body.self_param { p.print_binding(self_param); p.buf.push_str(": "); if let Some(ty) = params.next() { - p.print_type_ref(ty); + p.print_type_ref(*ty, &function_data.types_map); p.buf.push_str(", "); } } body.params.iter().zip(params).for_each(|(¶m, ty)| { p.print_pat(param); p.buf.push_str(": "); - p.print_type_ref(ty); + p.print_type_ref(*ty, &function_data.types_map); p.buf.push_str(", "); }); // remove the last ", " in param list @@ -92,7 +91,7 @@ pub(super) fn print_body_hir( p.buf.push(')'); // return type p.buf.push_str(" -> "); - p.print_type_ref(ret_type); + p.print_type_ref(*ret_type, &function_data.types_map); p.buf.push(' '); } p.print_expr(body.body_expr); @@ -242,7 +241,7 @@ impl Printer<'_> { Expr::InlineAsm(_) => w!(self, "builtin#asm(_)"), Expr::OffsetOf(offset_of) => { w!(self, "builtin#offset_of("); - self.print_type_ref(&offset_of.container); + self.print_type_ref(offset_of.container, &self.body.types); let edition = self.edition; w!( self, @@ -277,7 +276,7 @@ impl Printer<'_> { w!(self, "loop "); self.print_expr(*body); } - Expr::Call { callee, args, is_assignee_expr: _ } => { + Expr::Call { callee, args } => { self.print_expr(*callee); w!(self, "("); if !args.is_empty() { @@ -296,7 +295,7 @@ impl Printer<'_> { if let Some(args) = generic_args { w!(self, "::<"); let edition = self.edition; - print_generic_args(self.db, args, self, edition).unwrap(); + print_generic_args(self.db, args, &self.body.types, self, edition).unwrap(); w!(self, ">"); } w!(self, "("); @@ -372,7 +371,7 @@ impl Printer<'_> { self.print_expr(*expr); } } - Expr::RecordLit { path, fields, spread, ellipsis, is_assignee_expr: _ } => { + Expr::RecordLit { path, fields, spread } => { match path { Some(path) => self.print_path(path), None => w!(self, "�"), @@ -391,9 +390,6 @@ impl Printer<'_> { p.print_expr(*spread); wln!(p); } - if *ellipsis { - wln!(p, ".."); - } }); w!(self, "}}"); } @@ -408,7 +404,7 @@ impl Printer<'_> { Expr::Cast { expr, type_ref } => { self.print_expr(*expr); w!(self, " as "); - self.print_type_ref(type_ref); + self.print_type_ref(*type_ref, &self.body.types); } Expr::Ref { expr, rawness, mutability } => { w!(self, "&"); @@ -466,7 +462,7 @@ impl Printer<'_> { w!(self, ") "); } } - Expr::Index { base, index, is_assignee_expr: _ } => { + Expr::Index { base, index } => { self.print_expr(*base); w!(self, "["); self.print_expr(*index); @@ -496,18 +492,18 @@ impl Printer<'_> { self.print_pat(*pat); if let Some(ty) = ty { w!(self, ": "); - self.print_type_ref(ty); + self.print_type_ref(*ty, &self.body.types); } } w!(self, "|"); if let Some(ret_ty) = ret_type { w!(self, " -> "); - self.print_type_ref(ret_ty); + self.print_type_ref(*ret_ty, &self.body.types); } self.whitespace(); self.print_expr(*body); } - Expr::Tuple { exprs, is_assignee_expr: _ } => { + Expr::Tuple { exprs } => { w!(self, "("); for expr in exprs.iter() { self.print_expr(*expr); @@ -519,7 +515,7 @@ impl Printer<'_> { w!(self, "["); if !matches!(arr, Array::ElementList { elements, .. } if elements.is_empty()) { self.indented(|p| match arr { - Array::ElementList { elements, is_assignee_expr: _ } => { + Array::ElementList { elements } => { for elem in elements.iter() { p.print_expr(*elem); w!(p, ", "); @@ -551,6 +547,11 @@ impl Printer<'_> { Expr::Const(id) => { w!(self, "const {{ /* {id:?} */ }}"); } + &Expr::Assignment { target, value } => { + self.print_pat(target); + w!(self, " = "); + self.print_expr(value); + } } } @@ -719,6 +720,9 @@ impl Printer<'_> { w!(self, "const "); self.print_expr(*c); } + Pat::Expr(expr) => { + self.print_expr(*expr); + } } } @@ -729,7 +733,7 @@ impl Printer<'_> { self.print_pat(*pat); if let Some(ty) = type_ref { w!(self, ": "); - self.print_type_ref(ty); + self.print_type_ref(*ty, &self.body.types); } if let Some(init) = initializer { w!(self, " = "); @@ -748,7 +752,7 @@ impl Printer<'_> { } wln!(self); } - Statement::Item => (), + Statement::Item(_) => (), } } @@ -787,14 +791,14 @@ impl Printer<'_> { } } - fn print_type_ref(&mut self, ty: &TypeRef) { + fn print_type_ref(&mut self, ty: TypeRefId, map: &TypesMap) { let edition = self.edition; - print_type_ref(self.db, ty, self, edition).unwrap(); + print_type_ref(self.db, ty, map, self, edition).unwrap(); } fn print_path(&mut self, path: &Path) { let edition = self.edition; - print_path(self.db, path, self, edition).unwrap(); + print_path(self.db, path, &self.body.types, self, edition).unwrap(); } fn print_binding(&mut self, id: BindingId) { diff --git a/src/tools/rust-analyzer/crates/hir-def/src/body/scope.rs b/src/tools/rust-analyzer/crates/hir-def/src/body/scope.rs index bf201ca8347..63a7a9af201 100644 --- a/src/tools/rust-analyzer/crates/hir-def/src/body/scope.rs +++ b/src/tools/rust-analyzer/crates/hir-def/src/body/scope.rs @@ -1,12 +1,12 @@ //! Name resolution for expressions. -use hir_expand::name::Name; +use hir_expand::{name::Name, MacroDefId}; use la_arena::{Arena, ArenaMap, Idx, IdxRange, RawIdx}; use triomphe::Arc; use crate::{ - body::Body, + body::{Body, HygieneId}, db::DefDatabase, - hir::{Binding, BindingId, Expr, ExprId, LabelId, Pat, PatId, Statement}, + hir::{Binding, BindingId, Expr, ExprId, Item, LabelId, Pat, PatId, Statement}, BlockId, ConstBlockId, DefWithBodyId, }; @@ -22,6 +22,7 @@ pub struct ExprScopes { #[derive(Debug, PartialEq, Eq)] pub struct ScopeEntry { name: Name, + hygiene: HygieneId, binding: BindingId, } @@ -30,6 +31,10 @@ impl ScopeEntry { &self.name } + pub(crate) fn hygiene(&self) -> HygieneId { + self.hygiene + } + pub fn binding(&self) -> BindingId { self.binding } @@ -40,6 +45,8 @@ pub struct ScopeData { parent: Option<ScopeId>, block: Option<BlockId>, label: Option<(LabelId, Name)>, + // FIXME: We can compress this with an enum for this and `label`/`block` if memory usage matters. + macro_def: Option<Box<MacroDefId>>, entries: IdxRange<ScopeEntry>, } @@ -62,6 +69,12 @@ impl ExprScopes { self.scopes[scope].block } + /// If `scope` refers to a macro def scope, returns the corresponding `MacroId`. + #[allow(clippy::borrowed_box)] // If we return `&MacroDefId` we need to move it, this way we just clone the `Box`. + pub fn macro_def(&self, scope: ScopeId) -> Option<&Box<MacroDefId>> { + self.scopes[scope].macro_def.as_ref() + } + /// If `scope` refers to a labeled expression scope, returns the corresponding `Label`. pub fn label(&self, scope: ScopeId) -> Option<(LabelId, Name)> { self.scopes[scope].label.clone() @@ -102,7 +115,7 @@ impl ExprScopes { }; let mut root = scopes.root_scope(); if let Some(self_param) = body.self_param { - scopes.add_bindings(body, root, self_param); + scopes.add_bindings(body, root, self_param, body.binding_hygiene(self_param)); } scopes.add_params_bindings(body, root, &body.params); compute_expr_scopes(body.body_expr, body, &mut scopes, &mut root, resolve_const_block); @@ -114,6 +127,7 @@ impl ExprScopes { parent: None, block: None, label: None, + macro_def: None, entries: empty_entries(self.scope_entries.len()), }) } @@ -123,6 +137,7 @@ impl ExprScopes { parent: Some(parent), block: None, label: None, + macro_def: None, entries: empty_entries(self.scope_entries.len()), }) } @@ -132,6 +147,7 @@ impl ExprScopes { parent: Some(parent), block: None, label, + macro_def: None, entries: empty_entries(self.scope_entries.len()), }) } @@ -146,21 +162,38 @@ impl ExprScopes { parent: Some(parent), block, label, + macro_def: None, entries: empty_entries(self.scope_entries.len()), }) } - fn add_bindings(&mut self, body: &Body, scope: ScopeId, binding: BindingId) { + fn new_macro_def_scope(&mut self, parent: ScopeId, macro_id: Box<MacroDefId>) -> ScopeId { + self.scopes.alloc(ScopeData { + parent: Some(parent), + block: None, + label: None, + macro_def: Some(macro_id), + entries: empty_entries(self.scope_entries.len()), + }) + } + + fn add_bindings( + &mut self, + body: &Body, + scope: ScopeId, + binding: BindingId, + hygiene: HygieneId, + ) { let Binding { name, .. } = &body.bindings[binding]; - let entry = self.scope_entries.alloc(ScopeEntry { name: name.clone(), binding }); + let entry = self.scope_entries.alloc(ScopeEntry { name: name.clone(), binding, hygiene }); self.scopes[scope].entries = IdxRange::new_inclusive(self.scopes[scope].entries.start()..=entry); } fn add_pat_bindings(&mut self, body: &Body, scope: ScopeId, pat: PatId) { let pattern = &body[pat]; - if let Pat::Bind { id, .. } = pattern { - self.add_bindings(body, scope, *id); + if let Pat::Bind { id, .. } = *pattern { + self.add_bindings(body, scope, id, body.binding_hygiene(id)); } pattern.walk_child_pats(|pat| self.add_pat_bindings(body, scope, pat)); @@ -206,7 +239,10 @@ fn compute_block_scopes( Statement::Expr { expr, .. } => { compute_expr_scopes(*expr, body, scopes, scope, resolve_const_block); } - Statement::Item => (), + Statement::Item(Item::MacroDef(macro_id)) => { + *scope = scopes.new_macro_def_scope(*scope, macro_id.clone()); + } + Statement::Item(Item::Other) => (), } } if let Some(expr) = tail { @@ -282,7 +318,7 @@ fn compute_expr_scopes( *scope = scopes.new_scope(*scope); scopes.add_pat_bindings(body, *scope, pat); } - e => e.walk_child_exprs(|e| compute_expr_scopes(scopes, e, scope)), + _ => body.walk_child_exprs(expr, |e| compute_expr_scopes(scopes, e, scope)), }; } @@ -333,6 +369,8 @@ mod tests { let expr_id = source_map .node_expr(InFile { file_id: file_id.into(), value: &marker.into() }) + .unwrap() + .as_expr() .unwrap(); let scope = scopes.scope_for(expr_id); @@ -488,8 +526,11 @@ fn foo() { let expr_scope = { let expr_ast = name_ref.syntax().ancestors().find_map(ast::Expr::cast).unwrap(); - let expr_id = - source_map.node_expr(InFile { file_id: file_id.into(), value: &expr_ast }).unwrap(); + let expr_id = source_map + .node_expr(InFile { file_id: file_id.into(), value: &expr_ast }) + .unwrap() + .as_expr() + .unwrap(); scopes.scope_for(expr_id).unwrap() }; diff --git a/src/tools/rust-analyzer/crates/hir-def/src/body/tests.rs b/src/tools/rust-analyzer/crates/hir-def/src/body/tests.rs index dd3e79c874d..3b29d98d198 100644 --- a/src/tools/rust-analyzer/crates/hir-def/src/body/tests.rs +++ b/src/tools/rust-analyzer/crates/hir-def/src/body/tests.rs @@ -370,3 +370,37 @@ fn f(a: i32, b: u32) -> String { }"#]] .assert_eq(&body.pretty_print(&db, def, Edition::CURRENT)) } + +#[test] +fn destructuring_assignment_tuple_macro() { + // This is a funny one. `let m!()() = Bar()` is an error in rustc, because `m!()()` isn't a valid pattern, + // but in destructuring assignment it is valid, because `m!()()` is a valid expression, and destructuring + // assignments start their lives as expressions. So we have to do the same. + + let (db, body, def) = lower( + r#" +struct Bar(); + +macro_rules! m { + () => { Bar }; +} + +fn foo() { + m!()() = Bar(); +} +"#, + ); + + let (_, source_map) = db.body_with_source_map(def); + assert_eq!(source_map.diagnostics(), &[]); + + for (_, def_map) in body.blocks(&db) { + assert_eq!(def_map.diagnostics(), &[]); + } + + expect![[r#" + fn foo() -> () { + Bar() = Bar(); + }"#]] + .assert_eq(&body.pretty_print(&db, def, Edition::CURRENT)) +} diff --git a/src/tools/rust-analyzer/crates/hir-def/src/data.rs b/src/tools/rust-analyzer/crates/hir-def/src/data.rs index 263fad51d78..f49018eaf38 100644 --- a/src/tools/rust-analyzer/crates/hir-def/src/data.rs +++ b/src/tools/rust-analyzer/crates/hir-def/src/data.rs @@ -6,7 +6,7 @@ use base_db::CrateId; use hir_expand::{ name::Name, AstId, ExpandResult, HirFileId, InFile, MacroCallId, MacroCallKind, MacroDefKind, }; -use intern::{sym, Interned, Symbol}; +use intern::{sym, Symbol}; use la_arena::{Idx, RawIdx}; use smallvec::SmallVec; use syntax::{ast, Parse}; @@ -25,7 +25,7 @@ use crate::{ DefMap, MacroSubNs, }, path::ImportAlias, - type_ref::{TraitRef, TypeBound, TypeRef}, + type_ref::{TraitRef, TypeBound, TypeRefId, TypesMap}, visibility::RawVisibility, AssocItemId, AstIdWithPath, ConstId, ConstLoc, ExternCrateId, FunctionId, FunctionLoc, HasModule, ImplId, Intern, ItemContainerId, ItemLoc, Lookup, Macro2Id, MacroRulesId, ModuleId, @@ -35,13 +35,14 @@ use crate::{ #[derive(Debug, Clone, PartialEq, Eq)] pub struct FunctionData { pub name: Name, - pub params: Box<[Interned<TypeRef>]>, - pub ret_type: Interned<TypeRef>, + pub params: Box<[TypeRefId]>, + pub ret_type: TypeRefId, pub attrs: Attrs, pub visibility: RawVisibility, pub abi: Option<Symbol>, pub legacy_const_generics_indices: Option<Box<Box<[u32]>>>, pub rustc_allow_incoherent_impl: bool, + pub types_map: Arc<TypesMap>, flags: FnFlags, } @@ -110,13 +111,14 @@ impl FunctionData { .filter(|&(idx, _)| { item_tree.attrs(db, krate, attr_owner(idx)).is_cfg_enabled(cfg_options) }) - .filter_map(|(_, param)| param.type_ref.clone()) + .filter_map(|(_, param)| param.type_ref) .collect(), - ret_type: func.ret_type.clone(), + ret_type: func.ret_type, attrs: item_tree.attrs(db, krate, ModItem::from(loc.id.value).into()), visibility, abi: func.abi.clone(), legacy_const_generics_indices, + types_map: func.types_map.clone(), flags, rustc_allow_incoherent_impl, }) @@ -182,13 +184,14 @@ fn parse_rustc_legacy_const_generics(tt: &crate::tt::Subtree) -> Box<[u32]> { #[derive(Debug, Clone, PartialEq, Eq)] pub struct TypeAliasData { pub name: Name, - pub type_ref: Option<Interned<TypeRef>>, + pub type_ref: Option<TypeRefId>, pub visibility: RawVisibility, pub is_extern: bool, pub rustc_has_incoherent_inherent_impls: bool, pub rustc_allow_incoherent_impl: bool, /// Bounds restricting the type alias itself (eg. `type Ty: Bound;` in a trait or impl). - pub bounds: Box<[Interned<TypeBound>]>, + pub bounds: Box<[TypeBound]>, + pub types_map: Arc<TypesMap>, } impl TypeAliasData { @@ -216,12 +219,13 @@ impl TypeAliasData { Arc::new(TypeAliasData { name: typ.name.clone(), - type_ref: typ.type_ref.clone(), + type_ref: typ.type_ref, visibility, is_extern: matches!(loc.container, ItemContainerId::ExternBlockId(_)), rustc_has_incoherent_inherent_impls, rustc_allow_incoherent_impl, bounds: typ.bounds.clone(), + types_map: typ.types_map.clone(), }) } } @@ -343,13 +347,14 @@ impl TraitAliasData { #[derive(Debug, PartialEq, Eq)] pub struct ImplData { - pub target_trait: Option<Interned<TraitRef>>, - pub self_ty: Interned<TypeRef>, + pub target_trait: Option<TraitRef>, + pub self_ty: TypeRefId, pub items: Box<[AssocItemId]>, pub is_negative: bool, pub is_unsafe: bool, // box it as the vec is usually empty anyways pub macro_calls: Option<Box<Vec<(AstId<ast::Item>, MacroCallId)>>>, + pub types_map: Arc<TypesMap>, } impl ImplData { @@ -368,7 +373,7 @@ impl ImplData { let item_tree = tree_id.item_tree(db); let impl_def = &item_tree[tree_id.value]; let target_trait = impl_def.target_trait.clone(); - let self_ty = impl_def.self_ty.clone(); + let self_ty = impl_def.self_ty; let is_negative = impl_def.is_negative; let is_unsafe = impl_def.is_unsafe; @@ -387,6 +392,7 @@ impl ImplData { is_negative, is_unsafe, macro_calls, + types_map: impl_def.types_map.clone(), }), DefDiagnostics::new(diagnostics), ) @@ -532,10 +538,11 @@ impl ExternCrateDeclData { pub struct ConstData { /// `None` for `const _: () = ();` pub name: Option<Name>, - pub type_ref: Interned<TypeRef>, + pub type_ref: TypeRefId, pub visibility: RawVisibility, pub rustc_allow_incoherent_impl: bool, pub has_body: bool, + pub types_map: Arc<TypesMap>, } impl ConstData { @@ -556,10 +563,11 @@ impl ConstData { Arc::new(ConstData { name: konst.name.clone(), - type_ref: konst.type_ref.clone(), + type_ref: konst.type_ref, visibility, rustc_allow_incoherent_impl, has_body: konst.has_body, + types_map: konst.types_map.clone(), }) } } @@ -567,12 +575,13 @@ impl ConstData { #[derive(Debug, Clone, PartialEq, Eq)] pub struct StaticData { pub name: Name, - pub type_ref: Interned<TypeRef>, + pub type_ref: TypeRefId, pub visibility: RawVisibility, pub mutable: bool, pub is_extern: bool, pub has_safe_kw: bool, pub has_unsafe_kw: bool, + pub types_map: Arc<TypesMap>, } impl StaticData { @@ -583,12 +592,13 @@ impl StaticData { Arc::new(StaticData { name: statik.name.clone(), - type_ref: statik.type_ref.clone(), + type_ref: statik.type_ref, visibility: item_tree[statik.visibility].clone(), mutable: statik.mutable, is_extern: matches!(loc.container, ItemContainerId::ExternBlockId(_)), has_safe_kw: statik.has_safe_kw, has_unsafe_kw: statik.has_unsafe_kw, + types_map: statik.types_map.clone(), }) } } diff --git a/src/tools/rust-analyzer/crates/hir-def/src/data/adt.rs b/src/tools/rust-analyzer/crates/hir-def/src/data/adt.rs index ba54451e594..068ebb3b7e9 100644 --- a/src/tools/rust-analyzer/crates/hir-def/src/data/adt.rs +++ b/src/tools/rust-analyzer/crates/hir-def/src/data/adt.rs @@ -6,7 +6,7 @@ use cfg::CfgOptions; use either::Either; use hir_expand::name::Name; -use intern::{sym, Interned}; +use intern::sym; use la_arena::Arena; use rustc_abi::{Align, Integer, IntegerType, ReprFlags, ReprOptions}; use triomphe::Arc; @@ -21,7 +21,7 @@ use crate::{ lang_item::LangItem, nameres::diagnostics::{DefDiagnostic, DefDiagnostics}, tt::{Delimiter, DelimiterKind, Leaf, Subtree, TokenTree}, - type_ref::TypeRef, + type_ref::{TypeRefId, TypesMap}, visibility::RawVisibility, EnumId, EnumVariantId, LocalFieldId, LocalModuleId, Lookup, StructId, UnionId, VariantId, }; @@ -73,8 +73,8 @@ pub struct EnumVariantData { #[derive(Debug, Clone, PartialEq, Eq)] pub enum VariantData { - Record(Arena<FieldData>), - Tuple(Arena<FieldData>), + Record { fields: Arena<FieldData>, types_map: Arc<TypesMap> }, + Tuple { fields: Arena<FieldData>, types_map: Arc<TypesMap> }, Unit, } @@ -82,7 +82,7 @@ pub enum VariantData { #[derive(Debug, Clone, PartialEq, Eq)] pub struct FieldData { pub name: Name, - pub type_ref: Interned<TypeRef>, + pub type_ref: TypeRefId, pub visibility: RawVisibility, } @@ -208,7 +208,7 @@ impl StructData { } let strukt = &item_tree[loc.id.value]; - let (data, diagnostics) = lower_fields( + let (fields, diagnostics) = lower_fields( db, krate, loc.container.local_id, @@ -219,12 +219,13 @@ impl StructData { &strukt.fields, None, ); + let types_map = strukt.types_map.clone(); ( Arc::new(StructData { name: strukt.name.clone(), variant_data: Arc::new(match strukt.shape { - FieldsShape::Record => VariantData::Record(data), - FieldsShape::Tuple => VariantData::Tuple(data), + FieldsShape::Record => VariantData::Record { fields, types_map }, + FieldsShape::Tuple => VariantData::Tuple { fields, types_map }, FieldsShape::Unit => VariantData::Unit, }), repr, @@ -258,7 +259,7 @@ impl StructData { } let union = &item_tree[loc.id.value]; - let (data, diagnostics) = lower_fields( + let (fields, diagnostics) = lower_fields( db, krate, loc.container.local_id, @@ -269,10 +270,11 @@ impl StructData { &union.fields, None, ); + let types_map = union.types_map.clone(); ( Arc::new(StructData { name: union.name.clone(), - variant_data: Arc::new(VariantData::Record(data)), + variant_data: Arc::new(VariantData::Record { fields, types_map }), repr, visibility: item_tree[union.visibility].clone(), flags, @@ -360,7 +362,7 @@ impl EnumVariantData { let item_tree = loc.id.item_tree(db); let variant = &item_tree[loc.id.value]; - let (data, diagnostics) = lower_fields( + let (fields, diagnostics) = lower_fields( db, krate, container.local_id, @@ -371,13 +373,14 @@ impl EnumVariantData { &variant.fields, Some(item_tree[loc.parent.lookup(db).id.value].visibility), ); + let types_map = variant.types_map.clone(); ( Arc::new(EnumVariantData { name: variant.name.clone(), variant_data: Arc::new(match variant.shape { - FieldsShape::Record => VariantData::Record(data), - FieldsShape::Tuple => VariantData::Tuple(data), + FieldsShape::Record => VariantData::Record { fields, types_map }, + FieldsShape::Tuple => VariantData::Tuple { fields, types_map }, FieldsShape::Unit => VariantData::Unit, }), }), @@ -390,11 +393,20 @@ impl VariantData { pub fn fields(&self) -> &Arena<FieldData> { const EMPTY: &Arena<FieldData> = &Arena::new(); match &self { - VariantData::Record(fields) | VariantData::Tuple(fields) => fields, + VariantData::Record { fields, .. } | VariantData::Tuple { fields, .. } => fields, _ => EMPTY, } } + pub fn types_map(&self) -> &TypesMap { + match &self { + VariantData::Record { types_map, .. } | VariantData::Tuple { types_map, .. } => { + types_map + } + VariantData::Unit => TypesMap::EMPTY, + } + } + // FIXME: Linear lookup pub fn field(&self, name: &Name) -> Option<LocalFieldId> { self.fields().iter().find_map(|(id, data)| if &data.name == name { Some(id) } else { None }) @@ -402,8 +414,8 @@ impl VariantData { pub fn kind(&self) -> StructKind { match self { - VariantData::Record(_) => StructKind::Record, - VariantData::Tuple(_) => StructKind::Tuple, + VariantData::Record { .. } => StructKind::Record, + VariantData::Tuple { .. } => StructKind::Tuple, VariantData::Unit => StructKind::Unit, } } @@ -463,7 +475,7 @@ fn lower_field( ) -> FieldData { FieldData { name: field.name.clone(), - type_ref: field.type_ref.clone(), + type_ref: field.type_ref, visibility: item_tree[override_visibility.unwrap_or(field.visibility)].clone(), } } diff --git a/src/tools/rust-analyzer/crates/hir-def/src/db.rs b/src/tools/rust-analyzer/crates/hir-def/src/db.rs index aeda302f35c..d7e83ce33e8 100644 --- a/src/tools/rust-analyzer/crates/hir-def/src/db.rs +++ b/src/tools/rust-analyzer/crates/hir-def/src/db.rs @@ -2,7 +2,7 @@ use base_db::{ra_salsa, CrateId, SourceDatabase, Upcast}; use either::Either; use hir_expand::{db::ExpandDatabase, HirFileId, MacroDefId}; -use intern::{sym, Interned}; +use intern::sym; use la_arena::ArenaMap; use span::{EditionedFileId, MacroCallId}; use syntax::{ast, AstPtr}; @@ -18,9 +18,10 @@ use crate::{ }, generics::GenericParams, import_map::ImportMap, - item_tree::{AttrOwner, ItemTree}, + item_tree::{AttrOwner, ItemTree, ItemTreeSourceMaps}, lang_item::{self, LangItem, LangItemTarget, LangItems}, nameres::{diagnostics::DefDiagnostics, DefMap}, + type_ref::TypesSourceMap, visibility::{self, Visibility}, AttrDefId, BlockId, BlockLoc, ConstBlockId, ConstBlockLoc, ConstId, ConstLoc, DefWithBodyId, EnumId, EnumLoc, EnumVariantId, EnumVariantLoc, ExternBlockId, ExternBlockLoc, ExternCrateId, @@ -91,6 +92,18 @@ pub trait DefDatabase: InternDatabase + ExpandDatabase + Upcast<dyn ExpandDataba #[ra_salsa::invoke(ItemTree::block_item_tree_query)] fn block_item_tree(&self, block_id: BlockId) -> Arc<ItemTree>; + #[ra_salsa::invoke(ItemTree::file_item_tree_with_source_map_query)] + fn file_item_tree_with_source_map( + &self, + file_id: HirFileId, + ) -> (Arc<ItemTree>, Arc<ItemTreeSourceMaps>); + + #[ra_salsa::invoke(ItemTree::block_item_tree_with_source_map_query)] + fn block_item_tree_with_source_map( + &self, + block_id: BlockId, + ) -> (Arc<ItemTree>, Arc<ItemTreeSourceMaps>); + #[ra_salsa::invoke(DefMap::crate_def_map_query)] fn crate_def_map(&self, krate: CrateId) -> Arc<DefMap>; @@ -187,7 +200,14 @@ pub trait DefDatabase: InternDatabase + ExpandDatabase + Upcast<dyn ExpandDataba fn expr_scopes(&self, def: DefWithBodyId) -> Arc<ExprScopes>; #[ra_salsa::invoke(GenericParams::generic_params_query)] - fn generic_params(&self, def: GenericDefId) -> Interned<GenericParams>; + fn generic_params(&self, def: GenericDefId) -> Arc<GenericParams>; + + /// If this returns `None` for the source map, that means it is the same as with the item tree. + #[ra_salsa::invoke(GenericParams::generic_params_with_source_map_query)] + fn generic_params_with_source_map( + &self, + def: GenericDefId, + ) -> (Arc<GenericParams>, Option<Arc<TypesSourceMap>>); // region:attrs diff --git a/src/tools/rust-analyzer/crates/hir-def/src/expander.rs b/src/tools/rust-analyzer/crates/hir-def/src/expander.rs index 6d8b4445f75..d430733fcad 100644 --- a/src/tools/rust-analyzer/crates/hir-def/src/expander.rs +++ b/src/tools/rust-analyzer/crates/hir-def/src/expander.rs @@ -14,6 +14,7 @@ use span::SyntaxContextId; use syntax::{ast, Parse}; use triomphe::Arc; +use crate::type_ref::{TypesMap, TypesSourceMap}; use crate::{ attr::Attrs, db::DefDatabase, lower::LowerCtx, path::Path, AsMacroCall, MacroId, ModuleId, UnresolvedMacro, @@ -49,6 +50,10 @@ impl Expander { } } + pub(crate) fn span_map(&self, db: &dyn DefDatabase) -> &SpanMap { + self.span_map.get_or_init(|| db.span_map(self.current_file_id)) + } + pub fn krate(&self) -> CrateId { self.module.krate } @@ -110,8 +115,19 @@ impl Expander { mark.bomb.defuse(); } - pub fn ctx<'a>(&self, db: &'a dyn DefDatabase) -> LowerCtx<'a> { - LowerCtx::with_span_map_cell(db, self.current_file_id, self.span_map.clone()) + pub fn ctx<'a>( + &self, + db: &'a dyn DefDatabase, + types_map: &'a mut TypesMap, + types_source_map: &'a mut TypesSourceMap, + ) -> LowerCtx<'a> { + LowerCtx::with_span_map_cell( + db, + self.current_file_id, + self.span_map.clone(), + types_map, + types_source_map, + ) } pub(crate) fn in_file<T>(&self, value: T) -> InFile<T> { @@ -138,8 +154,20 @@ impl Expander { self.current_file_id } - pub(crate) fn parse_path(&mut self, db: &dyn DefDatabase, path: ast::Path) -> Option<Path> { - let ctx = LowerCtx::with_span_map_cell(db, self.current_file_id, self.span_map.clone()); + pub(crate) fn parse_path( + &mut self, + db: &dyn DefDatabase, + path: ast::Path, + types_map: &mut TypesMap, + types_source_map: &mut TypesSourceMap, + ) -> Option<Path> { + let ctx = LowerCtx::with_span_map_cell( + db, + self.current_file_id, + self.span_map.clone(), + types_map, + types_source_map, + ); Path::from_src(&ctx, path) } diff --git a/src/tools/rust-analyzer/crates/hir-def/src/find_path.rs b/src/tools/rust-analyzer/crates/hir-def/src/find_path.rs index f5e03e5281e..a615abd1bbe 100644 --- a/src/tools/rust-analyzer/crates/hir-def/src/find_path.rs +++ b/src/tools/rust-analyzer/crates/hir-def/src/find_path.rs @@ -1025,7 +1025,7 @@ pub mod ast { check_found_path( r#" mod bar { - mod foo { pub(super) struct S; } + mod foo { pub(crate) struct S; } pub(crate) use foo::*; } $0 @@ -1047,7 +1047,7 @@ $0 check_found_path( r#" mod bar { - mod foo { pub(super) struct S; } + mod foo { pub(crate) struct S; } pub(crate) use foo::S as U; } $0 diff --git a/src/tools/rust-analyzer/crates/hir-def/src/generics.rs b/src/tools/rust-analyzer/crates/hir-def/src/generics.rs index 6c34ee086aa..6b79850e9c4 100644 --- a/src/tools/rust-analyzer/crates/hir-def/src/generics.rs +++ b/src/tools/rust-analyzer/crates/hir-def/src/generics.rs @@ -3,16 +3,18 @@ //! generic parameters. See also the `Generics` type and the `generics_of` query //! in rustc. -use std::ops; +use std::{ops, sync::LazyLock}; use either::Either; use hir_expand::{ name::{AsName, Name}, ExpandResult, }; -use intern::Interned; use la_arena::{Arena, RawIdx}; -use stdx::impl_from; +use stdx::{ + impl_from, + thin_vec::{EmptyOptimizedThinVec, ThinVec}, +}; use syntax::ast::{self, HasGenericParams, HasName, HasTypeBounds}; use triomphe::Arc; @@ -22,7 +24,11 @@ use crate::{ item_tree::{AttrOwner, FileItemTreeId, GenericModItem, GenericsItemTreeNode, ItemTree}, lower::LowerCtx, nameres::{DefMap, MacroSubNs}, - type_ref::{ConstRef, LifetimeRef, TypeBound, TypeRef}, + path::{AssociatedTypeBinding, GenericArg, GenericArgs, NormalPath, Path}, + type_ref::{ + ArrayType, ConstRef, FnType, LifetimeRef, RefType, TypeBound, TypeRef, TypeRefId, TypesMap, + TypesSourceMap, + }, AdtId, ConstParamId, GenericDefId, HasModule, ItemTreeLoc, LifetimeParamId, LocalLifetimeParamId, LocalTypeOrConstParamId, Lookup, TypeOrConstParamId, TypeParamId, }; @@ -37,7 +43,7 @@ pub struct TypeParamData { /// [`None`] only if the type ref is an [`TypeRef::ImplTrait`]. FIXME: Might be better to just /// make it always be a value, giving impl trait a special name. pub name: Option<Name>, - pub default: Option<Interned<TypeRef>>, + pub default: Option<TypeRefId>, pub provenance: TypeParamProvenance, } @@ -51,7 +57,7 @@ pub struct LifetimeParamData { #[derive(Clone, PartialEq, Eq, Debug, Hash)] pub struct ConstParamData { pub name: Name, - pub ty: Interned<TypeRef>, + pub ty: TypeRefId, pub default: Option<ConstRef>, } @@ -161,6 +167,7 @@ pub struct GenericParams { type_or_consts: Arena<TypeOrConstParamData>, lifetimes: Arena<LifetimeParamData>, where_predicates: Box<[WherePredicate]>, + pub types_map: TypesMap, } impl ops::Index<LocalTypeOrConstParamId> for GenericParams { @@ -183,24 +190,14 @@ impl ops::Index<LocalLifetimeParamId> for GenericParams { /// associated type bindings like `Iterator<Item = u32>`. #[derive(Clone, PartialEq, Eq, Debug, Hash)] pub enum WherePredicate { - TypeBound { - target: WherePredicateTypeTarget, - bound: Interned<TypeBound>, - }, - Lifetime { - target: LifetimeRef, - bound: LifetimeRef, - }, - ForLifetime { - lifetimes: Box<[Name]>, - target: WherePredicateTypeTarget, - bound: Interned<TypeBound>, - }, + TypeBound { target: WherePredicateTypeTarget, bound: TypeBound }, + Lifetime { target: LifetimeRef, bound: LifetimeRef }, + ForLifetime { lifetimes: Box<[Name]>, target: WherePredicateTypeTarget, bound: TypeBound }, } #[derive(Clone, PartialEq, Eq, Debug, Hash)] pub enum WherePredicateTypeTarget { - TypeRef(Interned<TypeRef>), + TypeRef(TypeRefId), /// For desugared where predicates that can directly refer to a type param. TypeOrConstParam(LocalTypeOrConstParamId), } @@ -300,7 +297,14 @@ impl GenericParams { pub(crate) fn generic_params_query( db: &dyn DefDatabase, def: GenericDefId, - ) -> Interned<GenericParams> { + ) -> Arc<GenericParams> { + db.generic_params_with_source_map(def).0 + } + + pub(crate) fn generic_params_with_source_map_query( + db: &dyn DefDatabase, + def: GenericDefId, + ) -> (Arc<GenericParams>, Option<Arc<TypesSourceMap>>) { let _p = tracing::info_span!("generic_params_query").entered(); let krate = def.krate(db); @@ -309,7 +313,7 @@ impl GenericParams { // Returns the generic parameters that are enabled under the current `#[cfg]` options let enabled_params = - |params: &Interned<GenericParams>, item_tree: &ItemTree, parent: GenericModItem| { + |params: &Arc<GenericParams>, item_tree: &ItemTree, parent: GenericModItem| { let enabled = |param| item_tree.attrs(db, krate, param).is_cfg_enabled(cfg_options); let attr_owner_ct = |param| AttrOwner::TypeOrConstParamData(parent, param); let attr_owner_lt = |param| AttrOwner::LifetimeParamData(parent, param); @@ -325,7 +329,7 @@ impl GenericParams { if all_type_or_consts_enabled && all_lifetimes_enabled { params.clone() } else { - Interned::new(GenericParams { + Arc::new(GenericParams { type_or_consts: all_type_or_consts_enabled .then(|| params.type_or_consts.clone()) .unwrap_or_else(|| { @@ -347,6 +351,7 @@ impl GenericParams { .collect() }), where_predicates: params.where_predicates.clone(), + types_map: params.types_map.clone(), }) } }; @@ -357,18 +362,18 @@ impl GenericParams { Data = impl ItemTreeLoc<Id = Id>, >, enabled_params: impl Fn( - &Interned<GenericParams>, + &Arc<GenericParams>, &ItemTree, GenericModItem, - ) -> Interned<GenericParams>, - ) -> Interned<GenericParams> + ) -> Arc<GenericParams>, + ) -> (Arc<GenericParams>, Option<Arc<TypesSourceMap>>) where FileItemTreeId<Id>: Into<GenericModItem>, { let id = id.lookup(db).item_tree_id(); let tree = id.item_tree(db); let item = &tree[id.value]; - enabled_params(item.generic_params(), &tree, id.value.into()) + (enabled_params(item.generic_params(), &tree, id.value.into()), None) } match def { @@ -383,28 +388,37 @@ impl GenericParams { let module = loc.container.module(db); let func_data = db.function_data(id); if func_data.params.is_empty() { - enabled_params + (enabled_params, None) } else { + let source_maps = loc.id.item_tree_with_source_map(db).1; + let item_source_maps = source_maps.function(loc.id.value); let mut generic_params = GenericParamsCollector { type_or_consts: enabled_params.type_or_consts.clone(), lifetimes: enabled_params.lifetimes.clone(), where_predicates: enabled_params.where_predicates.clone().into(), }; + let (mut types_map, mut types_source_maps) = + (enabled_params.types_map.clone(), item_source_maps.generics().clone()); // Don't create an `Expander` if not needed since this // could cause a reparse after the `ItemTree` has been created due to the spanmap. let mut expander = None; - for param in func_data.params.iter() { + for ¶m in func_data.params.iter() { generic_params.fill_implicit_impl_trait_args( db, + &mut types_map, + &mut types_source_maps, &mut expander, &mut || { (module.def_map(db), Expander::new(db, loc.id.file_id(), module)) }, param, + &item.types_map, + item_source_maps.item(), ); } - Interned::new(generic_params.finish()) + let generics = generic_params.finish(types_map, &mut types_source_maps); + (generics, Some(Arc::new(types_source_maps))) } } GenericDefId::AdtId(AdtId::StructId(id)) => id_to_generics(db, id, enabled_params), @@ -414,11 +428,15 @@ impl GenericParams { GenericDefId::TraitAliasId(id) => id_to_generics(db, id, enabled_params), GenericDefId::TypeAliasId(id) => id_to_generics(db, id, enabled_params), GenericDefId::ImplId(id) => id_to_generics(db, id, enabled_params), - GenericDefId::ConstId(_) => Interned::new(GenericParams { - type_or_consts: Default::default(), - lifetimes: Default::default(), - where_predicates: Default::default(), - }), + GenericDefId::ConstId(_) => ( + Arc::new(GenericParams { + type_or_consts: Default::default(), + lifetimes: Default::default(), + where_predicates: Default::default(), + types_map: Default::default(), + }), + None, + ), } } } @@ -452,7 +470,7 @@ impl GenericParamsCollector { &mut self, lower_ctx: &LowerCtx<'_>, type_bounds: Option<ast::TypeBoundList>, - target: Either<TypeRef, LifetimeRef>, + target: Either<TypeRefId, LifetimeRef>, ) { for bound in type_bounds.iter().flat_map(|type_bound_list| type_bound_list.bounds()) { self.add_where_predicate_from_bound(lower_ctx, bound, None, target.clone()); @@ -473,16 +491,15 @@ impl GenericParamsCollector { ast::TypeOrConstParam::Type(type_param) => { let name = type_param.name().map_or_else(Name::missing, |it| it.as_name()); // FIXME: Use `Path::from_src` - let default = type_param - .default_type() - .map(|it| Interned::new(TypeRef::from_ast(lower_ctx, it))); + let default = + type_param.default_type().map(|it| TypeRef::from_ast(lower_ctx, it)); let param = TypeParamData { name: Some(name.clone()), default, provenance: TypeParamProvenance::TypeParamList, }; let idx = self.type_or_consts.alloc(param.into()); - let type_ref = TypeRef::Path(name.into()); + let type_ref = lower_ctx.alloc_type_ref_desugared(TypeRef::Path(name.into())); self.fill_bounds( lower_ctx, type_param.type_bound_list(), @@ -492,12 +509,10 @@ impl GenericParamsCollector { } ast::TypeOrConstParam::Const(const_param) => { let name = const_param.name().map_or_else(Name::missing, |it| it.as_name()); - let ty = const_param - .ty() - .map_or(TypeRef::Error, |it| TypeRef::from_ast(lower_ctx, it)); + let ty = TypeRef::from_ast_opt(lower_ctx, const_param.ty()); let param = ConstParamData { name, - ty: Interned::new(ty), + ty, default: ConstRef::from_const_param(lower_ctx, &const_param), }; let idx = self.type_or_consts.alloc(param.into()); @@ -557,7 +572,7 @@ impl GenericParamsCollector { lower_ctx: &LowerCtx<'_>, bound: ast::TypeBound, hrtb_lifetimes: Option<&[Name]>, - target: Either<TypeRef, LifetimeRef>, + target: Either<TypeRefId, LifetimeRef>, ) { let bound = TypeBound::from_ast(lower_ctx, bound); self.fill_impl_trait_bounds(lower_ctx.take_impl_traits_bounds()); @@ -565,12 +580,12 @@ impl GenericParamsCollector { (Either::Left(type_ref), bound) => match hrtb_lifetimes { Some(hrtb_lifetimes) => WherePredicate::ForLifetime { lifetimes: hrtb_lifetimes.to_vec().into_boxed_slice(), - target: WherePredicateTypeTarget::TypeRef(Interned::new(type_ref)), - bound: Interned::new(bound), + target: WherePredicateTypeTarget::TypeRef(type_ref), + bound, }, None => WherePredicate::TypeBound { - target: WherePredicateTypeTarget::TypeRef(Interned::new(type_ref)), - bound: Interned::new(bound), + target: WherePredicateTypeTarget::TypeRef(type_ref), + bound, }, }, (Either::Right(lifetime), TypeBound::Lifetime(bound)) => { @@ -581,7 +596,7 @@ impl GenericParamsCollector { self.where_predicates.push(predicate); } - fn fill_impl_trait_bounds(&mut self, impl_bounds: Vec<Vec<Interned<TypeBound>>>) { + fn fill_impl_trait_bounds(&mut self, impl_bounds: Vec<ThinVec<TypeBound>>) { for bounds in impl_bounds { let param = TypeParamData { name: None, @@ -589,10 +604,10 @@ impl GenericParamsCollector { provenance: TypeParamProvenance::ArgumentImplTrait, }; let param_id = self.type_or_consts.alloc(param.into()); - for bound in bounds { + for bound in &bounds { self.where_predicates.push(WherePredicate::TypeBound { target: WherePredicateTypeTarget::TypeOrConstParam(param_id), - bound, + bound: bound.clone(), }); } } @@ -601,12 +616,16 @@ impl GenericParamsCollector { fn fill_implicit_impl_trait_args( &mut self, db: &dyn DefDatabase, + generics_types_map: &mut TypesMap, + generics_types_source_map: &mut TypesSourceMap, // FIXME: Change this back to `LazyCell` if https://github.com/rust-lang/libs-team/issues/429 is accepted. exp: &mut Option<(Arc<DefMap>, Expander)>, exp_fill: &mut dyn FnMut() -> (Arc<DefMap>, Expander), - type_ref: &TypeRef, + type_ref: TypeRefId, + types_map: &TypesMap, + types_source_map: &TypesSourceMap, ) { - type_ref.walk(&mut |type_ref| { + TypeRef::walk(type_ref, types_map, &mut |type_ref| { if let TypeRef::ImplTrait(bounds) = type_ref { let param = TypeParamData { name: None, @@ -615,12 +634,20 @@ impl GenericParamsCollector { }; let param_id = self.type_or_consts.alloc(param.into()); for bound in bounds { + let bound = copy_type_bound( + bound, + types_map, + types_source_map, + generics_types_map, + generics_types_source_map, + ); self.where_predicates.push(WherePredicate::TypeBound { target: WherePredicateTypeTarget::TypeOrConstParam(param_id), - bound: bound.clone(), + bound, }); } } + if let TypeRef::Macro(mc) = type_ref { let macro_call = mc.to_node(db.upcast()); let (def_map, expander) = exp.get_or_insert_with(&mut *exp_fill); @@ -641,23 +668,217 @@ impl GenericParamsCollector { if let Ok(ExpandResult { value: Some((mark, expanded)), .. }) = expander.enter_expand(db, macro_call, resolver) { - let ctx = expander.ctx(db); + let (mut macro_types_map, mut macro_types_source_map) = + (TypesMap::default(), TypesSourceMap::default()); + let ctx = expander.ctx(db, &mut macro_types_map, &mut macro_types_source_map); let type_ref = TypeRef::from_ast(&ctx, expanded.tree()); - self.fill_implicit_impl_trait_args(db, &mut *exp, exp_fill, &type_ref); + self.fill_implicit_impl_trait_args( + db, + generics_types_map, + generics_types_source_map, + &mut *exp, + exp_fill, + type_ref, + ¯o_types_map, + ¯o_types_source_map, + ); exp.get_or_insert_with(&mut *exp_fill).1.exit(mark); } } }); } - pub(crate) fn finish(self) -> GenericParams { - let Self { mut lifetimes, mut type_or_consts, where_predicates } = self; + pub(crate) fn finish( + self, + mut generics_types_map: TypesMap, + generics_types_source_map: &mut TypesSourceMap, + ) -> Arc<GenericParams> { + let Self { mut lifetimes, mut type_or_consts, mut where_predicates } = self; + + if lifetimes.is_empty() && type_or_consts.is_empty() && where_predicates.is_empty() { + static EMPTY: LazyLock<Arc<GenericParams>> = LazyLock::new(|| { + Arc::new(GenericParams { + lifetimes: Arena::new(), + type_or_consts: Arena::new(), + where_predicates: Box::default(), + types_map: TypesMap::default(), + }) + }); + return Arc::clone(&EMPTY); + } + lifetimes.shrink_to_fit(); type_or_consts.shrink_to_fit(); - GenericParams { + where_predicates.shrink_to_fit(); + generics_types_map.shrink_to_fit(); + generics_types_source_map.shrink_to_fit(); + Arc::new(GenericParams { type_or_consts, lifetimes, where_predicates: where_predicates.into_boxed_slice(), + types_map: generics_types_map, + }) + } +} + +/// Copies a `TypeRef` from a `TypesMap` (accompanied with `TypesSourceMap`) into another `TypesMap` +/// (and `TypesSourceMap`). +fn copy_type_ref( + type_ref: TypeRefId, + from: &TypesMap, + from_source_map: &TypesSourceMap, + to: &mut TypesMap, + to_source_map: &mut TypesSourceMap, +) -> TypeRefId { + let result = match &from[type_ref] { + TypeRef::Fn(fn_) => { + let params = fn_.params().iter().map(|(name, param_type)| { + (name.clone(), copy_type_ref(*param_type, from, from_source_map, to, to_source_map)) + }); + TypeRef::Fn(FnType::new(fn_.is_varargs(), fn_.is_unsafe(), fn_.abi().clone(), params)) } + TypeRef::Tuple(types) => TypeRef::Tuple(EmptyOptimizedThinVec::from_iter( + types.iter().map(|&t| copy_type_ref(t, from, from_source_map, to, to_source_map)), + )), + &TypeRef::RawPtr(type_ref, mutbl) => TypeRef::RawPtr( + copy_type_ref(type_ref, from, from_source_map, to, to_source_map), + mutbl, + ), + TypeRef::Reference(ref_) => TypeRef::Reference(Box::new(RefType { + ty: copy_type_ref(ref_.ty, from, from_source_map, to, to_source_map), + lifetime: ref_.lifetime.clone(), + mutability: ref_.mutability, + })), + TypeRef::Array(array) => TypeRef::Array(Box::new(ArrayType { + ty: copy_type_ref(array.ty, from, from_source_map, to, to_source_map), + len: array.len.clone(), + })), + &TypeRef::Slice(type_ref) => { + TypeRef::Slice(copy_type_ref(type_ref, from, from_source_map, to, to_source_map)) + } + TypeRef::ImplTrait(bounds) => TypeRef::ImplTrait(ThinVec::from_iter(copy_type_bounds( + bounds, + from, + from_source_map, + to, + to_source_map, + ))), + TypeRef::DynTrait(bounds) => TypeRef::DynTrait(ThinVec::from_iter(copy_type_bounds( + bounds, + from, + from_source_map, + to, + to_source_map, + ))), + TypeRef::Path(path) => { + TypeRef::Path(copy_path(path, from, from_source_map, to, to_source_map)) + } + TypeRef::Never => TypeRef::Never, + TypeRef::Placeholder => TypeRef::Placeholder, + TypeRef::Macro(macro_call) => TypeRef::Macro(*macro_call), + TypeRef::Error => TypeRef::Error, + }; + let id = to.types.alloc(result); + if let Some(&ptr) = from_source_map.types_map_back.get(id) { + to_source_map.types_map_back.insert(id, ptr); + } + id +} + +fn copy_path( + path: &Path, + from: &TypesMap, + from_source_map: &TypesSourceMap, + to: &mut TypesMap, + to_source_map: &mut TypesSourceMap, +) -> Path { + match path { + Path::BarePath(mod_path) => Path::BarePath(mod_path.clone()), + Path::Normal(path) => { + let type_anchor = path + .type_anchor() + .map(|type_ref| copy_type_ref(type_ref, from, from_source_map, to, to_source_map)); + let mod_path = path.mod_path().clone(); + let generic_args = path.generic_args().iter().map(|generic_args| { + copy_generic_args(generic_args, from, from_source_map, to, to_source_map) + }); + Path::Normal(NormalPath::new(type_anchor, mod_path, generic_args)) + } + Path::LangItem(lang_item, name) => Path::LangItem(*lang_item, name.clone()), + } +} + +fn copy_generic_args( + generic_args: &Option<GenericArgs>, + from: &TypesMap, + from_source_map: &TypesSourceMap, + to: &mut TypesMap, + to_source_map: &mut TypesSourceMap, +) -> Option<GenericArgs> { + generic_args.as_ref().map(|generic_args| { + let args = generic_args + .args + .iter() + .map(|arg| match arg { + &GenericArg::Type(ty) => { + GenericArg::Type(copy_type_ref(ty, from, from_source_map, to, to_source_map)) + } + GenericArg::Lifetime(lifetime) => GenericArg::Lifetime(lifetime.clone()), + GenericArg::Const(konst) => GenericArg::Const(konst.clone()), + }) + .collect(); + let bindings = generic_args + .bindings + .iter() + .map(|binding| { + let name = binding.name.clone(); + let args = + copy_generic_args(&binding.args, from, from_source_map, to, to_source_map); + let type_ref = binding.type_ref.map(|type_ref| { + copy_type_ref(type_ref, from, from_source_map, to, to_source_map) + }); + let bounds = + copy_type_bounds(&binding.bounds, from, from_source_map, to, to_source_map) + .collect(); + AssociatedTypeBinding { name, args, type_ref, bounds } + }) + .collect(); + GenericArgs { + args, + has_self_type: generic_args.has_self_type, + bindings, + desugared_from_fn: generic_args.desugared_from_fn, + } + }) +} + +fn copy_type_bounds<'a>( + bounds: &'a [TypeBound], + from: &'a TypesMap, + from_source_map: &'a TypesSourceMap, + to: &'a mut TypesMap, + to_source_map: &'a mut TypesSourceMap, +) -> impl stdx::thin_vec::TrustedLen<Item = TypeBound> + 'a { + bounds.iter().map(|bound| copy_type_bound(bound, from, from_source_map, to, to_source_map)) +} + +fn copy_type_bound( + bound: &TypeBound, + from: &TypesMap, + from_source_map: &TypesSourceMap, + to: &mut TypesMap, + to_source_map: &mut TypesSourceMap, +) -> TypeBound { + match bound { + TypeBound::Path(path, modifier) => { + TypeBound::Path(copy_path(path, from, from_source_map, to, to_source_map), *modifier) + } + TypeBound::ForLifetime(lifetimes, path) => TypeBound::ForLifetime( + lifetimes.clone(), + copy_path(path, from, from_source_map, to, to_source_map), + ), + TypeBound::Lifetime(lifetime) => TypeBound::Lifetime(lifetime.clone()), + TypeBound::Use(use_args) => TypeBound::Use(use_args.clone()), + TypeBound::Error => TypeBound::Error, } } diff --git a/src/tools/rust-analyzer/crates/hir-def/src/hir.rs b/src/tools/rust-analyzer/crates/hir-def/src/hir.rs index d9358a28822..85963469430 100644 --- a/src/tools/rust-analyzer/crates/hir-def/src/hir.rs +++ b/src/tools/rust-analyzer/crates/hir-def/src/hir.rs @@ -17,16 +17,17 @@ pub mod type_ref; use std::fmt; -use hir_expand::name::Name; -use intern::{Interned, Symbol}; +use hir_expand::{name::Name, MacroDefId}; +use intern::Symbol; use la_arena::{Idx, RawIdx}; use rustc_apfloat::ieee::{Half as f16, Quad as f128}; use syntax::ast; +use type_ref::TypeRefId; use crate::{ builtin_type::{BuiltinFloat, BuiltinInt, BuiltinUint}, path::{GenericArgs, Path}, - type_ref::{Mutability, Rawness, TypeRef}, + type_ref::{Mutability, Rawness}, BlockId, ConstBlockId, }; @@ -48,6 +49,22 @@ pub enum ExprOrPatId { ExprId(ExprId), PatId(PatId), } + +impl ExprOrPatId { + pub fn as_expr(self) -> Option<ExprId> { + match self { + Self::ExprId(v) => Some(v), + _ => None, + } + } + + pub fn as_pat(self) -> Option<PatId> { + match self { + Self::PatId(v) => Some(v), + _ => None, + } + } +} stdx::impl_from!(ExprId, PatId for ExprOrPatId); #[derive(Debug, Clone, Eq, PartialEq)] @@ -204,7 +221,6 @@ pub enum Expr { Call { callee: ExprId, args: Box<[ExprId]>, - is_assignee_expr: bool, }, MethodCall { receiver: ExprId, @@ -239,8 +255,6 @@ pub enum Expr { path: Option<Box<Path>>, fields: Box<[RecordLitField]>, spread: Option<ExprId>, - ellipsis: bool, - is_assignee_expr: bool, }, Field { expr: ExprId, @@ -251,7 +265,7 @@ pub enum Expr { }, Cast { expr: ExprId, - type_ref: Interned<TypeRef>, + type_ref: TypeRefId, }, Ref { expr: ExprId, @@ -265,11 +279,17 @@ pub enum Expr { expr: ExprId, op: UnaryOp, }, + /// `op` cannot be bare `=` (but can be `op=`), these are lowered to `Assignment` instead. BinaryOp { lhs: ExprId, rhs: ExprId, op: Option<BinaryOp>, }, + // Assignments need a special treatment because of destructuring assignment. + Assignment { + target: PatId, + value: ExprId, + }, Range { lhs: Option<ExprId>, rhs: Option<ExprId>, @@ -278,19 +298,17 @@ pub enum Expr { Index { base: ExprId, index: ExprId, - is_assignee_expr: bool, }, Closure { args: Box<[PatId]>, - arg_types: Box<[Option<Interned<TypeRef>>]>, - ret_type: Option<Interned<TypeRef>>, + arg_types: Box<[Option<TypeRefId>]>, + ret_type: Option<TypeRefId>, body: ExprId, closure_kind: ClosureKind, capture_by: CaptureBy, }, Tuple { exprs: Box<[ExprId]>, - is_assignee_expr: bool, }, Array(Array), Literal(Literal), @@ -301,7 +319,7 @@ pub enum Expr { #[derive(Debug, Clone, PartialEq, Eq)] pub struct OffsetOf { - pub container: Interned<TypeRef>, + pub container: TypeRefId, pub fields: Box<[Name]>, } @@ -446,7 +464,7 @@ pub enum Movability { #[derive(Debug, Clone, Eq, PartialEq)] pub enum Array { - ElementList { elements: Box<[ExprId]>, is_assignee_expr: bool }, + ElementList { elements: Box<[ExprId]> }, Repeat { initializer: ExprId, repeat: ExprId }, } @@ -467,7 +485,7 @@ pub struct RecordLitField { pub enum Statement { Let { pat: PatId, - type_ref: Option<Interned<TypeRef>>, + type_ref: Option<TypeRefId>, initializer: Option<ExprId>, else_branch: Option<ExprId>, }, @@ -475,133 +493,13 @@ pub enum Statement { expr: ExprId, has_semi: bool, }, - // At the moment, we only use this to figure out if a return expression - // is really the last statement of a block. See #16566 - Item, + Item(Item), } -impl Expr { - pub fn walk_child_exprs(&self, mut f: impl FnMut(ExprId)) { - match self { - Expr::Missing => {} - Expr::Path(_) | Expr::OffsetOf(_) => {} - Expr::InlineAsm(it) => it.operands.iter().for_each(|(_, op)| match op { - AsmOperand::In { expr, .. } - | AsmOperand::Out { expr: Some(expr), .. } - | AsmOperand::InOut { expr, .. } => f(*expr), - AsmOperand::SplitInOut { in_expr, out_expr, .. } => { - f(*in_expr); - if let Some(out_expr) = out_expr { - f(*out_expr); - } - } - AsmOperand::Out { expr: None, .. } - | AsmOperand::Const(_) - | AsmOperand::Label(_) - | AsmOperand::Sym(_) => (), - }), - Expr::If { condition, then_branch, else_branch } => { - f(*condition); - f(*then_branch); - if let &Some(else_branch) = else_branch { - f(else_branch); - } - } - Expr::Let { expr, .. } => { - f(*expr); - } - Expr::Const(_) => (), - Expr::Block { statements, tail, .. } - | Expr::Unsafe { statements, tail, .. } - | Expr::Async { statements, tail, .. } => { - for stmt in statements.iter() { - match stmt { - Statement::Let { initializer, else_branch, .. } => { - if let &Some(expr) = initializer { - f(expr); - } - if let &Some(expr) = else_branch { - f(expr); - } - } - Statement::Expr { expr: expression, .. } => f(*expression), - Statement::Item => (), - } - } - if let &Some(expr) = tail { - f(expr); - } - } - Expr::Loop { body, .. } => f(*body), - Expr::Call { callee, args, .. } => { - f(*callee); - args.iter().copied().for_each(f); - } - Expr::MethodCall { receiver, args, .. } => { - f(*receiver); - args.iter().copied().for_each(f); - } - Expr::Match { expr, arms } => { - f(*expr); - arms.iter().map(|arm| arm.expr).for_each(f); - } - Expr::Continue { .. } => {} - Expr::Break { expr, .. } - | Expr::Return { expr } - | Expr::Yield { expr } - | Expr::Yeet { expr } => { - if let &Some(expr) = expr { - f(expr); - } - } - Expr::Become { expr } => f(*expr), - Expr::RecordLit { fields, spread, .. } => { - for field in fields.iter() { - f(field.expr); - } - if let &Some(expr) = spread { - f(expr); - } - } - Expr::Closure { body, .. } => { - f(*body); - } - Expr::BinaryOp { lhs, rhs, .. } => { - f(*lhs); - f(*rhs); - } - Expr::Range { lhs, rhs, .. } => { - if let &Some(lhs) = rhs { - f(lhs); - } - if let &Some(rhs) = lhs { - f(rhs); - } - } - Expr::Index { base, index, .. } => { - f(*base); - f(*index); - } - Expr::Field { expr, .. } - | Expr::Await { expr } - | Expr::Cast { expr, .. } - | Expr::Ref { expr, .. } - | Expr::UnaryOp { expr, .. } - | Expr::Box { expr } => { - f(*expr); - } - Expr::Tuple { exprs, .. } => exprs.iter().copied().for_each(f), - Expr::Array(a) => match a { - Array::ElementList { elements, .. } => elements.iter().copied().for_each(f), - Array::Repeat { initializer, repeat } => { - f(*initializer); - f(*repeat) - } - }, - Expr::Literal(_) => {} - Expr::Underscore => {} - } - } +#[derive(Debug, Clone, PartialEq, Eq)] +pub enum Item { + MacroDef(Box<MacroDefId>), + Other, } /// Explicit binding annotations given in the HIR for a binding. Note @@ -665,18 +563,49 @@ pub struct RecordFieldPat { pub enum Pat { Missing, Wild, - Tuple { args: Box<[PatId]>, ellipsis: Option<u32> }, + Tuple { + args: Box<[PatId]>, + ellipsis: Option<u32>, + }, Or(Box<[PatId]>), - Record { path: Option<Box<Path>>, args: Box<[RecordFieldPat]>, ellipsis: bool }, - Range { start: Option<Box<LiteralOrConst>>, end: Option<Box<LiteralOrConst>> }, - Slice { prefix: Box<[PatId]>, slice: Option<PatId>, suffix: Box<[PatId]> }, - Path(Box<Path>), + Record { + path: Option<Box<Path>>, + args: Box<[RecordFieldPat]>, + ellipsis: bool, + }, + Range { + start: Option<Box<LiteralOrConst>>, + end: Option<Box<LiteralOrConst>>, + }, + Slice { + prefix: Box<[PatId]>, + slice: Option<PatId>, + suffix: Box<[PatId]>, + }, + /// This might refer to a variable if a single segment path (specifically, on destructuring assignment). + Path(Path), Lit(ExprId), - Bind { id: BindingId, subpat: Option<PatId> }, - TupleStruct { path: Option<Box<Path>>, args: Box<[PatId]>, ellipsis: Option<u32> }, - Ref { pat: PatId, mutability: Mutability }, - Box { inner: PatId }, + Bind { + id: BindingId, + subpat: Option<PatId>, + }, + TupleStruct { + path: Option<Box<Path>>, + args: Box<[PatId]>, + ellipsis: Option<u32>, + }, + Ref { + pat: PatId, + mutability: Mutability, + }, + Box { + inner: PatId, + }, ConstBlock(ExprId), + /// An expression inside a pattern. That can only occur inside assignments. + /// + /// E.g. in `(a, *b) = (1, &mut 2)`, `*b` is an expression. + Expr(ExprId), } impl Pat { @@ -687,7 +616,8 @@ impl Pat { | Pat::Path(..) | Pat::ConstBlock(..) | Pat::Wild - | Pat::Missing => {} + | Pat::Missing + | Pat::Expr(_) => {} Pat::Bind { subpat, .. } => { subpat.iter().copied().for_each(f); } diff --git a/src/tools/rust-analyzer/crates/hir-def/src/hir/type_ref.rs b/src/tools/rust-analyzer/crates/hir-def/src/hir/type_ref.rs index b74cd90f693..2582340c0f8 100644 --- a/src/tools/rust-analyzer/crates/hir-def/src/hir/type_ref.rs +++ b/src/tools/rust-analyzer/crates/hir-def/src/hir/type_ref.rs @@ -2,22 +2,27 @@ //! be directly created from an ast::TypeRef, without further queries. use core::fmt; -use std::fmt::Write; +use std::{fmt::Write, ops::Index}; use hir_expand::{ db::ExpandDatabase, name::{AsName, Name}, - AstId, + AstId, InFile, }; -use intern::{sym, Interned, Symbol}; +use intern::{sym, Symbol}; +use la_arena::{Arena, ArenaMap, Idx}; use span::Edition; -use syntax::ast::{self, HasGenericArgs, HasName, IsString}; +use stdx::thin_vec::{thin_vec_with_header_struct, EmptyOptimizedThinVec, ThinVec}; +use syntax::{ + ast::{self, HasGenericArgs, HasName, IsString}, + AstPtr, +}; use crate::{ builtin_type::{BuiltinInt, BuiltinType, BuiltinUint}, hir::Literal, lower::LowerCtx, - path::Path, + path::{GenericArg, Path}, }; #[derive(Copy, Clone, PartialEq, Eq, Hash, Debug)] @@ -104,35 +109,90 @@ impl TraitRef { } } +thin_vec_with_header_struct! { + pub new(pub(crate)) struct FnType, FnTypeHeader { + pub params: [(Option<Name>, TypeRefId)], + pub is_varargs: bool, + pub is_unsafe: bool, + pub abi: Option<Symbol>; ref, + } +} + +#[derive(Clone, PartialEq, Eq, Hash, Debug)] +pub struct ArrayType { + pub ty: TypeRefId, + // FIXME: This should be Ast<ConstArg> + pub len: ConstRef, +} + +#[derive(Clone, PartialEq, Eq, Hash, Debug)] +pub struct RefType { + pub ty: TypeRefId, + pub lifetime: Option<LifetimeRef>, + pub mutability: Mutability, +} + /// Compare ty::Ty -/// -/// Note: Most users of `TypeRef` that end up in the salsa database intern it using -/// `Interned<TypeRef>` to save space. But notably, nested `TypeRef`s are not interned, since that -/// does not seem to save any noticeable amount of memory. #[derive(Clone, PartialEq, Eq, Hash, Debug)] pub enum TypeRef { Never, Placeholder, - Tuple(Vec<TypeRef>), + Tuple(EmptyOptimizedThinVec<TypeRefId>), Path(Path), - RawPtr(Box<TypeRef>, Mutability), - Reference(Box<TypeRef>, Option<LifetimeRef>, Mutability), - // FIXME: This should be Array(Box<TypeRef>, Ast<ConstArg>), - Array(Box<TypeRef>, ConstRef), - Slice(Box<TypeRef>), + RawPtr(TypeRefId, Mutability), + Reference(Box<RefType>), + Array(Box<ArrayType>), + Slice(TypeRefId), /// A fn pointer. Last element of the vector is the return type. - Fn( - Box<[(Option<Name>, TypeRef)]>, - bool, /*varargs*/ - bool, /*is_unsafe*/ - Option<Symbol>, /* abi */ - ), - ImplTrait(Vec<Interned<TypeBound>>), - DynTrait(Vec<Interned<TypeBound>>), + Fn(FnType), + ImplTrait(ThinVec<TypeBound>), + DynTrait(ThinVec<TypeBound>), Macro(AstId<ast::MacroCall>), Error, } +#[cfg(target_arch = "x86_64")] +const _: () = assert!(size_of::<TypeRef>() == 16); + +pub type TypeRefId = Idx<TypeRef>; + +#[derive(Default, Clone, PartialEq, Eq, Debug, Hash)] +pub struct TypesMap { + pub(crate) types: Arena<TypeRef>, +} + +impl TypesMap { + pub const EMPTY: &TypesMap = &TypesMap { types: Arena::new() }; + + pub(crate) fn shrink_to_fit(&mut self) { + let TypesMap { types } = self; + types.shrink_to_fit(); + } +} + +impl Index<TypeRefId> for TypesMap { + type Output = TypeRef; + + fn index(&self, index: TypeRefId) -> &Self::Output { + &self.types[index] + } +} + +pub type TypePtr = AstPtr<ast::Type>; +pub type TypeSource = InFile<TypePtr>; + +#[derive(Default, Clone, PartialEq, Eq, Debug, Hash)] +pub struct TypesSourceMap { + pub(crate) types_map_back: ArenaMap<TypeRefId, TypeSource>, +} + +impl TypesSourceMap { + pub(crate) fn shrink_to_fit(&mut self) { + let TypesSourceMap { types_map_back } = self; + types_map_back.shrink_to_fit(); + } +} + #[derive(Clone, PartialEq, Eq, Hash, Debug)] pub struct LifetimeRef { pub name: Name, @@ -157,12 +217,22 @@ pub enum TypeBound { Path(Path, TraitBoundModifier), ForLifetime(Box<[Name]>, Path), Lifetime(LifetimeRef), + Use(Box<[UseArgRef]>), Error, } +#[cfg(target_pointer_width = "64")] +const _: [(); 32] = [(); ::std::mem::size_of::<TypeBound>()]; + +#[derive(Clone, PartialEq, Eq, Hash, Debug)] +pub enum UseArgRef { + Name(Name), + Lifetime(LifetimeRef), +} + /// A modifier on a bound, currently this is only used for `?Sized`, where the /// modifier is `Maybe`. -#[derive(Clone, PartialEq, Eq, Hash, Debug)] +#[derive(Clone, Copy, PartialEq, Eq, Hash, Debug)] pub enum TraitBoundModifier { None, Maybe, @@ -170,12 +240,12 @@ pub enum TraitBoundModifier { impl TypeRef { /// Converts an `ast::TypeRef` to a `hir::TypeRef`. - pub fn from_ast(ctx: &LowerCtx<'_>, node: ast::Type) -> Self { - match node { - ast::Type::ParenType(inner) => TypeRef::from_ast_opt(ctx, inner.ty()), - ast::Type::TupleType(inner) => { - TypeRef::Tuple(inner.fields().map(|it| TypeRef::from_ast(ctx, it)).collect()) - } + pub fn from_ast(ctx: &LowerCtx<'_>, node: ast::Type) -> TypeRefId { + let ty = match &node { + ast::Type::ParenType(inner) => return TypeRef::from_ast_opt(ctx, inner.ty()), + ast::Type::TupleType(inner) => TypeRef::Tuple(EmptyOptimizedThinVec::from_iter( + Vec::from_iter(inner.fields().map(|it| TypeRef::from_ast(ctx, it))), + )), ast::Type::NeverType(..) => TypeRef::Never, ast::Type::PathType(inner) => { // FIXME: Use `Path::from_src` @@ -188,20 +258,21 @@ impl TypeRef { ast::Type::PtrType(inner) => { let inner_ty = TypeRef::from_ast_opt(ctx, inner.ty()); let mutability = Mutability::from_mutable(inner.mut_token().is_some()); - TypeRef::RawPtr(Box::new(inner_ty), mutability) + TypeRef::RawPtr(inner_ty, mutability) } ast::Type::ArrayType(inner) => { let len = ConstRef::from_const_arg(ctx, inner.const_arg()); - TypeRef::Array(Box::new(TypeRef::from_ast_opt(ctx, inner.ty())), len) - } - ast::Type::SliceType(inner) => { - TypeRef::Slice(Box::new(TypeRef::from_ast_opt(ctx, inner.ty()))) + TypeRef::Array(Box::new(ArrayType { + ty: TypeRef::from_ast_opt(ctx, inner.ty()), + len, + })) } + ast::Type::SliceType(inner) => TypeRef::Slice(TypeRef::from_ast_opt(ctx, inner.ty())), ast::Type::RefType(inner) => { let inner_ty = TypeRef::from_ast_opt(ctx, inner.ty()); let lifetime = inner.lifetime().map(|lt| LifetimeRef::new(<)); let mutability = Mutability::from_mutable(inner.mut_token().is_some()); - TypeRef::Reference(Box::new(inner_ty), lifetime, mutability) + TypeRef::Reference(Box::new(RefType { ty: inner_ty, lifetime, mutability })) } ast::Type::InferType(_inner) => TypeRef::Placeholder, ast::Type::FnPtrType(inner) => { @@ -209,7 +280,7 @@ impl TypeRef { .ret_type() .and_then(|rt| rt.ty()) .map(|it| TypeRef::from_ast(ctx, it)) - .unwrap_or_else(|| TypeRef::Tuple(Vec::new())); + .unwrap_or_else(|| ctx.alloc_type_ref_desugared(TypeRef::unit())); let mut is_varargs = false; let mut params = if let Some(pl) = inner.param_list() { if let Some(param) = pl.params().last() { @@ -241,10 +312,10 @@ impl TypeRef { let abi = inner.abi().map(lower_abi); params.push((None, ret_ty)); - TypeRef::Fn(params.into(), is_varargs, inner.unsafe_token().is_some(), abi) + TypeRef::Fn(FnType::new(is_varargs, inner.unsafe_token().is_some(), abi, params)) } // for types are close enough for our purposes to the inner type for now... - ast::Type::ForType(inner) => TypeRef::from_ast_opt(ctx, inner.ty()), + ast::Type::ForType(inner) => return TypeRef::from_ast_opt(ctx, inner.ty()), ast::Type::ImplTraitType(inner) => { if ctx.outer_impl_trait() { // Disallow nested impl traits @@ -261,74 +332,74 @@ impl TypeRef { Some(mc) => TypeRef::Macro(ctx.ast_id(&mc)), None => TypeRef::Error, }, - } + }; + ctx.alloc_type_ref(ty, AstPtr::new(&node)) } - pub(crate) fn from_ast_opt(ctx: &LowerCtx<'_>, node: Option<ast::Type>) -> Self { + pub(crate) fn from_ast_opt(ctx: &LowerCtx<'_>, node: Option<ast::Type>) -> TypeRefId { match node { Some(node) => TypeRef::from_ast(ctx, node), - None => TypeRef::Error, + None => ctx.alloc_error_type(), } } pub(crate) fn unit() -> TypeRef { - TypeRef::Tuple(Vec::new()) + TypeRef::Tuple(EmptyOptimizedThinVec::empty()) } - pub fn walk(&self, f: &mut impl FnMut(&TypeRef)) { - go(self, f); + pub fn walk(this: TypeRefId, map: &TypesMap, f: &mut impl FnMut(&TypeRef)) { + go(this, f, map); - fn go(type_ref: &TypeRef, f: &mut impl FnMut(&TypeRef)) { + fn go(type_ref: TypeRefId, f: &mut impl FnMut(&TypeRef), map: &TypesMap) { + let type_ref = &map[type_ref]; f(type_ref); match type_ref { - TypeRef::Fn(params, _, _, _) => { - params.iter().for_each(|(_, param_type)| go(param_type, f)) + TypeRef::Fn(fn_) => { + fn_.params().iter().for_each(|&(_, param_type)| go(param_type, f, map)) } - TypeRef::Tuple(types) => types.iter().for_each(|t| go(t, f)), - TypeRef::RawPtr(type_ref, _) - | TypeRef::Reference(type_ref, ..) - | TypeRef::Array(type_ref, _) - | TypeRef::Slice(type_ref) => go(type_ref, f), + TypeRef::Tuple(types) => types.iter().for_each(|&t| go(t, f, map)), + TypeRef::RawPtr(type_ref, _) | TypeRef::Slice(type_ref) => go(*type_ref, f, map), + TypeRef::Reference(it) => go(it.ty, f, map), + TypeRef::Array(it) => go(it.ty, f, map), TypeRef::ImplTrait(bounds) | TypeRef::DynTrait(bounds) => { for bound in bounds { - match bound.as_ref() { + match bound { TypeBound::Path(path, _) | TypeBound::ForLifetime(_, path) => { - go_path(path, f) + go_path(path, f, map) } - TypeBound::Lifetime(_) | TypeBound::Error => (), + TypeBound::Lifetime(_) | TypeBound::Error | TypeBound::Use(_) => (), } } } - TypeRef::Path(path) => go_path(path, f), + TypeRef::Path(path) => go_path(path, f, map), TypeRef::Never | TypeRef::Placeholder | TypeRef::Macro(_) | TypeRef::Error => {} }; } - fn go_path(path: &Path, f: &mut impl FnMut(&TypeRef)) { + fn go_path(path: &Path, f: &mut impl FnMut(&TypeRef), map: &TypesMap) { if let Some(type_ref) = path.type_anchor() { - go(type_ref, f); + go(type_ref, f, map); } for segment in path.segments().iter() { if let Some(args_and_bindings) = segment.args_and_bindings { for arg in args_and_bindings.args.iter() { match arg { - crate::path::GenericArg::Type(type_ref) => { - go(type_ref, f); + GenericArg::Type(type_ref) => { + go(*type_ref, f, map); } - crate::path::GenericArg::Const(_) - | crate::path::GenericArg::Lifetime(_) => {} + GenericArg::Const(_) | GenericArg::Lifetime(_) => {} } } for binding in args_and_bindings.bindings.iter() { - if let Some(type_ref) = &binding.type_ref { - go(type_ref, f); + if let Some(type_ref) = binding.type_ref { + go(type_ref, f, map); } for bound in binding.bounds.iter() { - match bound.as_ref() { + match bound { TypeBound::Path(path, _) | TypeBound::ForLifetime(_, path) => { - go_path(path, f) + go_path(path, f, map) } - TypeBound::Lifetime(_) | TypeBound::Error => (), + TypeBound::Lifetime(_) | TypeBound::Error | TypeBound::Use(_) => (), } } } @@ -341,11 +412,13 @@ impl TypeRef { pub(crate) fn type_bounds_from_ast( lower_ctx: &LowerCtx<'_>, type_bounds_opt: Option<ast::TypeBoundList>, -) -> Vec<Interned<TypeBound>> { +) -> ThinVec<TypeBound> { if let Some(type_bounds) = type_bounds_opt { - type_bounds.bounds().map(|it| Interned::new(TypeBound::from_ast(lower_ctx, it))).collect() + ThinVec::from_iter(Vec::from_iter( + type_bounds.bounds().map(|it| TypeBound::from_ast(lower_ctx, it)), + )) } else { - vec![] + ThinVec::from_iter([]) } } @@ -380,7 +453,16 @@ impl TypeBound { None => TypeBound::Error, } } - ast::TypeBoundKind::Use(_) => TypeBound::Error, + ast::TypeBoundKind::Use(gal) => TypeBound::Use( + gal.use_bound_generic_args() + .map(|p| match p { + ast::UseBoundGenericArg::Lifetime(l) => { + UseArgRef::Lifetime(LifetimeRef::new(&l)) + } + ast::UseBoundGenericArg::NameRef(n) => UseArgRef::Name(n.as_name()), + }) + .collect(), + ), ast::TypeBoundKind::Lifetime(lifetime) => { TypeBound::Lifetime(LifetimeRef::new(&lifetime)) } @@ -391,7 +473,7 @@ impl TypeBound { match self { TypeBound::Path(p, m) => Some((p, m)), TypeBound::ForLifetime(_, p) => Some((p, &TraitBoundModifier::None)), - TypeBound::Lifetime(_) | TypeBound::Error => None, + TypeBound::Lifetime(_) | TypeBound::Error | TypeBound::Use(_) => None, } } } diff --git a/src/tools/rust-analyzer/crates/hir-def/src/item_tree.rs b/src/tools/rust-analyzer/crates/hir-def/src/item_tree.rs index 7cb833fdce7..b5bf2feb82a 100644 --- a/src/tools/rust-analyzer/crates/hir-def/src/item_tree.rs +++ b/src/tools/rust-analyzer/crates/hir-def/src/item_tree.rs @@ -61,7 +61,7 @@ use crate::{ db::DefDatabase, generics::GenericParams, path::{GenericArgs, ImportAlias, ModPath, Path, PathKind}, - type_ref::{Mutability, TraitRef, TypeBound, TypeRef}, + type_ref::{Mutability, TraitRef, TypeBound, TypeRefId, TypesMap, TypesSourceMap}, visibility::{RawVisibility, VisibilityExplicitness}, BlockId, LocalLifetimeParamId, LocalTypeOrConstParamId, Lookup, }; @@ -100,14 +100,20 @@ pub struct ItemTree { impl ItemTree { pub(crate) fn file_item_tree_query(db: &dyn DefDatabase, file_id: HirFileId) -> Arc<ItemTree> { - let _p = tracing::info_span!("file_item_tree_query", ?file_id).entered(); - static EMPTY: OnceLock<Arc<ItemTree>> = OnceLock::new(); + db.file_item_tree_with_source_map(file_id).0 + } - let syntax = db.parse_or_expand(file_id); + pub(crate) fn file_item_tree_with_source_map_query( + db: &dyn DefDatabase, + file_id: HirFileId, + ) -> (Arc<ItemTree>, Arc<ItemTreeSourceMaps>) { + let _p = tracing::info_span!("file_item_tree_query", ?file_id).entered(); + static EMPTY: OnceLock<(Arc<ItemTree>, Arc<ItemTreeSourceMaps>)> = OnceLock::new(); let ctx = lower::Ctx::new(db, file_id); + let syntax = db.parse_or_expand(file_id); let mut top_attrs = None; - let mut item_tree = match_ast! { + let (mut item_tree, source_maps) = match_ast! { match syntax { ast::SourceFile(file) => { top_attrs = Some(RawAttrs::new(db.upcast(), &file, ctx.span_map())); @@ -137,42 +143,55 @@ impl ItemTree { { EMPTY .get_or_init(|| { - Arc::new(ItemTree { - top_level: SmallVec::new_const(), - attrs: FxHashMap::default(), - data: None, - }) + ( + Arc::new(ItemTree { + top_level: SmallVec::new_const(), + attrs: FxHashMap::default(), + data: None, + }), + Arc::default(), + ) }) .clone() } else { item_tree.shrink_to_fit(); - Arc::new(item_tree) + (Arc::new(item_tree), Arc::new(source_maps)) } } pub(crate) fn block_item_tree_query(db: &dyn DefDatabase, block: BlockId) -> Arc<ItemTree> { + db.block_item_tree_with_source_map(block).0 + } + + pub(crate) fn block_item_tree_with_source_map_query( + db: &dyn DefDatabase, + block: BlockId, + ) -> (Arc<ItemTree>, Arc<ItemTreeSourceMaps>) { let _p = tracing::info_span!("block_item_tree_query", ?block).entered(); - static EMPTY: OnceLock<Arc<ItemTree>> = OnceLock::new(); + static EMPTY: OnceLock<(Arc<ItemTree>, Arc<ItemTreeSourceMaps>)> = OnceLock::new(); let loc = block.lookup(db); let block = loc.ast_id.to_node(db.upcast()); let ctx = lower::Ctx::new(db, loc.ast_id.file_id); - let mut item_tree = ctx.lower_block(&block); + let (mut item_tree, source_maps) = ctx.lower_block(&block); if item_tree.data.is_none() && item_tree.top_level.is_empty() && item_tree.attrs.is_empty() { EMPTY .get_or_init(|| { - Arc::new(ItemTree { - top_level: SmallVec::new_const(), - attrs: FxHashMap::default(), - data: None, - }) + ( + Arc::new(ItemTree { + top_level: SmallVec::new_const(), + attrs: FxHashMap::default(), + data: None, + }), + Arc::default(), + ) }) .clone() } else { item_tree.shrink_to_fit(); - Arc::new(item_tree) + (Arc::new(item_tree), Arc::new(source_maps)) } } @@ -309,6 +328,160 @@ struct ItemTreeData { vis: ItemVisibilities, } +#[derive(Default, Debug, Eq, PartialEq)] +pub struct ItemTreeSourceMaps { + all_concatenated: Box<[TypesSourceMap]>, + structs_offset: u32, + unions_offset: u32, + enum_generics_offset: u32, + variants_offset: u32, + consts_offset: u32, + statics_offset: u32, + trait_generics_offset: u32, + trait_alias_generics_offset: u32, + impls_offset: u32, + type_aliases_offset: u32, +} + +#[derive(Clone, Copy)] +pub struct GenericItemSourceMap<'a>(&'a [TypesSourceMap; 2]); + +impl<'a> GenericItemSourceMap<'a> { + #[inline] + pub fn item(self) -> &'a TypesSourceMap { + &self.0[0] + } + + #[inline] + pub fn generics(self) -> &'a TypesSourceMap { + &self.0[1] + } +} + +#[derive(Default, Debug, Eq, PartialEq)] +pub struct GenericItemSourceMapBuilder { + pub item: TypesSourceMap, + pub generics: TypesSourceMap, +} + +#[derive(Default, Debug, Eq, PartialEq)] +struct ItemTreeSourceMapsBuilder { + functions: Vec<GenericItemSourceMapBuilder>, + structs: Vec<GenericItemSourceMapBuilder>, + unions: Vec<GenericItemSourceMapBuilder>, + enum_generics: Vec<TypesSourceMap>, + variants: Vec<TypesSourceMap>, + consts: Vec<TypesSourceMap>, + statics: Vec<TypesSourceMap>, + trait_generics: Vec<TypesSourceMap>, + trait_alias_generics: Vec<TypesSourceMap>, + impls: Vec<GenericItemSourceMapBuilder>, + type_aliases: Vec<GenericItemSourceMapBuilder>, +} + +impl ItemTreeSourceMapsBuilder { + fn build(self) -> ItemTreeSourceMaps { + let ItemTreeSourceMapsBuilder { + functions, + structs, + unions, + enum_generics, + variants, + consts, + statics, + trait_generics, + trait_alias_generics, + impls, + type_aliases, + } = self; + let structs_offset = functions.len() as u32 * 2; + let unions_offset = structs_offset + (structs.len() as u32 * 2); + let enum_generics_offset = unions_offset + (unions.len() as u32 * 2); + let variants_offset = enum_generics_offset + (enum_generics.len() as u32); + let consts_offset = variants_offset + (variants.len() as u32); + let statics_offset = consts_offset + (consts.len() as u32); + let trait_generics_offset = statics_offset + (statics.len() as u32); + let trait_alias_generics_offset = trait_generics_offset + (trait_generics.len() as u32); + let impls_offset = trait_alias_generics_offset + (trait_alias_generics.len() as u32); + let type_aliases_offset = impls_offset + (impls.len() as u32 * 2); + let all_concatenated = generics_concat(functions) + .chain(generics_concat(structs)) + .chain(generics_concat(unions)) + .chain(enum_generics) + .chain(variants) + .chain(consts) + .chain(statics) + .chain(trait_generics) + .chain(trait_alias_generics) + .chain(generics_concat(impls)) + .chain(generics_concat(type_aliases)) + .collect(); + return ItemTreeSourceMaps { + all_concatenated, + structs_offset, + unions_offset, + enum_generics_offset, + variants_offset, + consts_offset, + statics_offset, + trait_generics_offset, + trait_alias_generics_offset, + impls_offset, + type_aliases_offset, + }; + + fn generics_concat( + source_maps: Vec<GenericItemSourceMapBuilder>, + ) -> impl Iterator<Item = TypesSourceMap> { + source_maps.into_iter().flat_map(|it| [it.item, it.generics]) + } + } +} + +impl ItemTreeSourceMaps { + #[inline] + fn generic_item(&self, offset: u32, index: u32) -> GenericItemSourceMap<'_> { + GenericItemSourceMap( + self.all_concatenated[(offset + (index * 2)) as usize..][..2].try_into().unwrap(), + ) + } + + #[inline] + fn non_generic_item(&self, offset: u32, index: u32) -> &TypesSourceMap { + &self.all_concatenated[(offset + index) as usize] + } + + #[inline] + pub fn function(&self, index: FileItemTreeId<Function>) -> GenericItemSourceMap<'_> { + self.generic_item(0, index.0.into_raw().into_u32()) + } +} + +macro_rules! index_item_source_maps { + ( $( $name:ident; $field:ident[$tree_id:ident]; $fn:ident; $ret:ty, )* ) => { + impl ItemTreeSourceMaps { + $( + #[inline] + pub fn $name(&self, index: FileItemTreeId<$tree_id>) -> $ret { + self.$fn(self.$field, index.0.into_raw().into_u32()) + } + )* + } + }; +} +index_item_source_maps! { + strukt; structs_offset[Struct]; generic_item; GenericItemSourceMap<'_>, + union; unions_offset[Union]; generic_item; GenericItemSourceMap<'_>, + enum_generic; enum_generics_offset[Enum]; non_generic_item; &TypesSourceMap, + variant; variants_offset[Variant]; non_generic_item; &TypesSourceMap, + konst; consts_offset[Const]; non_generic_item; &TypesSourceMap, + statik; statics_offset[Static]; non_generic_item; &TypesSourceMap, + trait_generic; trait_generics_offset[Trait]; non_generic_item; &TypesSourceMap, + trait_alias_generic; trait_alias_generics_offset[TraitAlias]; non_generic_item; &TypesSourceMap, + impl_; impls_offset[Impl]; generic_item; GenericItemSourceMap<'_>, + type_alias; type_aliases_offset[TypeAlias]; generic_item; GenericItemSourceMap<'_>, +} + #[derive(Copy, Clone, Debug, Eq, PartialEq, Hash)] pub enum AttrOwner { /// Attributes on an item. @@ -364,7 +537,7 @@ pub trait ItemTreeNode: Clone { fn attr_owner(id: FileItemTreeId<Self>) -> AttrOwner; } pub trait GenericsItemTreeNode: ItemTreeNode { - fn generic_params(&self) -> &Interned<GenericParams>; + fn generic_params(&self) -> &Arc<GenericParams>; } pub struct FileItemTreeId<N>(Idx<N>); @@ -429,6 +602,16 @@ impl TreeId { } } + pub fn item_tree_with_source_map( + &self, + db: &dyn DefDatabase, + ) -> (Arc<ItemTree>, Arc<ItemTreeSourceMaps>) { + match self.block { + Some(block) => db.block_item_tree_with_source_map(block), + None => db.file_item_tree_with_source_map(self.file), + } + } + pub fn file_id(self) -> HirFileId { self.file } @@ -461,6 +644,13 @@ impl<N> ItemTreeId<N> { self.tree.item_tree(db) } + pub fn item_tree_with_source_map( + self, + db: &dyn DefDatabase, + ) -> (Arc<ItemTree>, Arc<ItemTreeSourceMaps>) { + self.tree.item_tree_with_source_map(db) + } + pub fn resolved<R>(self, db: &dyn DefDatabase, cb: impl FnOnce(&N) -> R) -> R where ItemTree: Index<FileItemTreeId<N>, Output = N>, @@ -593,7 +783,7 @@ macro_rules! mod_items { $( impl GenericsItemTreeNode for $typ { - fn generic_params(&self) -> &Interned<GenericParams> { + fn generic_params(&self) -> &Arc<GenericParams> { &self.$generic_params } } @@ -731,17 +921,18 @@ pub struct ExternBlock { pub struct Function { pub name: Name, pub visibility: RawVisibilityId, - pub explicit_generic_params: Interned<GenericParams>, + pub explicit_generic_params: Arc<GenericParams>, pub abi: Option<Symbol>, pub params: Box<[Param]>, - pub ret_type: Interned<TypeRef>, + pub ret_type: TypeRefId, pub ast_id: FileAstId<ast::Fn>, + pub types_map: Arc<TypesMap>, pub(crate) flags: FnFlags, } #[derive(Debug, Clone, PartialEq, Eq)] pub struct Param { - pub type_ref: Option<Interned<TypeRef>>, + pub type_ref: Option<TypeRefId>, } bitflags::bitflags! { @@ -762,26 +953,28 @@ bitflags::bitflags! { pub struct Struct { pub name: Name, pub visibility: RawVisibilityId, - pub generic_params: Interned<GenericParams>, + pub generic_params: Arc<GenericParams>, pub fields: Box<[Field]>, pub shape: FieldsShape, pub ast_id: FileAstId<ast::Struct>, + pub types_map: Arc<TypesMap>, } #[derive(Debug, Clone, Eq, PartialEq)] pub struct Union { pub name: Name, pub visibility: RawVisibilityId, - pub generic_params: Interned<GenericParams>, + pub generic_params: Arc<GenericParams>, pub fields: Box<[Field]>, pub ast_id: FileAstId<ast::Union>, + pub types_map: Arc<TypesMap>, } #[derive(Debug, Clone, Eq, PartialEq)] pub struct Enum { pub name: Name, pub visibility: RawVisibilityId, - pub generic_params: Interned<GenericParams>, + pub generic_params: Arc<GenericParams>, pub variants: Range<FileItemTreeId<Variant>>, pub ast_id: FileAstId<ast::Enum>, } @@ -792,6 +985,7 @@ pub struct Variant { pub fields: Box<[Field]>, pub shape: FieldsShape, pub ast_id: FileAstId<ast::Variant>, + pub types_map: Arc<TypesMap>, } #[derive(Debug, Copy, Clone, PartialEq, Eq)] @@ -805,7 +999,7 @@ pub enum FieldsShape { #[derive(Debug, Clone, PartialEq, Eq)] pub struct Field { pub name: Name, - pub type_ref: Interned<TypeRef>, + pub type_ref: TypeRefId, pub visibility: RawVisibilityId, } @@ -814,9 +1008,10 @@ pub struct Const { /// `None` for `const _: () = ();` pub name: Option<Name>, pub visibility: RawVisibilityId, - pub type_ref: Interned<TypeRef>, + pub type_ref: TypeRefId, pub ast_id: FileAstId<ast::Const>, pub has_body: bool, + pub types_map: Arc<TypesMap>, } #[derive(Debug, Clone, Eq, PartialEq)] @@ -827,15 +1022,16 @@ pub struct Static { pub mutable: bool, pub has_safe_kw: bool, pub has_unsafe_kw: bool, - pub type_ref: Interned<TypeRef>, + pub type_ref: TypeRefId, pub ast_id: FileAstId<ast::Static>, + pub types_map: Arc<TypesMap>, } #[derive(Debug, Clone, Eq, PartialEq)] pub struct Trait { pub name: Name, pub visibility: RawVisibilityId, - pub generic_params: Interned<GenericParams>, + pub generic_params: Arc<GenericParams>, pub is_auto: bool, pub is_unsafe: bool, pub items: Box<[AssocItem]>, @@ -846,19 +1042,20 @@ pub struct Trait { pub struct TraitAlias { pub name: Name, pub visibility: RawVisibilityId, - pub generic_params: Interned<GenericParams>, + pub generic_params: Arc<GenericParams>, pub ast_id: FileAstId<ast::TraitAlias>, } #[derive(Debug, Clone, Eq, PartialEq)] pub struct Impl { - pub generic_params: Interned<GenericParams>, - pub target_trait: Option<Interned<TraitRef>>, - pub self_ty: Interned<TypeRef>, + pub generic_params: Arc<GenericParams>, + pub target_trait: Option<TraitRef>, + pub self_ty: TypeRefId, pub is_negative: bool, pub is_unsafe: bool, pub items: Box<[AssocItem]>, pub ast_id: FileAstId<ast::Impl>, + pub types_map: Arc<TypesMap>, } #[derive(Debug, Clone, PartialEq, Eq)] @@ -866,10 +1063,11 @@ pub struct TypeAlias { pub name: Name, pub visibility: RawVisibilityId, /// Bounds on the type alias itself. Only valid in trait declarations, eg. `type Assoc: Copy;`. - pub bounds: Box<[Interned<TypeBound>]>, - pub generic_params: Interned<GenericParams>, - pub type_ref: Option<Interned<TypeRef>>, + pub bounds: Box<[TypeBound]>, + pub generic_params: Arc<GenericParams>, + pub type_ref: Option<TypeRefId>, pub ast_id: FileAstId<ast::TypeAlias>, + pub types_map: Arc<TypesMap>, } #[derive(Debug, Clone, Eq, PartialEq)] @@ -968,6 +1166,11 @@ impl UseTree { self.expand_impl(None, &mut cb) } + /// The [`UseTreeKind`] of this `UseTree`. + pub fn kind(&self) -> &UseTreeKind { + &self.kind + } + fn expand_impl( &self, prefix: Option<ModPath>, diff --git a/src/tools/rust-analyzer/crates/hir-def/src/item_tree/lower.rs b/src/tools/rust-analyzer/crates/hir-def/src/item_tree/lower.rs index 431a7f66f40..bd17fce37b7 100644 --- a/src/tools/rust-analyzer/crates/hir-def/src/item_tree/lower.rs +++ b/src/tools/rust-analyzer/crates/hir-def/src/item_tree/lower.rs @@ -1,12 +1,18 @@ //! AST -> `ItemTree` lowering code. -use std::collections::hash_map::Entry; +use std::{cell::OnceCell, collections::hash_map::Entry}; -use hir_expand::{mod_path::path, name::AsName, span_map::SpanMapRef, HirFileId}; +use hir_expand::{ + mod_path::path, + name::AsName, + span_map::{SpanMap, SpanMapRef}, + HirFileId, +}; use intern::{sym, Symbol}; use la_arena::Arena; use rustc_hash::FxHashMap; use span::{AstIdMap, SyntaxContextId}; +use stdx::thin_vec::ThinVec; use syntax::{ ast::{self, HasModuleItem, HasName, HasTypeBounds, IsString}, AstNode, @@ -18,14 +24,19 @@ use crate::{ generics::{GenericParams, GenericParamsCollector, TypeParamData, TypeParamProvenance}, item_tree::{ AssocItem, AttrOwner, Const, Either, Enum, ExternBlock, ExternCrate, Field, FieldParent, - FieldsShape, FileItemTreeId, FnFlags, Function, GenericArgs, GenericModItem, Idx, Impl, - ImportAlias, Interned, ItemTree, ItemTreeData, Macro2, MacroCall, MacroRules, Mod, ModItem, + FieldsShape, FileItemTreeId, FnFlags, Function, GenericArgs, GenericItemSourceMapBuilder, + GenericModItem, Idx, Impl, ImportAlias, Interned, ItemTree, ItemTreeData, + ItemTreeSourceMaps, ItemTreeSourceMapsBuilder, Macro2, MacroCall, MacroRules, Mod, ModItem, ModKind, ModPath, Mutability, Name, Param, Path, Range, RawAttrs, RawIdx, RawVisibilityId, Static, Struct, StructKind, Trait, TraitAlias, TypeAlias, Union, Use, UseTree, UseTreeKind, Variant, }, + lower::LowerCtx, path::AssociatedTypeBinding, - type_ref::{LifetimeRef, TraitBoundModifier, TraitRef, TypeBound, TypeRef}, + type_ref::{ + LifetimeRef, RefType, TraitBoundModifier, TraitRef, TypeBound, TypeRef, TypeRefId, + TypesMap, TypesSourceMap, + }, visibility::RawVisibility, LocalLifetimeParamId, LocalTypeOrConstParamId, }; @@ -40,7 +51,9 @@ pub(super) struct Ctx<'a> { source_ast_id_map: Arc<AstIdMap>, generic_param_attr_buffer: FxHashMap<Either<LocalTypeOrConstParamId, LocalLifetimeParamId>, RawAttrs>, - body_ctx: crate::lower::LowerCtx<'a>, + span_map: OnceCell<SpanMap>, + file: HirFileId, + source_maps: ItemTreeSourceMapsBuilder, } impl<'a> Ctx<'a> { @@ -50,22 +63,49 @@ impl<'a> Ctx<'a> { tree: ItemTree::default(), generic_param_attr_buffer: FxHashMap::default(), source_ast_id_map: db.ast_id_map(file), - body_ctx: crate::lower::LowerCtx::new(db, file), + file, + span_map: OnceCell::new(), + source_maps: ItemTreeSourceMapsBuilder::default(), } } pub(super) fn span_map(&self) -> SpanMapRef<'_> { - self.body_ctx.span_map() + self.span_map.get_or_init(|| self.db.span_map(self.file)).as_ref() + } + + fn body_ctx<'b, 'c>( + &self, + types_map: &'b mut TypesMap, + types_source_map: &'b mut TypesSourceMap, + ) -> LowerCtx<'c> + where + 'a: 'c, + 'b: 'c, + { + // FIXME: This seems a bit wasteful that if `LowerCtx` will initialize the span map we won't benefit. + LowerCtx::with_span_map_cell( + self.db, + self.file, + self.span_map.clone(), + types_map, + types_source_map, + ) } - pub(super) fn lower_module_items(mut self, item_owner: &dyn HasModuleItem) -> ItemTree { + pub(super) fn lower_module_items( + mut self, + item_owner: &dyn HasModuleItem, + ) -> (ItemTree, ItemTreeSourceMaps) { self.tree.top_level = item_owner.items().flat_map(|item| self.lower_mod_item(&item)).collect(); assert!(self.generic_param_attr_buffer.is_empty()); - self.tree + (self.tree, self.source_maps.build()) } - pub(super) fn lower_macro_stmts(mut self, stmts: ast::MacroStmts) -> ItemTree { + pub(super) fn lower_macro_stmts( + mut self, + stmts: ast::MacroStmts, + ) -> (ItemTree, ItemTreeSourceMaps) { self.tree.top_level = stmts .statements() .filter_map(|stmt| { @@ -96,10 +136,10 @@ impl<'a> Ctx<'a> { } assert!(self.generic_param_attr_buffer.is_empty()); - self.tree + (self.tree, self.source_maps.build()) } - pub(super) fn lower_block(mut self, block: &ast::BlockExpr) -> ItemTree { + pub(super) fn lower_block(mut self, block: &ast::BlockExpr) -> (ItemTree, ItemTreeSourceMaps) { self.tree .attrs .insert(AttrOwner::TopLevel, RawAttrs::new(self.db.upcast(), block, self.span_map())); @@ -125,7 +165,7 @@ impl<'a> Ctx<'a> { } assert!(self.generic_param_attr_buffer.is_empty()); - self.tree + (self.tree, self.source_maps.build()) } fn data(&mut self) -> &mut ItemTreeData { @@ -144,7 +184,7 @@ impl<'a> Ctx<'a> { ast::Item::Module(ast) => self.lower_module(ast)?.into(), ast::Item::Trait(ast) => self.lower_trait(ast)?.into(), ast::Item::TraitAlias(ast) => self.lower_trait_alias(ast)?.into(), - ast::Item::Impl(ast) => self.lower_impl(ast)?.into(), + ast::Item::Impl(ast) => self.lower_impl(ast).into(), ast::Item::Use(ast) => self.lower_use(ast)?.into(), ast::Item::ExternCrate(ast) => self.lower_extern_crate(ast)?.into(), ast::Item::MacroCall(ast) => self.lower_macro_call(ast)?.into(), @@ -159,12 +199,14 @@ impl<'a> Ctx<'a> { } fn add_attrs(&mut self, item: AttrOwner, attrs: RawAttrs) { - match self.tree.attrs.entry(item) { - Entry::Occupied(mut entry) => { - *entry.get_mut() = entry.get().merge(attrs); - } - Entry::Vacant(entry) => { - entry.insert(attrs); + if !attrs.is_empty() { + match self.tree.attrs.entry(item) { + Entry::Occupied(mut entry) => { + *entry.get_mut() = entry.get().merge(attrs); + } + Entry::Vacant(entry) => { + entry.insert(attrs); + } } } } @@ -190,13 +232,31 @@ impl<'a> Ctx<'a> { } fn lower_struct(&mut self, strukt: &ast::Struct) -> Option<FileItemTreeId<Struct>> { + let (mut types_map, mut types_source_map) = + (TypesMap::default(), TypesSourceMap::default()); + let body_ctx = self.body_ctx(&mut types_map, &mut types_source_map); let visibility = self.lower_visibility(strukt); let name = strukt.name()?.as_name(); let ast_id = self.source_ast_id_map.ast_id(strukt); - let (fields, kind, attrs) = self.lower_fields(&strukt.kind()); - let generic_params = self.lower_generic_params(HasImplicitSelf::No, strukt); - let res = Struct { name, visibility, generic_params, fields, shape: kind, ast_id }; + let (fields, kind, attrs) = self.lower_fields(&strukt.kind(), &body_ctx); + let (generic_params, generics_source_map) = + self.lower_generic_params(HasImplicitSelf::No, strukt); + types_map.shrink_to_fit(); + types_source_map.shrink_to_fit(); + let res = Struct { + name, + visibility, + generic_params, + fields, + shape: kind, + ast_id, + types_map: Arc::new(types_map), + }; let id = id(self.data().structs.alloc(res)); + self.source_maps.structs.push(GenericItemSourceMapBuilder { + item: types_source_map, + generics: generics_source_map, + }); for (idx, attr) in attrs { self.add_attrs( AttrOwner::Field( @@ -213,6 +273,7 @@ impl<'a> Ctx<'a> { fn lower_fields( &mut self, strukt_kind: &ast::StructKind, + body_ctx: &LowerCtx<'_>, ) -> (Box<[Field]>, FieldsShape, Vec<(usize, RawAttrs)>) { match strukt_kind { ast::StructKind::Record(it) => { @@ -220,7 +281,7 @@ impl<'a> Ctx<'a> { let mut attrs = vec![]; for (i, field) in it.fields().enumerate() { - let data = self.lower_record_field(&field); + let data = self.lower_record_field(&field, body_ctx); fields.push(data); let attr = RawAttrs::new(self.db.upcast(), &field, self.span_map()); if !attr.is_empty() { @@ -234,7 +295,7 @@ impl<'a> Ctx<'a> { let mut attrs = vec![]; for (i, field) in it.fields().enumerate() { - let data = self.lower_tuple_field(i, &field); + let data = self.lower_tuple_field(i, &field, body_ctx); fields.push(data); let attr = RawAttrs::new(self.db.upcast(), &field, self.span_map()); if !attr.is_empty() { @@ -247,35 +308,59 @@ impl<'a> Ctx<'a> { } } - fn lower_record_field(&mut self, field: &ast::RecordField) -> Field { + fn lower_record_field(&mut self, field: &ast::RecordField, body_ctx: &LowerCtx<'_>) -> Field { let name = match field.name() { Some(name) => name.as_name(), None => Name::missing(), }; let visibility = self.lower_visibility(field); - let type_ref = self.lower_type_ref_opt(field.ty()); + let type_ref = TypeRef::from_ast_opt(body_ctx, field.ty()); Field { name, type_ref, visibility } } - fn lower_tuple_field(&mut self, idx: usize, field: &ast::TupleField) -> Field { + fn lower_tuple_field( + &mut self, + idx: usize, + field: &ast::TupleField, + body_ctx: &LowerCtx<'_>, + ) -> Field { let name = Name::new_tuple_field(idx); let visibility = self.lower_visibility(field); - let type_ref = self.lower_type_ref_opt(field.ty()); + let type_ref = TypeRef::from_ast_opt(body_ctx, field.ty()); Field { name, type_ref, visibility } } fn lower_union(&mut self, union: &ast::Union) -> Option<FileItemTreeId<Union>> { + let (mut types_map, mut types_source_map) = + (TypesMap::default(), TypesSourceMap::default()); + let body_ctx = self.body_ctx(&mut types_map, &mut types_source_map); let visibility = self.lower_visibility(union); let name = union.name()?.as_name(); let ast_id = self.source_ast_id_map.ast_id(union); let (fields, _, attrs) = match union.record_field_list() { - Some(record_field_list) => self.lower_fields(&StructKind::Record(record_field_list)), + Some(record_field_list) => { + self.lower_fields(&StructKind::Record(record_field_list), &body_ctx) + } None => (Box::default(), FieldsShape::Record, Vec::default()), }; - let generic_params = self.lower_generic_params(HasImplicitSelf::No, union); - let res = Union { name, visibility, generic_params, fields, ast_id }; + let (generic_params, generics_source_map) = + self.lower_generic_params(HasImplicitSelf::No, union); + types_map.shrink_to_fit(); + types_source_map.shrink_to_fit(); + let res = Union { + name, + visibility, + generic_params, + fields, + ast_id, + types_map: Arc::new(types_map), + }; let id = id(self.data().unions.alloc(res)); + self.source_maps.unions.push(GenericItemSourceMapBuilder { + item: types_source_map, + generics: generics_source_map, + }); for (idx, attr) in attrs { self.add_attrs( AttrOwner::Field( @@ -299,9 +384,11 @@ impl<'a> Ctx<'a> { FileItemTreeId(self.next_variant_idx())..FileItemTreeId(self.next_variant_idx()) } }; - let generic_params = self.lower_generic_params(HasImplicitSelf::No, enum_); + let (generic_params, generics_source_map) = + self.lower_generic_params(HasImplicitSelf::No, enum_); let res = Enum { name, visibility, generic_params, variants, ast_id }; let id = id(self.data().enums.alloc(res)); + self.source_maps.enum_generics.push(generics_source_map); self.write_generic_params_attributes(id.into()); Some(id) } @@ -320,14 +407,20 @@ impl<'a> Ctx<'a> { } fn lower_variant(&mut self, variant: &ast::Variant) -> Idx<Variant> { + let (mut types_map, mut types_source_map) = + (TypesMap::default(), TypesSourceMap::default()); + let body_ctx = self.body_ctx(&mut types_map, &mut types_source_map); let name = match variant.name() { Some(name) => name.as_name(), None => Name::missing(), }; - let (fields, kind, attrs) = self.lower_fields(&variant.kind()); + let (fields, kind, attrs) = self.lower_fields(&variant.kind(), &body_ctx); let ast_id = self.source_ast_id_map.ast_id(variant); - let res = Variant { name, fields, shape: kind, ast_id }; + types_map.shrink_to_fit(); + types_source_map.shrink_to_fit(); + let res = Variant { name, fields, shape: kind, ast_id, types_map: Arc::new(types_map) }; let id = self.data().variants.alloc(res); + self.source_maps.variants.push(types_source_map); for (idx, attr) in attrs { self.add_attrs( AttrOwner::Field( @@ -341,6 +434,10 @@ impl<'a> Ctx<'a> { } fn lower_function(&mut self, func: &ast::Fn) -> Option<FileItemTreeId<Function>> { + let (mut types_map, mut types_source_map) = + (TypesMap::default(), TypesSourceMap::default()); + let body_ctx = self.body_ctx(&mut types_map, &mut types_source_map); + let visibility = self.lower_visibility(func); let name = func.name()?.as_name(); @@ -360,27 +457,31 @@ impl<'a> Ctx<'a> { RawAttrs::new(self.db.upcast(), &self_param, self.span_map()), ); let self_type = match self_param.ty() { - Some(type_ref) => TypeRef::from_ast(&self.body_ctx, type_ref), + Some(type_ref) => TypeRef::from_ast(&body_ctx, type_ref), None => { - let self_type = - TypeRef::Path(Name::new_symbol_root(sym::Self_.clone()).into()); + let self_type = body_ctx.alloc_type_ref_desugared(TypeRef::Path( + Name::new_symbol_root(sym::Self_.clone()).into(), + )); match self_param.kind() { ast::SelfParamKind::Owned => self_type, - ast::SelfParamKind::Ref => TypeRef::Reference( - Box::new(self_type), - self_param.lifetime().as_ref().map(LifetimeRef::new), - Mutability::Shared, + ast::SelfParamKind::Ref => body_ctx.alloc_type_ref_desugared( + TypeRef::Reference(Box::new(RefType { + ty: self_type, + lifetime: self_param.lifetime().as_ref().map(LifetimeRef::new), + mutability: Mutability::Shared, + })), ), - ast::SelfParamKind::MutRef => TypeRef::Reference( - Box::new(self_type), - self_param.lifetime().as_ref().map(LifetimeRef::new), - Mutability::Mut, + ast::SelfParamKind::MutRef => body_ctx.alloc_type_ref_desugared( + TypeRef::Reference(Box::new(RefType { + ty: self_type, + lifetime: self_param.lifetime().as_ref().map(LifetimeRef::new), + mutability: Mutability::Mut, + })), ), } } }; - let type_ref = Interned::new(self_type); - params.push(Param { type_ref: Some(type_ref) }); + params.push(Param { type_ref: Some(self_type) }); has_self_param = true; } for param in param_list.params() { @@ -391,9 +492,8 @@ impl<'a> Ctx<'a> { Param { type_ref: None } } None => { - let type_ref = TypeRef::from_ast_opt(&self.body_ctx, param.ty()); - let ty = Interned::new(type_ref); - Param { type_ref: Some(ty) } + let type_ref = TypeRef::from_ast_opt(&body_ctx, param.ty()); + Param { type_ref: Some(type_ref) } } }; params.push(param); @@ -402,17 +502,17 @@ impl<'a> Ctx<'a> { let ret_type = match func.ret_type() { Some(rt) => match rt.ty() { - Some(type_ref) => TypeRef::from_ast(&self.body_ctx, type_ref), - None if rt.thin_arrow_token().is_some() => TypeRef::Error, - None => TypeRef::unit(), + Some(type_ref) => TypeRef::from_ast(&body_ctx, type_ref), + None if rt.thin_arrow_token().is_some() => body_ctx.alloc_error_type(), + None => body_ctx.alloc_type_ref_desugared(TypeRef::unit()), }, - None => TypeRef::unit(), + None => body_ctx.alloc_type_ref_desugared(TypeRef::unit()), }; let ret_type = if func.async_token().is_some() { let future_impl = desugar_future_path(ret_type); - let ty_bound = Interned::new(TypeBound::Path(future_impl, TraitBoundModifier::None)); - TypeRef::ImplTrait(vec![ty_bound]) + let ty_bound = TypeBound::Path(future_impl, TraitBoundModifier::None); + body_ctx.alloc_type_ref_desugared(TypeRef::ImplTrait(ThinVec::from_iter([ty_bound]))) } else { ret_type }; @@ -447,18 +547,27 @@ impl<'a> Ctx<'a> { flags |= FnFlags::IS_VARARGS; } + types_map.shrink_to_fit(); + types_source_map.shrink_to_fit(); + let (generic_params, generics_source_map) = + self.lower_generic_params(HasImplicitSelf::No, func); let res = Function { name, visibility, - explicit_generic_params: self.lower_generic_params(HasImplicitSelf::No, func), + explicit_generic_params: generic_params, abi, params: params.into_boxed_slice(), - ret_type: Interned::new(ret_type), + ret_type, ast_id, + types_map: Arc::new(types_map), flags, }; let id = id(self.data().functions.alloc(res)); + self.source_maps.functions.push(GenericItemSourceMapBuilder { + item: types_source_map, + generics: generics_source_map, + }); for (idx, attr) in attrs { self.add_attrs(AttrOwner::Param(id, Idx::from_raw(RawIdx::from_u32(idx as u32))), attr); } @@ -470,37 +579,82 @@ impl<'a> Ctx<'a> { &mut self, type_alias: &ast::TypeAlias, ) -> Option<FileItemTreeId<TypeAlias>> { + let (mut types_map, mut types_source_map) = + (TypesMap::default(), TypesSourceMap::default()); + let body_ctx = self.body_ctx(&mut types_map, &mut types_source_map); let name = type_alias.name()?.as_name(); - let type_ref = type_alias.ty().map(|it| self.lower_type_ref(&it)); + let type_ref = type_alias.ty().map(|it| TypeRef::from_ast(&body_ctx, it)); let visibility = self.lower_visibility(type_alias); - let bounds = self.lower_type_bounds(type_alias); + let bounds = self.lower_type_bounds(type_alias, &body_ctx); let ast_id = self.source_ast_id_map.ast_id(type_alias); - let generic_params = self.lower_generic_params(HasImplicitSelf::No, type_alias); - let res = TypeAlias { name, visibility, bounds, generic_params, type_ref, ast_id }; + let (generic_params, generics_source_map) = + self.lower_generic_params(HasImplicitSelf::No, type_alias); + types_map.shrink_to_fit(); + types_source_map.shrink_to_fit(); + let res = TypeAlias { + name, + visibility, + bounds, + generic_params, + type_ref, + ast_id, + types_map: Arc::new(types_map), + }; let id = id(self.data().type_aliases.alloc(res)); + self.source_maps.type_aliases.push(GenericItemSourceMapBuilder { + item: types_source_map, + generics: generics_source_map, + }); self.write_generic_params_attributes(id.into()); Some(id) } fn lower_static(&mut self, static_: &ast::Static) -> Option<FileItemTreeId<Static>> { + let (mut types_map, mut types_source_map) = + (TypesMap::default(), TypesSourceMap::default()); + let body_ctx = self.body_ctx(&mut types_map, &mut types_source_map); let name = static_.name()?.as_name(); - let type_ref = self.lower_type_ref_opt(static_.ty()); + let type_ref = TypeRef::from_ast_opt(&body_ctx, static_.ty()); let visibility = self.lower_visibility(static_); let mutable = static_.mut_token().is_some(); let has_safe_kw = static_.safe_token().is_some(); let has_unsafe_kw = static_.unsafe_token().is_some(); let ast_id = self.source_ast_id_map.ast_id(static_); - let res = - Static { name, visibility, mutable, type_ref, ast_id, has_safe_kw, has_unsafe_kw }; + types_map.shrink_to_fit(); + types_source_map.shrink_to_fit(); + let res = Static { + name, + visibility, + mutable, + type_ref, + ast_id, + has_safe_kw, + has_unsafe_kw, + types_map: Arc::new(types_map), + }; + self.source_maps.statics.push(types_source_map); Some(id(self.data().statics.alloc(res))) } fn lower_const(&mut self, konst: &ast::Const) -> FileItemTreeId<Const> { + let (mut types_map, mut types_source_map) = + (TypesMap::default(), TypesSourceMap::default()); + let body_ctx = self.body_ctx(&mut types_map, &mut types_source_map); let name = konst.name().map(|it| it.as_name()); - let type_ref = self.lower_type_ref_opt(konst.ty()); + let type_ref = TypeRef::from_ast_opt(&body_ctx, konst.ty()); let visibility = self.lower_visibility(konst); let ast_id = self.source_ast_id_map.ast_id(konst); - let res = Const { name, visibility, type_ref, ast_id, has_body: konst.body().is_some() }; + types_map.shrink_to_fit(); + types_source_map.shrink_to_fit(); + let res = Const { + name, + visibility, + type_ref, + ast_id, + has_body: konst.body().is_some(), + types_map: Arc::new(types_map), + }; + self.source_maps.consts.push(types_source_map); id(self.data().consts.alloc(res)) } @@ -539,10 +693,11 @@ impl<'a> Ctx<'a> { .filter_map(|item_node| self.lower_assoc_item(&item_node)) .collect(); - let generic_params = + let (generic_params, generics_source_map) = self.lower_generic_params(HasImplicitSelf::Yes(trait_def.type_bound_list()), trait_def); let def = Trait { name, visibility, generic_params, is_auto, is_unsafe, items, ast_id }; let id = id(self.data().traits.alloc(def)); + self.source_maps.trait_generics.push(generics_source_map); self.write_generic_params_attributes(id.into()); Some(id) } @@ -554,24 +709,29 @@ impl<'a> Ctx<'a> { let name = trait_alias_def.name()?.as_name(); let visibility = self.lower_visibility(trait_alias_def); let ast_id = self.source_ast_id_map.ast_id(trait_alias_def); - let generic_params = self.lower_generic_params( + let (generic_params, generics_source_map) = self.lower_generic_params( HasImplicitSelf::Yes(trait_alias_def.type_bound_list()), trait_alias_def, ); let alias = TraitAlias { name, visibility, generic_params, ast_id }; let id = id(self.data().trait_aliases.alloc(alias)); + self.source_maps.trait_alias_generics.push(generics_source_map); self.write_generic_params_attributes(id.into()); Some(id) } - fn lower_impl(&mut self, impl_def: &ast::Impl) -> Option<FileItemTreeId<Impl>> { + fn lower_impl(&mut self, impl_def: &ast::Impl) -> FileItemTreeId<Impl> { + let (mut types_map, mut types_source_map) = + (TypesMap::default(), TypesSourceMap::default()); + let body_ctx = self.body_ctx(&mut types_map, &mut types_source_map); + let ast_id = self.source_ast_id_map.ast_id(impl_def); // FIXME: If trait lowering fails, due to a non PathType for example, we treat this impl // as if it was an non-trait impl. Ideally we want to create a unique missing ref that only // equals itself. - let self_ty = self.lower_type_ref(&impl_def.self_ty()?); - let target_trait = impl_def.trait_().and_then(|tr| self.lower_trait_ref(&tr)); + let self_ty = TypeRef::from_ast_opt(&body_ctx, impl_def.self_ty()); + let target_trait = impl_def.trait_().and_then(|tr| TraitRef::from_ast(&body_ctx, tr)); let is_negative = impl_def.excl_token().is_some(); let is_unsafe = impl_def.unsafe_token().is_some(); @@ -584,12 +744,27 @@ impl<'a> Ctx<'a> { .collect(); // Note that trait impls don't get implicit `Self` unlike traits, because here they are a // type alias rather than a type parameter, so this is handled by the resolver. - let generic_params = self.lower_generic_params(HasImplicitSelf::No, impl_def); - let res = - Impl { generic_params, target_trait, self_ty, is_negative, is_unsafe, items, ast_id }; + let (generic_params, generics_source_map) = + self.lower_generic_params(HasImplicitSelf::No, impl_def); + types_map.shrink_to_fit(); + types_source_map.shrink_to_fit(); + let res = Impl { + generic_params, + target_trait, + self_ty, + is_negative, + is_unsafe, + items, + ast_id, + types_map: Arc::new(types_map), + }; let id = id(self.data().impls.alloc(res)); + self.source_maps.impls.push(GenericItemSourceMapBuilder { + item: types_source_map, + generics: generics_source_map, + }); self.write_generic_params_attributes(id.into()); - Some(id) + id } fn lower_use(&mut self, use_item: &ast::Use) -> Option<FileItemTreeId<Use>> { @@ -692,14 +867,17 @@ impl<'a> Ctx<'a> { &mut self, has_implicit_self: HasImplicitSelf, node: &dyn ast::HasGenericParams, - ) -> Interned<GenericParams> { + ) -> (Arc<GenericParams>, TypesSourceMap) { + let (mut types_map, mut types_source_map) = + (TypesMap::default(), TypesSourceMap::default()); + let body_ctx = self.body_ctx(&mut types_map, &mut types_source_map); debug_assert!(self.generic_param_attr_buffer.is_empty(),); let add_param_attrs = |item: Either<LocalTypeOrConstParamId, LocalLifetimeParamId>, param| { - let attrs = RawAttrs::new(self.db.upcast(), ¶m, self.body_ctx.span_map()); + let attrs = RawAttrs::new(self.db.upcast(), ¶m, body_ctx.span_map()); debug_assert!(self.generic_param_attr_buffer.insert(item, attrs).is_none()); }; - self.body_ctx.take_impl_traits_bounds(); + body_ctx.take_impl_traits_bounds(); let mut generics = GenericParamsCollector::default(); if let HasImplicitSelf::Yes(bounds) = has_implicit_self { @@ -715,23 +893,29 @@ impl<'a> Ctx<'a> { // add super traits as bounds on Self // i.e., `trait Foo: Bar` is equivalent to `trait Foo where Self: Bar` generics.fill_bounds( - &self.body_ctx, + &body_ctx, bounds, - Either::Left(TypeRef::Path(Name::new_symbol_root(sym::Self_.clone()).into())), + Either::Left(body_ctx.alloc_type_ref_desugared(TypeRef::Path( + Name::new_symbol_root(sym::Self_.clone()).into(), + ))), ); } - generics.fill(&self.body_ctx, node, add_param_attrs); + generics.fill(&body_ctx, node, add_param_attrs); - Interned::new(generics.finish()) + let generics = generics.finish(types_map, &mut types_source_map); + (generics, types_source_map) } - fn lower_type_bounds(&mut self, node: &dyn ast::HasTypeBounds) -> Box<[Interned<TypeBound>]> { + fn lower_type_bounds( + &mut self, + node: &dyn ast::HasTypeBounds, + body_ctx: &LowerCtx<'_>, + ) -> Box<[TypeBound]> { match node.type_bound_list() { - Some(bound_list) => bound_list - .bounds() - .map(|it| Interned::new(TypeBound::from_ast(&self.body_ctx, it))) - .collect(), + Some(bound_list) => { + bound_list.bounds().map(|it| TypeBound::from_ast(body_ctx, it)).collect() + } None => Box::default(), } } @@ -743,23 +927,6 @@ impl<'a> Ctx<'a> { self.data().vis.alloc(vis) } - fn lower_trait_ref(&mut self, trait_ref: &ast::Type) -> Option<Interned<TraitRef>> { - let trait_ref = TraitRef::from_ast(&self.body_ctx, trait_ref.clone())?; - Some(Interned::new(trait_ref)) - } - - fn lower_type_ref(&mut self, type_ref: &ast::Type) -> Interned<TypeRef> { - let tyref = TypeRef::from_ast(&self.body_ctx, type_ref.clone()); - Interned::new(tyref) - } - - fn lower_type_ref_opt(&mut self, type_ref: Option<ast::Type>) -> Interned<TypeRef> { - match type_ref.map(|ty| self.lower_type_ref(&ty)) { - Some(it) => it, - None => Interned::new(TypeRef::Error), - } - } - fn next_variant_idx(&self) -> Idx<Variant> { Idx::from_raw(RawIdx::from( self.tree.data.as_ref().map_or(0, |data| data.variants.len() as u32), @@ -767,7 +934,7 @@ impl<'a> Ctx<'a> { } } -fn desugar_future_path(orig: TypeRef) -> Path { +fn desugar_future_path(orig: TypeRefId) -> Path { let path = path![core::future::Future]; let mut generic_args: Vec<_> = std::iter::repeat(None).take(path.segments().len() - 1).collect(); @@ -777,10 +944,7 @@ fn desugar_future_path(orig: TypeRef) -> Path { type_ref: Some(orig), bounds: Box::default(), }; - generic_args.push(Some(Interned::new(GenericArgs { - bindings: Box::new([binding]), - ..GenericArgs::empty() - }))); + generic_args.push(Some(GenericArgs { bindings: Box::new([binding]), ..GenericArgs::empty() })); Path::from_known_path(path, generic_args) } diff --git a/src/tools/rust-analyzer/crates/hir-def/src/item_tree/pretty.rs b/src/tools/rust-analyzer/crates/hir-def/src/item_tree/pretty.rs index 9dce28b2e49..b6816a1f968 100644 --- a/src/tools/rust-analyzer/crates/hir-def/src/item_tree/pretty.rs +++ b/src/tools/rust-analyzer/crates/hir-def/src/item_tree/pretty.rs @@ -10,11 +10,12 @@ use crate::{ item_tree::{ AttrOwner, Const, DefDatabase, Enum, ExternBlock, ExternCrate, Field, FieldParent, FieldsShape, FileItemTreeId, FnFlags, Function, GenericModItem, GenericParams, Impl, - Interned, ItemTree, Macro2, MacroCall, MacroRules, Mod, ModItem, ModKind, Param, Path, - RawAttrs, RawVisibilityId, Static, Struct, Trait, TraitAlias, TypeAlias, TypeBound, - TypeRef, Union, Use, UseTree, UseTreeKind, Variant, + ItemTree, Macro2, MacroCall, MacroRules, Mod, ModItem, ModKind, Param, Path, RawAttrs, + RawVisibilityId, Static, Struct, Trait, TraitAlias, TypeAlias, TypeBound, Union, Use, + UseTree, UseTreeKind, Variant, }, pretty::{print_path, print_type_bounds, print_type_ref}, + type_ref::{TypeRefId, TypesMap}, visibility::RawVisibility, }; @@ -121,7 +122,13 @@ impl Printer<'_> { }; } - fn print_fields(&mut self, parent: FieldParent, kind: FieldsShape, fields: &[Field]) { + fn print_fields( + &mut self, + parent: FieldParent, + kind: FieldsShape, + fields: &[Field], + map: &TypesMap, + ) { let edition = self.edition; match kind { FieldsShape::Record => { @@ -135,7 +142,7 @@ impl Printer<'_> { ); this.print_visibility(*visibility); w!(this, "{}: ", name.display(self.db.upcast(), edition)); - this.print_type_ref(type_ref); + this.print_type_ref(*type_ref, map); wln!(this, ","); } }); @@ -151,7 +158,7 @@ impl Printer<'_> { ); this.print_visibility(*visibility); w!(this, "{}: ", name.display(self.db.upcast(), edition)); - this.print_type_ref(type_ref); + this.print_type_ref(*type_ref, map); wln!(this, ","); } }); @@ -167,20 +174,21 @@ impl Printer<'_> { kind: FieldsShape, fields: &[Field], params: &GenericParams, + map: &TypesMap, ) { match kind { FieldsShape::Record => { if self.print_where_clause(params) { wln!(self); } - self.print_fields(parent, kind, fields); + self.print_fields(parent, kind, fields, map); } FieldsShape::Unit => { self.print_where_clause(params); - self.print_fields(parent, kind, fields); + self.print_fields(parent, kind, fields, map); } FieldsShape::Tuple => { - self.print_fields(parent, kind, fields); + self.print_fields(parent, kind, fields, map); self.print_where_clause(params); } } @@ -262,6 +270,7 @@ impl Printer<'_> { params, ret_type, ast_id, + types_map, flags, } = &self.tree[it]; self.print_ast_id(ast_id.erase()); @@ -298,7 +307,7 @@ impl Printer<'_> { w!(this, "self: "); } if let Some(type_ref) = type_ref { - this.print_type_ref(type_ref); + this.print_type_ref(*type_ref, types_map); } else { wln!(this, "..."); } @@ -307,7 +316,7 @@ impl Printer<'_> { }); } w!(self, ") -> "); - self.print_type_ref(ret_type); + self.print_type_ref(*ret_type, types_map); self.print_where_clause(explicit_generic_params); if flags.contains(FnFlags::HAS_BODY) { wln!(self, " {{ ... }}"); @@ -316,8 +325,15 @@ impl Printer<'_> { } } ModItem::Struct(it) => { - let Struct { visibility, name, fields, shape: kind, generic_params, ast_id } = - &self.tree[it]; + let Struct { + visibility, + name, + fields, + shape: kind, + generic_params, + ast_id, + types_map, + } = &self.tree[it]; self.print_ast_id(ast_id.erase()); self.print_visibility(*visibility); w!(self, "struct {}", name.display(self.db.upcast(), self.edition)); @@ -327,6 +343,7 @@ impl Printer<'_> { *kind, fields, generic_params, + types_map, ); if matches!(kind, FieldsShape::Record) { wln!(self); @@ -335,7 +352,8 @@ impl Printer<'_> { } } ModItem::Union(it) => { - let Union { name, visibility, fields, generic_params, ast_id } = &self.tree[it]; + let Union { name, visibility, fields, generic_params, ast_id, types_map } = + &self.tree[it]; self.print_ast_id(ast_id.erase()); self.print_visibility(*visibility); w!(self, "union {}", name.display(self.db.upcast(), self.edition)); @@ -345,6 +363,7 @@ impl Printer<'_> { FieldsShape::Record, fields, generic_params, + types_map, ); wln!(self); } @@ -358,18 +377,20 @@ impl Printer<'_> { let edition = self.edition; self.indented(|this| { for variant in FileItemTreeId::range_iter(variants.clone()) { - let Variant { name, fields, shape: kind, ast_id } = &this.tree[variant]; + let Variant { name, fields, shape: kind, ast_id, types_map } = + &this.tree[variant]; this.print_ast_id(ast_id.erase()); this.print_attrs_of(variant, "\n"); w!(this, "{}", name.display(self.db.upcast(), edition)); - this.print_fields(FieldParent::Variant(variant), *kind, fields); + this.print_fields(FieldParent::Variant(variant), *kind, fields, types_map); wln!(this, ","); } }); wln!(self, "}}"); } ModItem::Const(it) => { - let Const { name, visibility, type_ref, ast_id, has_body: _ } = &self.tree[it]; + let Const { name, visibility, type_ref, ast_id, has_body: _, types_map } = + &self.tree[it]; self.print_ast_id(ast_id.erase()); self.print_visibility(*visibility); w!(self, "const "); @@ -378,7 +399,7 @@ impl Printer<'_> { None => w!(self, "_"), } w!(self, ": "); - self.print_type_ref(type_ref); + self.print_type_ref(*type_ref, types_map); wln!(self, " = _;"); } ModItem::Static(it) => { @@ -390,6 +411,7 @@ impl Printer<'_> { ast_id, has_safe_kw, has_unsafe_kw, + types_map, } = &self.tree[it]; self.print_ast_id(ast_id.erase()); self.print_visibility(*visibility); @@ -404,7 +426,7 @@ impl Printer<'_> { w!(self, "mut "); } w!(self, "{}: ", name.display(self.db.upcast(), self.edition)); - self.print_type_ref(type_ref); + self.print_type_ref(*type_ref, types_map); w!(self, " = _;"); wln!(self); } @@ -449,6 +471,7 @@ impl Printer<'_> { items, generic_params, ast_id, + types_map, } = &self.tree[it]; self.print_ast_id(ast_id.erase()); if *is_unsafe { @@ -461,10 +484,10 @@ impl Printer<'_> { w!(self, "!"); } if let Some(tr) = target_trait { - self.print_path(&tr.path); + self.print_path(&tr.path, types_map); w!(self, " for "); } - self.print_type_ref(self_ty); + self.print_type_ref(*self_ty, types_map); self.print_where_clause_and_opening_brace(generic_params); self.indented(|this| { for item in &**items { @@ -474,19 +497,26 @@ impl Printer<'_> { wln!(self, "}}"); } ModItem::TypeAlias(it) => { - let TypeAlias { name, visibility, bounds, type_ref, generic_params, ast_id } = - &self.tree[it]; + let TypeAlias { + name, + visibility, + bounds, + type_ref, + generic_params, + ast_id, + types_map, + } = &self.tree[it]; self.print_ast_id(ast_id.erase()); self.print_visibility(*visibility); w!(self, "type {}", name.display(self.db.upcast(), self.edition)); self.print_generic_params(generic_params, it.into()); if !bounds.is_empty() { w!(self, ": "); - self.print_type_bounds(bounds); + self.print_type_bounds(bounds, types_map); } if let Some(ty) = type_ref { w!(self, " = "); - self.print_type_ref(ty); + self.print_type_ref(*ty, types_map); } self.print_where_clause(generic_params); w!(self, ";"); @@ -543,19 +573,19 @@ impl Printer<'_> { self.blank(); } - fn print_type_ref(&mut self, type_ref: &TypeRef) { + fn print_type_ref(&mut self, type_ref: TypeRefId, map: &TypesMap) { let edition = self.edition; - print_type_ref(self.db, type_ref, self, edition).unwrap(); + print_type_ref(self.db, type_ref, map, self, edition).unwrap(); } - fn print_type_bounds(&mut self, bounds: &[Interned<TypeBound>]) { + fn print_type_bounds(&mut self, bounds: &[TypeBound], map: &TypesMap) { let edition = self.edition; - print_type_bounds(self.db, bounds, self, edition).unwrap(); + print_type_bounds(self.db, bounds, map, self, edition).unwrap(); } - fn print_path(&mut self, path: &Path) { + fn print_path(&mut self, path: &Path, map: &TypesMap) { let edition = self.edition; - print_path(self.db, path, self, edition).unwrap(); + print_path(self.db, path, map, self, edition).unwrap(); } fn print_generic_params(&mut self, params: &GenericParams, parent: GenericModItem) { @@ -586,7 +616,7 @@ impl Printer<'_> { }, TypeOrConstParamData::ConstParamData(konst) => { w!(self, "const {}: ", konst.name.display(self.db.upcast(), self.edition)); - self.print_type_ref(&konst.ty); + self.print_type_ref(konst.ty, ¶ms.types_map); } } } @@ -640,14 +670,16 @@ impl Printer<'_> { }; match target { - WherePredicateTypeTarget::TypeRef(ty) => this.print_type_ref(ty), + WherePredicateTypeTarget::TypeRef(ty) => { + this.print_type_ref(*ty, ¶ms.types_map) + } WherePredicateTypeTarget::TypeOrConstParam(id) => match params[*id].name() { Some(name) => w!(this, "{}", name.display(self.db.upcast(), edition)), None => w!(this, "_anon_{}", id.into_raw()), }, } w!(this, ": "); - this.print_type_bounds(std::slice::from_ref(bound)); + this.print_type_bounds(std::slice::from_ref(bound), ¶ms.types_map); } }); true diff --git a/src/tools/rust-analyzer/crates/hir-def/src/lib.rs b/src/tools/rust-analyzer/crates/hir-def/src/lib.rs index 157c9ef0805..f6ed826f04c 100644 --- a/src/tools/rust-analyzer/crates/hir-def/src/lib.rs +++ b/src/tools/rust-analyzer/crates/hir-def/src/lib.rs @@ -1531,11 +1531,3 @@ fn macro_call_as_call_id_with_eager( pub struct UnresolvedMacro { pub path: hir_expand::mod_path::ModPath, } - -intern::impl_internable!( - crate::type_ref::TypeRef, - crate::type_ref::TraitRef, - crate::type_ref::TypeBound, - crate::path::GenericArgs, - generics::GenericParams, -); diff --git a/src/tools/rust-analyzer/crates/hir-def/src/lower.rs b/src/tools/rust-analyzer/crates/hir-def/src/lower.rs index e4786a1dd40..df5847929c5 100644 --- a/src/tools/rust-analyzer/crates/hir-def/src/lower.rs +++ b/src/tools/rust-analyzer/crates/hir-def/src/lower.rs @@ -5,43 +5,53 @@ use hir_expand::{ span_map::{SpanMap, SpanMapRef}, AstId, HirFileId, InFile, }; -use intern::Interned; use span::{AstIdMap, AstIdNode}; +use stdx::thin_vec::ThinVec; use syntax::ast; use triomphe::Arc; -use crate::{db::DefDatabase, path::Path, type_ref::TypeBound}; +use crate::{ + db::DefDatabase, + path::Path, + type_ref::{TypeBound, TypePtr, TypeRef, TypeRefId, TypesMap, TypesSourceMap}, +}; pub struct LowerCtx<'a> { pub db: &'a dyn DefDatabase, file_id: HirFileId, span_map: OnceCell<SpanMap>, ast_id_map: OnceCell<Arc<AstIdMap>>, - impl_trait_bounds: RefCell<Vec<Vec<Interned<TypeBound>>>>, + impl_trait_bounds: RefCell<Vec<ThinVec<TypeBound>>>, // Prevent nested impl traits like `impl Foo<impl Bar>`. outer_impl_trait: RefCell<bool>, + types_map: RefCell<(&'a mut TypesMap, &'a mut TypesSourceMap)>, } -pub(crate) struct OuterImplTraitGuard<'a> { - ctx: &'a LowerCtx<'a>, +pub(crate) struct OuterImplTraitGuard<'a, 'b> { + ctx: &'a LowerCtx<'b>, old: bool, } -impl<'a> OuterImplTraitGuard<'a> { - fn new(ctx: &'a LowerCtx<'a>, impl_trait: bool) -> Self { +impl<'a, 'b> OuterImplTraitGuard<'a, 'b> { + fn new(ctx: &'a LowerCtx<'b>, impl_trait: bool) -> Self { let old = ctx.outer_impl_trait.replace(impl_trait); Self { ctx, old } } } -impl<'a> Drop for OuterImplTraitGuard<'a> { +impl Drop for OuterImplTraitGuard<'_, '_> { fn drop(&mut self) { self.ctx.outer_impl_trait.replace(self.old); } } impl<'a> LowerCtx<'a> { - pub fn new(db: &'a dyn DefDatabase, file_id: HirFileId) -> Self { + pub fn new( + db: &'a dyn DefDatabase, + file_id: HirFileId, + types_map: &'a mut TypesMap, + types_source_map: &'a mut TypesSourceMap, + ) -> Self { LowerCtx { db, file_id, @@ -49,6 +59,7 @@ impl<'a> LowerCtx<'a> { ast_id_map: OnceCell::new(), impl_trait_bounds: RefCell::new(Vec::new()), outer_impl_trait: RefCell::default(), + types_map: RefCell::new((types_map, types_source_map)), } } @@ -56,6 +67,8 @@ impl<'a> LowerCtx<'a> { db: &'a dyn DefDatabase, file_id: HirFileId, span_map: OnceCell<SpanMap>, + types_map: &'a mut TypesMap, + types_source_map: &'a mut TypesSourceMap, ) -> Self { LowerCtx { db, @@ -64,6 +77,7 @@ impl<'a> LowerCtx<'a> { ast_id_map: OnceCell::new(), impl_trait_bounds: RefCell::new(Vec::new()), outer_impl_trait: RefCell::default(), + types_map: RefCell::new((types_map, types_source_map)), } } @@ -82,11 +96,11 @@ impl<'a> LowerCtx<'a> { ) } - pub fn update_impl_traits_bounds(&self, bounds: Vec<Interned<TypeBound>>) { + pub fn update_impl_traits_bounds(&self, bounds: ThinVec<TypeBound>) { self.impl_trait_bounds.borrow_mut().push(bounds); } - pub fn take_impl_traits_bounds(&self) -> Vec<Vec<Interned<TypeBound>>> { + pub fn take_impl_traits_bounds(&self) -> Vec<ThinVec<TypeBound>> { self.impl_trait_bounds.take() } @@ -94,7 +108,32 @@ impl<'a> LowerCtx<'a> { *self.outer_impl_trait.borrow() } - pub(crate) fn outer_impl_trait_scope(&'a self, impl_trait: bool) -> OuterImplTraitGuard<'a> { + pub(crate) fn outer_impl_trait_scope<'b>( + &'b self, + impl_trait: bool, + ) -> OuterImplTraitGuard<'b, 'a> { OuterImplTraitGuard::new(self, impl_trait) } + + pub(crate) fn alloc_type_ref(&self, type_ref: TypeRef, node: TypePtr) -> TypeRefId { + let mut types_map = self.types_map.borrow_mut(); + let (types_map, types_source_map) = &mut *types_map; + let id = types_map.types.alloc(type_ref); + types_source_map.types_map_back.insert(id, InFile::new(self.file_id, node)); + id + } + + pub(crate) fn alloc_type_ref_desugared(&self, type_ref: TypeRef) -> TypeRefId { + self.types_map.borrow_mut().0.types.alloc(type_ref) + } + + pub(crate) fn alloc_error_type(&self) -> TypeRefId { + self.types_map.borrow_mut().0.types.alloc(TypeRef::Error) + } + + // FIXME: If we alloc while holding this, well... Bad Things will happen. Need to change this + // to use proper mutability instead of interior mutability. + pub(crate) fn types_map(&self) -> std::cell::Ref<'_, TypesMap> { + std::cell::Ref::map(self.types_map.borrow(), |it| &*it.0) + } } diff --git a/src/tools/rust-analyzer/crates/hir-def/src/macro_expansion_tests/mod.rs b/src/tools/rust-analyzer/crates/hir-def/src/macro_expansion_tests/mod.rs index 450a15bd66e..d5b94f0ae44 100644 --- a/src/tools/rust-analyzer/crates/hir-def/src/macro_expansion_tests/mod.rs +++ b/src/tools/rust-analyzer/crates/hir-def/src/macro_expansion_tests/mod.rs @@ -122,7 +122,7 @@ pub fn identity_when_valid(_attr: TokenStream, item: TokenStream) -> TokenStream let mut expn_text = String::new(); if let Some(err) = exp.err { - format_to!(expn_text, "/* error: {} */", err.render_to_string(&db).0); + format_to!(expn_text, "/* error: {} */", err.render_to_string(&db).message); } let (parse, token_map) = exp.value; if expect_errors { diff --git a/src/tools/rust-analyzer/crates/hir-def/src/nameres/collector.rs b/src/tools/rust-analyzer/crates/hir-def/src/nameres/collector.rs index 22b9c2b4e37..a37e3c70e22 100644 --- a/src/tools/rust-analyzer/crates/hir-def/src/nameres/collector.rs +++ b/src/tools/rust-analyzer/crates/hir-def/src/nameres/collector.rs @@ -31,7 +31,7 @@ use crate::{ item_scope::{ImportId, ImportOrExternCrate, ImportType, PerNsGlobImports}, item_tree::{ self, AttrOwner, FieldsShape, FileItemTreeId, ImportKind, ItemTree, ItemTreeId, - ItemTreeNode, Macro2, MacroCall, MacroRules, Mod, ModItem, ModKind, TreeId, + ItemTreeNode, Macro2, MacroCall, MacroRules, Mod, ModItem, ModKind, TreeId, UseTreeKind, }, macro_call_as_call_id, macro_call_as_call_id_with_eager, nameres::{ @@ -985,12 +985,8 @@ impl DefCollector<'_> { for (name, res) in resolutions { match name { Some(name) => { - changed |= self.push_res_and_update_glob_vis( - module_id, - name, - res.with_visibility(vis), - import, - ); + changed |= + self.push_res_and_update_glob_vis(module_id, name, *res, vis, import); } None => { let tr = match res.take_types() { @@ -1043,10 +1039,11 @@ impl DefCollector<'_> { .collect::<Vec<_>>(); for (glob_importing_module, glob_import_vis, use_) in glob_imports { + let vis = glob_import_vis.min(vis, &self.def_map).unwrap_or(glob_import_vis); self.update_recursive( glob_importing_module, resolutions, - glob_import_vis, + vis, Some(ImportType::Glob(use_)), depth + 1, ); @@ -1058,8 +1055,44 @@ impl DefCollector<'_> { module_id: LocalModuleId, name: &Name, mut defs: PerNs, + vis: Visibility, def_import_type: Option<ImportType>, ) -> bool { + // `extern crate crate_name` things can be re-exported as `pub use crate_name`. + // But they cannot be re-exported as `pub use self::crate_name`, `pub use crate::crate_name` + // or `pub use ::crate_name`. + // + // This has been historically allowed, but may be not allowed in future + // https://github.com/rust-lang/rust/issues/127909 + if let Some((_, v, it)) = defs.types.as_mut() { + let is_extern_crate_reimport_without_prefix = || { + let Some(ImportOrExternCrate::ExternCrate(_)) = it else { + return false; + }; + let Some(ImportType::Import(id)) = def_import_type else { + return false; + }; + let use_id = id.import.lookup(self.db).id; + let item_tree = use_id.item_tree(self.db); + let use_kind = item_tree[use_id.value].use_tree.kind(); + let UseTreeKind::Single { path, .. } = use_kind else { + return false; + }; + path.segments().len() < 2 + }; + if is_extern_crate_reimport_without_prefix() { + *v = vis; + } else { + *v = v.min(vis, &self.def_map).unwrap_or(vis); + } + } + if let Some((_, v, _)) = defs.values.as_mut() { + *v = v.min(vis, &self.def_map).unwrap_or(vis); + } + if let Some((_, v, _)) = defs.macros.as_mut() { + *v = v.min(vis, &self.def_map).unwrap_or(vis); + } + let mut changed = false; if let Some(ImportType::Glob(_)) = def_import_type { diff --git a/src/tools/rust-analyzer/crates/hir-def/src/nameres/path_resolution.rs b/src/tools/rust-analyzer/crates/hir-def/src/nameres/path_resolution.rs index 75cab137f78..29379d00749 100644 --- a/src/tools/rust-analyzer/crates/hir-def/src/nameres/path_resolution.rs +++ b/src/tools/rust-analyzer/crates/hir-def/src/nameres/path_resolution.rs @@ -10,6 +10,7 @@ //! //! `ReachedFixedPoint` signals about this. +use either::Either; use hir_expand::{name::Name, Lookup}; use span::Edition; use triomphe::Arc; @@ -150,17 +151,8 @@ impl DefMap { let mut arc; let mut current_map = self; - loop { - let new = current_map.resolve_path_fp_with_macro_single( - db, - mode, - original_module, - path, - shadow, - expected_macro_subns, - ); - // Merge `new` into `result`. + let mut merge = |new: ResolvePathResult| { result.resolved_def = result.resolved_def.or(new.resolved_def); if result.reached_fixedpoint == ReachedFixedPoint::No { result.reached_fixedpoint = new.reached_fixedpoint; @@ -171,7 +163,9 @@ impl DefMap { (Some(old), Some(new)) => Some(old.max(new)), (None, new) => new, }; + }; + loop { match current_map.block { Some(block) if original_module == Self::ROOT => { // Block modules "inherit" names from its parent module. @@ -180,8 +174,38 @@ impl DefMap { current_map = &arc; } // Proper (non-block) modules, including those in block `DefMap`s, don't. - _ => return result, + _ => { + if original_module != Self::ROOT && current_map.block.is_some() { + // A module inside a block. Do not resolve items declared in upper blocks, but we do need to get + // the prelude items (which are not inserted into blocks because they can be overridden there). + original_module = Self::ROOT; + arc = db.crate_def_map(self.krate); + current_map = &arc; + + let new = current_map.resolve_path_fp_in_all_preludes( + db, + mode, + original_module, + path, + shadow, + ); + merge(new); + } + + return result; + } } + + let new = current_map.resolve_path_fp_with_macro_single( + db, + mode, + original_module, + path, + shadow, + expected_macro_subns, + ); + + merge(new); } } @@ -195,7 +219,7 @@ impl DefMap { expected_macro_subns: Option<MacroSubNs>, ) -> ResolvePathResult { let mut segments = path.segments().iter().enumerate(); - let mut curr_per_ns = match path.kind { + let curr_per_ns = match path.kind { PathKind::DollarCrate(krate) => { if krate == self.krate { cov_mark::hit!(macro_dollar_crate_self); @@ -296,25 +320,96 @@ impl DefMap { PerNs::types(module.into(), Visibility::Public, None) } - PathKind::Abs => { - // 2018-style absolute path -- only extern prelude - let segment = match segments.next() { - Some((_, segment)) => segment, + PathKind::Abs => match self.resolve_path_abs(&mut segments, path) { + Either::Left(it) => it, + Either::Right(reached_fixed_point) => { + return ResolvePathResult::empty(reached_fixed_point) + } + }, + }; + + self.resolve_remaining_segments(segments, curr_per_ns, path, db, shadow, original_module) + } + + /// Resolves a path only in the preludes, without accounting for item scopes. + pub(super) fn resolve_path_fp_in_all_preludes( + &self, + db: &dyn DefDatabase, + mode: ResolveMode, + original_module: LocalModuleId, + path: &ModPath, + shadow: BuiltinShadowMode, + ) -> ResolvePathResult { + let mut segments = path.segments().iter().enumerate(); + let curr_per_ns = match path.kind { + // plain import or absolute path in 2015: crate-relative with + // fallback to extern prelude (with the simplification in + // rust-lang/rust#57745) + // FIXME there must be a nicer way to write this condition + PathKind::Plain | PathKind::Abs + if self.data.edition == Edition::Edition2015 + && (path.kind == PathKind::Abs || mode == ResolveMode::Import) => + { + let (_, segment) = match segments.next() { + Some((idx, segment)) => (idx, segment), None => return ResolvePathResult::empty(ReachedFixedPoint::Yes), }; - if let Some(&(def, extern_crate)) = self.data.extern_prelude.get(segment) { - tracing::debug!("absolute path {:?} resolved to crate {:?}", path, def); - PerNs::types( - def.into(), - Visibility::Public, - extern_crate.map(ImportOrExternCrate::ExternCrate), - ) - } else { - return ResolvePathResult::empty(ReachedFixedPoint::No); // extern crate declarations can add to the extern prelude + tracing::debug!("resolving {:?} in crate root (+ extern prelude)", segment); + self.resolve_name_in_extern_prelude(segment) + } + PathKind::Plain => { + let (_, segment) = match segments.next() { + Some((idx, segment)) => (idx, segment), + None => return ResolvePathResult::empty(ReachedFixedPoint::Yes), + }; + tracing::debug!("resolving {:?} in module", segment); + self.resolve_name_in_all_preludes(db, segment) + } + PathKind::Abs => match self.resolve_path_abs(&mut segments, path) { + Either::Left(it) => it, + Either::Right(reached_fixed_point) => { + return ResolvePathResult::empty(reached_fixed_point) } + }, + PathKind::DollarCrate(_) | PathKind::Crate | PathKind::Super(_) => { + return ResolvePathResult::empty(ReachedFixedPoint::Yes) } }; + self.resolve_remaining_segments(segments, curr_per_ns, path, db, shadow, original_module) + } + + /// 2018-style absolute path -- only extern prelude + fn resolve_path_abs<'a>( + &self, + segments: &mut impl Iterator<Item = (usize, &'a Name)>, + path: &ModPath, + ) -> Either<PerNs, ReachedFixedPoint> { + let segment = match segments.next() { + Some((_, segment)) => segment, + None => return Either::Right(ReachedFixedPoint::Yes), + }; + if let Some(&(def, extern_crate)) = self.data.extern_prelude.get(segment) { + tracing::debug!("absolute path {:?} resolved to crate {:?}", path, def); + Either::Left(PerNs::types( + def.into(), + Visibility::Public, + extern_crate.map(ImportOrExternCrate::ExternCrate), + )) + } else { + Either::Right(ReachedFixedPoint::No) // extern crate declarations can add to the extern prelude + } + } + + fn resolve_remaining_segments<'a>( + &self, + segments: impl Iterator<Item = (usize, &'a Name)>, + mut curr_per_ns: PerNs, + path: &ModPath, + db: &dyn DefDatabase, + shadow: BuiltinShadowMode, + original_module: LocalModuleId, + ) -> ResolvePathResult { for (i, segment) in segments { let (curr, vis, imp) = match curr_per_ns.take_types_full() { Some(r) => r, @@ -475,24 +570,9 @@ impl DefMap { // they might been shadowed by local names. return PerNs::none(); } - self.data.extern_prelude.get(name).map_or(PerNs::none(), |&(it, extern_crate)| { - PerNs::types( - it.into(), - Visibility::Public, - extern_crate.map(ImportOrExternCrate::ExternCrate), - ) - }) - }; - let macro_use_prelude = || { - self.macro_use_prelude.get(name).map_or(PerNs::none(), |&(it, _extern_crate)| { - PerNs::macros( - it, - Visibility::Public, - // FIXME? - None, // extern_crate.map(ImportOrExternCrate::ExternCrate), - ) - }) + self.resolve_name_in_extern_prelude(name) }; + let macro_use_prelude = || self.resolve_in_macro_use_prelude(name); let prelude = || { if self.block.is_some() && module == DefMap::ROOT { return PerNs::none(); @@ -507,6 +587,38 @@ impl DefMap { .or_else(prelude) } + fn resolve_name_in_all_preludes(&self, db: &dyn DefDatabase, name: &Name) -> PerNs { + // Resolve in: + // - extern prelude / macro_use prelude + // - std prelude + let extern_prelude = self.resolve_name_in_extern_prelude(name); + let macro_use_prelude = || self.resolve_in_macro_use_prelude(name); + let prelude = || self.resolve_in_prelude(db, name); + + extern_prelude.or_else(macro_use_prelude).or_else(prelude) + } + + fn resolve_name_in_extern_prelude(&self, name: &Name) -> PerNs { + self.data.extern_prelude.get(name).map_or(PerNs::none(), |&(it, extern_crate)| { + PerNs::types( + it.into(), + Visibility::Public, + extern_crate.map(ImportOrExternCrate::ExternCrate), + ) + }) + } + + fn resolve_in_macro_use_prelude(&self, name: &Name) -> PerNs { + self.macro_use_prelude.get(name).map_or(PerNs::none(), |&(it, _extern_crate)| { + PerNs::macros( + it, + Visibility::Public, + // FIXME? + None, // extern_crate.map(ImportOrExternCrate::ExternCrate), + ) + }) + } + fn resolve_name_in_crate_root_or_extern_prelude( &self, db: &dyn DefDatabase, @@ -525,16 +637,7 @@ impl DefMap { // Don't resolve extern prelude in pseudo-module of a block. return PerNs::none(); } - self.data.extern_prelude.get(name).copied().map_or( - PerNs::none(), - |(it, extern_crate)| { - PerNs::types( - it.into(), - Visibility::Public, - extern_crate.map(ImportOrExternCrate::ExternCrate), - ) - }, - ) + self.resolve_name_in_extern_prelude(name) }; from_crate_root.or_else(from_extern_prelude) diff --git a/src/tools/rust-analyzer/crates/hir-def/src/nameres/tests.rs b/src/tools/rust-analyzer/crates/hir-def/src/nameres/tests.rs index 7b02a89e5de..e1e30e5cec9 100644 --- a/src/tools/rust-analyzer/crates/hir-def/src/nameres/tests.rs +++ b/src/tools/rust-analyzer/crates/hir-def/src/nameres/tests.rs @@ -386,6 +386,52 @@ pub struct Arc; } #[test] +fn extern_crate_reexport() { + check( + r#" +//- /main.rs crate:main deps:importer +use importer::*; +use importer::extern_crate1::exported::*; +use importer::allowed_reexport::*; +use importer::extern_crate2::*; +use importer::not_allowed_reexport1; +use importer::not_allowed_reexport2; + +//- /importer.rs crate:importer deps:extern_crate1,extern_crate2 +extern crate extern_crate1; +extern crate extern_crate2; + +pub use extern_crate1; +pub use extern_crate1 as allowed_reexport; + +pub use ::extern_crate; +pub use self::extern_crate as not_allowed_reexport1; +pub use crate::extern_crate as not_allowed_reexport2; + +//- /extern_crate1.rs crate:extern_crate1 +pub mod exported { + pub struct PublicItem; + struct PrivateItem; +} + +pub struct Exported; + +//- /extern_crate2.rs crate:extern_crate2 +pub struct NotExported; +"#, + expect![[r#" + crate + Exported: t v + PublicItem: t v + allowed_reexport: t + exported: t + not_allowed_reexport1: _ + not_allowed_reexport2: _ + "#]], + ); +} + +#[test] fn extern_crate_rename_2015_edition() { check( r#" diff --git a/src/tools/rust-analyzer/crates/hir-def/src/nameres/tests/globs.rs b/src/tools/rust-analyzer/crates/hir-def/src/nameres/tests/globs.rs index a2696055ca1..543ab41cd59 100644 --- a/src/tools/rust-analyzer/crates/hir-def/src/nameres/tests/globs.rs +++ b/src/tools/rust-analyzer/crates/hir-def/src/nameres/tests/globs.rs @@ -412,3 +412,42 @@ use reexport::*; "#]], ); } + +#[test] +fn regression_18308() { + check( + r#" +use outer::*; + +mod outer { + mod inner_superglob { + pub use super::*; + } + + // The importing order matters! + pub use inner_superglob::*; + use super::glob_target::*; +} + +mod glob_target { + pub struct ShouldBePrivate; +} +"#, + expect![[r#" + crate + glob_target: t + outer: t + + crate::glob_target + ShouldBePrivate: t v + + crate::outer + ShouldBePrivate: t v + inner_superglob: t + + crate::outer::inner_superglob + ShouldBePrivate: t v + inner_superglob: t + "#]], + ); +} diff --git a/src/tools/rust-analyzer/crates/hir-def/src/nameres/tests/incremental.rs b/src/tools/rust-analyzer/crates/hir-def/src/nameres/tests/incremental.rs index d319831867c..d920c108266 100644 --- a/src/tools/rust-analyzer/crates/hir-def/src/nameres/tests/incremental.rs +++ b/src/tools/rust-analyzer/crates/hir-def/src/nameres/tests/incremental.rs @@ -253,7 +253,8 @@ m!(Z); let (_, module_data) = crate_def_map.modules.iter().last().unwrap(); assert_eq!(module_data.scope.resolutions().count(), 4); }); - let n_recalculated_item_trees = events.iter().filter(|it| it.contains("item_tree")).count(); + let n_recalculated_item_trees = + events.iter().filter(|it| it.contains("item_tree(")).count(); assert_eq!(n_recalculated_item_trees, 6); let n_reparsed_macros = events.iter().filter(|it| it.contains("parse_macro_expansion(")).count(); @@ -308,7 +309,7 @@ pub type Ty = (); let events = db.log_executed(|| { db.file_item_tree(pos.file_id.into()); }); - let n_calculated_item_trees = events.iter().filter(|it| it.contains("item_tree")).count(); + let n_calculated_item_trees = events.iter().filter(|it| it.contains("item_tree(")).count(); assert_eq!(n_calculated_item_trees, 1); let n_parsed_files = events.iter().filter(|it| it.contains("parse(")).count(); assert_eq!(n_parsed_files, 1); diff --git a/src/tools/rust-analyzer/crates/hir-def/src/path.rs b/src/tools/rust-analyzer/crates/hir-def/src/path.rs index 077863c0c93..dc6947c5b56 100644 --- a/src/tools/rust-analyzer/crates/hir-def/src/path.rs +++ b/src/tools/rust-analyzer/crates/hir-def/src/path.rs @@ -9,11 +9,12 @@ use std::{ use crate::{ lang_item::LangItemTarget, lower::LowerCtx, - type_ref::{ConstRef, LifetimeRef, TypeBound, TypeRef}, + type_ref::{ConstRef, LifetimeRef, TypeBound, TypeRefId}, }; use hir_expand::name::Name; use intern::Interned; use span::Edition; +use stdx::thin_vec::thin_vec_with_header_struct; use syntax::ast; pub use hir_expand::mod_path::{path, ModPath, PathKind}; @@ -47,20 +48,33 @@ impl Display for ImportAliasDisplay<'_> { #[derive(Debug, Clone, PartialEq, Eq, Hash)] pub enum Path { - /// A normal path - Normal { - /// Type based path like `<T>::foo`. - /// Note that paths like `<Type as Trait>::foo` are desugared to `Trait::<Self=Type>::foo`. - type_anchor: Option<Interned<TypeRef>>, - mod_path: Interned<ModPath>, - /// Invariant: the same len as `self.mod_path.segments` or `None` if all segments are `None`. - generic_args: Option<Box<[Option<Interned<GenericArgs>>]>>, - }, + /// `BarePath` is used when the path has neither generics nor type anchor, since the vast majority of paths + /// are in this category, and splitting `Path` this way allows it to be more thin. When the path has either generics + /// or type anchor, it is `Path::Normal` with the generics filled with `None` even if there are none (practically + /// this is not a problem since many more paths have generics than a type anchor). + BarePath(Interned<ModPath>), + /// `Path::Normal` may have empty generics and type anchor (but generic args will be filled with `None`). + Normal(NormalPath), /// A link to a lang item. It is used in desugaring of things like `it?`. We can show these /// links via a normal path since they might be private and not accessible in the usage place. LangItem(LangItemTarget, Option<Name>), } +// This type is being used a lot, make sure it doesn't grow unintentionally. +#[cfg(target_arch = "x86_64")] +const _: () = { + assert!(size_of::<Path>() == 16); + assert!(size_of::<Option<Path>>() == 16); +}; + +thin_vec_with_header_struct! { + pub new(pub(crate)) struct NormalPath, NormalPathHeader { + pub generic_args: [Option<GenericArgs>], + pub type_anchor: Option<TypeRefId>, + pub mod_path: Interned<ModPath>; ref, + } +} + /// Generic arguments to a path segment (e.g. the `i32` in `Option<i32>`). This /// also includes bindings of associated types, like in `Iterator<Item = Foo>`. #[derive(Debug, Clone, PartialEq, Eq, Hash)] @@ -86,20 +100,20 @@ pub struct AssociatedTypeBinding { pub name: Name, /// The generic arguments to the associated type. e.g. For `Trait<Assoc<'a, T> = &'a T>`, this /// would be `['a, T]`. - pub args: Option<Interned<GenericArgs>>, + pub args: Option<GenericArgs>, /// The type bound to this associated type (in `Item = T`, this would be the /// `T`). This can be `None` if there are bounds instead. - pub type_ref: Option<TypeRef>, + pub type_ref: Option<TypeRefId>, /// Bounds for the associated type, like in `Iterator<Item: /// SomeOtherTrait>`. (This is the unstable `associated_type_bounds` /// feature.) - pub bounds: Box<[Interned<TypeBound>]>, + pub bounds: Box<[TypeBound]>, } /// A single generic argument. #[derive(Debug, Clone, PartialEq, Eq, Hash)] pub enum GenericArg { - Type(TypeRef), + Type(TypeRefId), Lifetime(LifetimeRef), Const(ConstRef), } @@ -112,50 +126,49 @@ impl Path { } /// Converts a known mod path to `Path`. - pub fn from_known_path( - path: ModPath, - generic_args: impl Into<Box<[Option<Interned<GenericArgs>>]>>, - ) -> Path { - let generic_args = generic_args.into(); - assert_eq!(path.len(), generic_args.len()); - Path::Normal { - type_anchor: None, - mod_path: Interned::new(path), - generic_args: Some(generic_args), - } + pub fn from_known_path(path: ModPath, generic_args: Vec<Option<GenericArgs>>) -> Path { + Path::Normal(NormalPath::new(None, Interned::new(path), generic_args)) } /// Converts a known mod path to `Path`. pub fn from_known_path_with_no_generic(path: ModPath) -> Path { - Path::Normal { type_anchor: None, mod_path: Interned::new(path), generic_args: None } + Path::BarePath(Interned::new(path)) } + #[inline] pub fn kind(&self) -> &PathKind { match self { - Path::Normal { mod_path, .. } => &mod_path.kind, + Path::BarePath(mod_path) => &mod_path.kind, + Path::Normal(path) => &path.mod_path().kind, Path::LangItem(..) => &PathKind::Abs, } } - pub fn type_anchor(&self) -> Option<&TypeRef> { + #[inline] + pub fn type_anchor(&self) -> Option<TypeRefId> { match self { - Path::Normal { type_anchor, .. } => type_anchor.as_deref(), - Path::LangItem(..) => None, + Path::Normal(path) => path.type_anchor(), + Path::LangItem(..) | Path::BarePath(_) => None, + } + } + + #[inline] + pub fn generic_args(&self) -> Option<&[Option<GenericArgs>]> { + match self { + Path::Normal(path) => Some(path.generic_args()), + Path::LangItem(..) | Path::BarePath(_) => None, } } pub fn segments(&self) -> PathSegments<'_> { match self { - Path::Normal { mod_path, generic_args, .. } => { - let s = PathSegments { - segments: mod_path.segments(), - generic_args: generic_args.as_deref(), - }; - if let Some(generic_args) = s.generic_args { - assert_eq!(s.segments.len(), generic_args.len()); - } - s + Path::BarePath(mod_path) => { + PathSegments { segments: mod_path.segments(), generic_args: None } } + Path::Normal(path) => PathSegments { + segments: path.mod_path().segments(), + generic_args: Some(path.generic_args()), + }, Path::LangItem(_, seg) => PathSegments { segments: seg.as_ref().map_or(&[], |seg| std::slice::from_ref(seg)), generic_args: None, @@ -165,34 +178,55 @@ impl Path { pub fn mod_path(&self) -> Option<&ModPath> { match self { - Path::Normal { mod_path, .. } => Some(mod_path), + Path::BarePath(mod_path) => Some(mod_path), + Path::Normal(path) => Some(path.mod_path()), Path::LangItem(..) => None, } } pub fn qualifier(&self) -> Option<Path> { - let Path::Normal { mod_path, generic_args, type_anchor } = self else { - return None; - }; - if mod_path.is_ident() { - return None; + match self { + Path::BarePath(mod_path) => { + if mod_path.is_ident() { + return None; + } + Some(Path::BarePath(Interned::new(ModPath::from_segments( + mod_path.kind, + mod_path.segments()[..mod_path.segments().len() - 1].iter().cloned(), + )))) + } + Path::Normal(path) => { + let mod_path = path.mod_path(); + if mod_path.is_ident() { + return None; + } + let type_anchor = path.type_anchor(); + let generic_args = path.generic_args(); + let qualifier_mod_path = Interned::new(ModPath::from_segments( + mod_path.kind, + mod_path.segments()[..mod_path.segments().len() - 1].iter().cloned(), + )); + let qualifier_generic_args = &generic_args[..generic_args.len() - 1]; + Some(Path::Normal(NormalPath::new( + type_anchor, + qualifier_mod_path, + qualifier_generic_args.iter().cloned(), + ))) + } + Path::LangItem(..) => None, } - let res = Path::Normal { - type_anchor: type_anchor.clone(), - mod_path: Interned::new(ModPath::from_segments( - mod_path.kind, - mod_path.segments()[..mod_path.segments().len() - 1].iter().cloned(), - )), - generic_args: generic_args.as_ref().map(|it| it[..it.len() - 1].to_vec().into()), - }; - Some(res) } pub fn is_self_type(&self) -> bool { - let Path::Normal { mod_path, generic_args, type_anchor } = self else { - return false; - }; - type_anchor.is_none() && generic_args.as_deref().is_none() && mod_path.is_Self() + match self { + Path::BarePath(mod_path) => mod_path.is_Self(), + Path::Normal(path) => { + path.type_anchor().is_none() + && path.mod_path().is_Self() + && path.generic_args().iter().all(|args| args.is_none()) + } + Path::LangItem(..) => false, + } } } @@ -204,7 +238,7 @@ pub struct PathSegment<'a> { pub struct PathSegments<'a> { segments: &'a [Name], - generic_args: Option<&'a [Option<Interned<GenericArgs>>]>, + generic_args: Option<&'a [Option<GenericArgs>]>, } impl<'a> PathSegments<'a> { @@ -224,7 +258,7 @@ impl<'a> PathSegments<'a> { pub fn get(&self, idx: usize) -> Option<PathSegment<'a>> { let res = PathSegment { name: self.segments.get(idx)?, - args_and_bindings: self.generic_args.and_then(|it| it.get(idx)?.as_deref()), + args_and_bindings: self.generic_args.and_then(|it| it.get(idx)?.as_ref()), }; Some(res) } @@ -244,7 +278,7 @@ impl<'a> PathSegments<'a> { self.segments .iter() .zip(self.generic_args.into_iter().flatten().chain(iter::repeat(&None))) - .map(|(name, args)| PathSegment { name, args_and_bindings: args.as_deref() }) + .map(|(name, args)| PathSegment { name, args_and_bindings: args.as_ref() }) } } @@ -268,16 +302,6 @@ impl GenericArgs { impl From<Name> for Path { fn from(name: Name) -> Path { - Path::Normal { - type_anchor: None, - mod_path: Interned::new(ModPath::from_segments(PathKind::Plain, iter::once(name))), - generic_args: None, - } - } -} - -impl From<Name> for Box<Path> { - fn from(name: Name) -> Box<Path> { - Box::new(Path::from(name)) + Path::BarePath(Interned::new(ModPath::from_segments(PathKind::Plain, iter::once(name)))) } } diff --git a/src/tools/rust-analyzer/crates/hir-def/src/path/lower.rs b/src/tools/rust-analyzer/crates/hir-def/src/path/lower.rs index 70918a9358e..c328b9c6ce2 100644 --- a/src/tools/rust-analyzer/crates/hir-def/src/path/lower.rs +++ b/src/tools/rust-analyzer/crates/hir-def/src/path/lower.rs @@ -2,13 +2,14 @@ use std::iter; -use crate::{lower::LowerCtx, type_ref::ConstRef}; +use crate::{lower::LowerCtx, path::NormalPath, type_ref::ConstRef}; use hir_expand::{ mod_path::resolve_crate_root, name::{AsName, Name}, }; use intern::{sym, Interned}; +use stdx::thin_vec::EmptyOptimizedThinVec; use syntax::ast::{self, AstNode, HasGenericArgs, HasTypeBounds}; use crate::{ @@ -51,8 +52,7 @@ pub(super) fn lower_path(ctx: &LowerCtx<'_>, mut path: ast::Path) -> Option<Path segment.param_list(), segment.ret_type(), ) - }) - .map(Interned::new); + }); if args.is_some() { generic_args.resize(segments.len(), None); generic_args.push(args); @@ -70,16 +70,14 @@ pub(super) fn lower_path(ctx: &LowerCtx<'_>, mut path: ast::Path) -> Option<Path match trait_ref { // <T>::foo None => { - type_anchor = Some(Interned::new(self_type)); + type_anchor = Some(self_type); kind = PathKind::Plain; } // <T as Trait<A>>::Foo desugars to Trait<Self=T, A>::Foo Some(trait_ref) => { - let Path::Normal { mod_path, generic_args: path_generic_args, .. } = - Path::from_src(ctx, trait_ref.path()?)? - else { - return None; - }; + let path = Path::from_src(ctx, trait_ref.path()?)?; + let mod_path = path.mod_path()?; + let path_generic_args = path.generic_args(); let num_segments = mod_path.segments().len(); kind = mod_path.kind; @@ -95,7 +93,7 @@ pub(super) fn lower_path(ctx: &LowerCtx<'_>, mut path: ast::Path) -> Option<Path // Insert the type reference (T in the above example) as Self parameter for the trait let last_segment = generic_args.get_mut(segments.len() - num_segments)?; - *last_segment = Some(Interned::new(match last_segment.take() { + *last_segment = Some(match last_segment.take() { Some(it) => GenericArgs { args: iter::once(self_type) .chain(it.args.iter().cloned()) @@ -110,7 +108,7 @@ pub(super) fn lower_path(ctx: &LowerCtx<'_>, mut path: ast::Path) -> Option<Path has_self_type: true, ..GenericArgs::empty() }, - })); + }); } } } @@ -137,7 +135,7 @@ pub(super) fn lower_path(ctx: &LowerCtx<'_>, mut path: ast::Path) -> Option<Path }; } segments.reverse(); - if !generic_args.is_empty() { + if !generic_args.is_empty() || type_anchor.is_some() { generic_args.resize(segments.len(), None); generic_args.reverse(); } @@ -166,11 +164,11 @@ pub(super) fn lower_path(ctx: &LowerCtx<'_>, mut path: ast::Path) -> Option<Path } let mod_path = Interned::new(ModPath::from_segments(kind, segments)); - return Some(Path::Normal { - type_anchor, - mod_path, - generic_args: if generic_args.is_empty() { None } else { Some(generic_args.into()) }, - }); + if type_anchor.is_none() && generic_args.is_empty() { + return Some(Path::BarePath(mod_path)); + } else { + return Some(Path::Normal(NormalPath::new(type_anchor, mod_path, generic_args))); + } fn qualifier(path: &ast::Path) -> Option<ast::Path> { if let Some(q) = path.qualifier() { @@ -194,11 +192,13 @@ pub(super) fn lower_generic_args( match generic_arg { ast::GenericArg::TypeArg(type_arg) => { let type_ref = TypeRef::from_ast_opt(lower_ctx, type_arg.ty()); - type_ref.walk(&mut |tr| { + let types_map = lower_ctx.types_map(); + TypeRef::walk(type_ref, &types_map, &mut |tr| { if let TypeRef::ImplTrait(bounds) = tr { lower_ctx.update_impl_traits_bounds(bounds.clone()); } }); + drop(types_map); args.push(GenericArg::Type(type_ref)); } ast::GenericArg::AssocTypeArg(assoc_type_arg) => { @@ -212,20 +212,19 @@ pub(super) fn lower_generic_args( let name = name_ref.as_name(); let args = assoc_type_arg .generic_arg_list() - .and_then(|args| lower_generic_args(lower_ctx, args)) - .map(Interned::new); + .and_then(|args| lower_generic_args(lower_ctx, args)); let type_ref = assoc_type_arg.ty().map(|it| TypeRef::from_ast(lower_ctx, it)); - let type_ref = type_ref.inspect(|tr| { - tr.walk(&mut |tr| { + let type_ref = type_ref.inspect(|&tr| { + let types_map = lower_ctx.types_map(); + TypeRef::walk(tr, &types_map, &mut |tr| { if let TypeRef::ImplTrait(bounds) = tr { lower_ctx.update_impl_traits_bounds(bounds.clone()); } }); + drop(types_map); }); let bounds = if let Some(l) = assoc_type_arg.type_bound_list() { - l.bounds() - .map(|it| Interned::new(TypeBound::from_ast(lower_ctx, it))) - .collect() + l.bounds().map(|it| TypeBound::from_ast(lower_ctx, it)).collect() } else { Box::default() }; @@ -269,7 +268,9 @@ fn lower_generic_args_from_fn_path( let type_ref = TypeRef::from_ast_opt(ctx, param.ty()); param_types.push(type_ref); } - let args = Box::new([GenericArg::Type(TypeRef::Tuple(param_types))]); + let args = Box::new([GenericArg::Type( + ctx.alloc_type_ref_desugared(TypeRef::Tuple(EmptyOptimizedThinVec::from_iter(param_types))), + )]); let bindings = if let Some(ret_type) = ret_type { let type_ref = TypeRef::from_ast_opt(ctx, ret_type.ty()); Box::new([AssociatedTypeBinding { @@ -280,7 +281,7 @@ fn lower_generic_args_from_fn_path( }]) } else { // -> () - let type_ref = TypeRef::Tuple(Vec::new()); + let type_ref = ctx.alloc_type_ref_desugared(TypeRef::unit()); Box::new([AssociatedTypeBinding { name: Name::new_symbol_root(sym::Output.clone()), args: None, diff --git a/src/tools/rust-analyzer/crates/hir-def/src/pretty.rs b/src/tools/rust-analyzer/crates/hir-def/src/pretty.rs index d5ef17a91fb..9ceb82d5fd6 100644 --- a/src/tools/rust-analyzer/crates/hir-def/src/pretty.rs +++ b/src/tools/rust-analyzer/crates/hir-def/src/pretty.rs @@ -1,9 +1,11 @@ //! Display and pretty printing routines. -use std::fmt::{self, Write}; +use std::{ + fmt::{self, Write}, + mem, +}; use hir_expand::mod_path::PathKind; -use intern::Interned; use itertools::Itertools; use span::Edition; @@ -11,12 +13,15 @@ use crate::{ db::DefDatabase, lang_item::LangItemTarget, path::{GenericArg, GenericArgs, Path}, - type_ref::{Mutability, TraitBoundModifier, TypeBound, TypeRef}, + type_ref::{ + Mutability, TraitBoundModifier, TypeBound, TypeRef, TypeRefId, TypesMap, UseArgRef, + }, }; pub(crate) fn print_path( db: &dyn DefDatabase, path: &Path, + map: &TypesMap, buf: &mut dyn Write, edition: Edition, ) -> fmt::Result { @@ -58,7 +63,7 @@ pub(crate) fn print_path( match path.type_anchor() { Some(anchor) => { write!(buf, "<")?; - print_type_ref(db, anchor, buf, edition)?; + print_type_ref(db, anchor, map, buf, edition)?; write!(buf, ">::")?; } None => match path.kind() { @@ -87,7 +92,7 @@ pub(crate) fn print_path( write!(buf, "{}", segment.name.display(db.upcast(), edition))?; if let Some(generics) = segment.args_and_bindings { write!(buf, "::<")?; - print_generic_args(db, generics, buf, edition)?; + print_generic_args(db, generics, map, buf, edition)?; write!(buf, ">")?; } @@ -99,6 +104,7 @@ pub(crate) fn print_path( pub(crate) fn print_generic_args( db: &dyn DefDatabase, generics: &GenericArgs, + map: &TypesMap, buf: &mut dyn Write, edition: Edition, ) -> fmt::Result { @@ -106,7 +112,7 @@ pub(crate) fn print_generic_args( let args = if generics.has_self_type { let (self_ty, args) = generics.args.split_first().unwrap(); write!(buf, "Self=")?; - print_generic_arg(db, self_ty, buf, edition)?; + print_generic_arg(db, self_ty, map, buf, edition)?; first = false; args } else { @@ -117,7 +123,7 @@ pub(crate) fn print_generic_args( write!(buf, ", ")?; } first = false; - print_generic_arg(db, arg, buf, edition)?; + print_generic_arg(db, arg, map, buf, edition)?; } for binding in generics.bindings.iter() { if !first { @@ -127,11 +133,11 @@ pub(crate) fn print_generic_args( write!(buf, "{}", binding.name.display(db.upcast(), edition))?; if !binding.bounds.is_empty() { write!(buf, ": ")?; - print_type_bounds(db, &binding.bounds, buf, edition)?; + print_type_bounds(db, &binding.bounds, map, buf, edition)?; } - if let Some(ty) = &binding.type_ref { + if let Some(ty) = binding.type_ref { write!(buf, " = ")?; - print_type_ref(db, ty, buf, edition)?; + print_type_ref(db, ty, map, buf, edition)?; } } Ok(()) @@ -140,11 +146,12 @@ pub(crate) fn print_generic_args( pub(crate) fn print_generic_arg( db: &dyn DefDatabase, arg: &GenericArg, + map: &TypesMap, buf: &mut dyn Write, edition: Edition, ) -> fmt::Result { match arg { - GenericArg::Type(ty) => print_type_ref(db, ty, buf, edition), + GenericArg::Type(ty) => print_type_ref(db, *ty, map, buf, edition), GenericArg::Const(c) => write!(buf, "{}", c.display(db.upcast(), edition)), GenericArg::Lifetime(lt) => write!(buf, "{}", lt.name.display(db.upcast(), edition)), } @@ -152,12 +159,13 @@ pub(crate) fn print_generic_arg( pub(crate) fn print_type_ref( db: &dyn DefDatabase, - type_ref: &TypeRef, + type_ref: TypeRefId, + map: &TypesMap, buf: &mut dyn Write, edition: Edition, ) -> fmt::Result { // FIXME: deduplicate with `HirDisplay` impl - match type_ref { + match &map[type_ref] { TypeRef::Never => write!(buf, "!")?, TypeRef::Placeholder => write!(buf, "_")?, TypeRef::Tuple(fields) => { @@ -166,48 +174,48 @@ pub(crate) fn print_type_ref( if i != 0 { write!(buf, ", ")?; } - print_type_ref(db, field, buf, edition)?; + print_type_ref(db, *field, map, buf, edition)?; } write!(buf, ")")?; } - TypeRef::Path(path) => print_path(db, path, buf, edition)?, + TypeRef::Path(path) => print_path(db, path, map, buf, edition)?, TypeRef::RawPtr(pointee, mtbl) => { let mtbl = match mtbl { Mutability::Shared => "*const", Mutability::Mut => "*mut", }; write!(buf, "{mtbl} ")?; - print_type_ref(db, pointee, buf, edition)?; + print_type_ref(db, *pointee, map, buf, edition)?; } - TypeRef::Reference(pointee, lt, mtbl) => { - let mtbl = match mtbl { + TypeRef::Reference(ref_) => { + let mtbl = match ref_.mutability { Mutability::Shared => "", Mutability::Mut => "mut ", }; write!(buf, "&")?; - if let Some(lt) = lt { + if let Some(lt) = &ref_.lifetime { write!(buf, "{} ", lt.name.display(db.upcast(), edition))?; } write!(buf, "{mtbl}")?; - print_type_ref(db, pointee, buf, edition)?; + print_type_ref(db, ref_.ty, map, buf, edition)?; } - TypeRef::Array(elem, len) => { + TypeRef::Array(array) => { write!(buf, "[")?; - print_type_ref(db, elem, buf, edition)?; - write!(buf, "; {}]", len.display(db.upcast(), edition))?; + print_type_ref(db, array.ty, map, buf, edition)?; + write!(buf, "; {}]", array.len.display(db.upcast(), edition))?; } TypeRef::Slice(elem) => { write!(buf, "[")?; - print_type_ref(db, elem, buf, edition)?; + print_type_ref(db, *elem, map, buf, edition)?; write!(buf, "]")?; } - TypeRef::Fn(args_and_ret, varargs, is_unsafe, abi) => { + TypeRef::Fn(fn_) => { let ((_, return_type), args) = - args_and_ret.split_last().expect("TypeRef::Fn is missing return type"); - if *is_unsafe { + fn_.params().split_last().expect("TypeRef::Fn is missing return type"); + if fn_.is_unsafe() { write!(buf, "unsafe ")?; } - if let Some(abi) = abi { + if let Some(abi) = fn_.abi() { buf.write_str("extern ")?; buf.write_str(abi.as_str())?; buf.write_char(' ')?; @@ -217,16 +225,16 @@ pub(crate) fn print_type_ref( if i != 0 { write!(buf, ", ")?; } - print_type_ref(db, typeref, buf, edition)?; + print_type_ref(db, *typeref, map, buf, edition)?; } - if *varargs { + if fn_.is_varargs() { if !args.is_empty() { write!(buf, ", ")?; } write!(buf, "...")?; } write!(buf, ") -> ")?; - print_type_ref(db, return_type, buf, edition)?; + print_type_ref(db, *return_type, map, buf, edition)?; } TypeRef::Macro(_ast_id) => { write!(buf, "<macro>")?; @@ -234,11 +242,11 @@ pub(crate) fn print_type_ref( TypeRef::Error => write!(buf, "{{unknown}}")?, TypeRef::ImplTrait(bounds) => { write!(buf, "impl ")?; - print_type_bounds(db, bounds, buf, edition)?; + print_type_bounds(db, bounds, map, buf, edition)?; } TypeRef::DynTrait(bounds) => { write!(buf, "dyn ")?; - print_type_bounds(db, bounds, buf, edition)?; + print_type_bounds(db, bounds, map, buf, edition)?; } } @@ -247,7 +255,8 @@ pub(crate) fn print_type_ref( pub(crate) fn print_type_bounds( db: &dyn DefDatabase, - bounds: &[Interned<TypeBound>], + bounds: &[TypeBound], + map: &TypesMap, buf: &mut dyn Write, edition: Edition, ) -> fmt::Result { @@ -256,13 +265,13 @@ pub(crate) fn print_type_bounds( write!(buf, " + ")?; } - match bound.as_ref() { + match bound { TypeBound::Path(path, modifier) => { match modifier { TraitBoundModifier::None => (), TraitBoundModifier::Maybe => write!(buf, "?")?, } - print_path(db, path, buf, edition)?; + print_path(db, path, map, buf, edition)?; } TypeBound::ForLifetime(lifetimes, path) => { write!( @@ -270,9 +279,25 @@ pub(crate) fn print_type_bounds( "for<{}> ", lifetimes.iter().map(|it| it.display(db.upcast(), edition)).format(", ") )?; - print_path(db, path, buf, edition)?; + print_path(db, path, map, buf, edition)?; } TypeBound::Lifetime(lt) => write!(buf, "{}", lt.name.display(db.upcast(), edition))?, + TypeBound::Use(args) => { + write!(buf, "use<")?; + let mut first = true; + for arg in args { + if !mem::take(&mut first) { + write!(buf, ", ")?; + } + match arg { + UseArgRef::Name(it) => write!(buf, "{}", it.display(db.upcast(), edition))?, + UseArgRef::Lifetime(it) => { + write!(buf, "{}", it.name.display(db.upcast(), edition))? + } + } + } + write!(buf, ">")? + } TypeBound::Error => write!(buf, "{{unknown}}")?, } } diff --git a/src/tools/rust-analyzer/crates/hir-def/src/resolver.rs b/src/tools/rust-analyzer/crates/hir-def/src/resolver.rs index f0f2210ec2c..26655e40ca7 100644 --- a/src/tools/rust-analyzer/crates/hir-def/src/resolver.rs +++ b/src/tools/rust-analyzer/crates/hir-def/src/resolver.rs @@ -3,14 +3,17 @@ use std::{fmt, iter, mem}; use base_db::CrateId; use hir_expand::{name::Name, MacroDefId}; -use intern::{sym, Interned}; +use intern::sym; use itertools::Itertools as _; use rustc_hash::FxHashSet; use smallvec::{smallvec, SmallVec}; use triomphe::Arc; use crate::{ - body::scope::{ExprScopes, ScopeId}, + body::{ + scope::{ExprScopes, ScopeId}, + HygieneId, + }, builtin_type::BuiltinType, data::ExternCrateDeclData, db::DefDatabase, @@ -21,7 +24,7 @@ use crate::{ nameres::{DefMap, MacroSubNs}, path::{ModPath, Path, PathKind}, per_ns::PerNs, - type_ref::LifetimeRef, + type_ref::{LifetimeRef, TypesMap}, visibility::{RawVisibility, Visibility}, AdtId, ConstId, ConstParamId, CrateRootModuleId, DefWithBodyId, EnumId, EnumVariantId, ExternBlockId, ExternCrateId, FunctionId, FxIndexMap, GenericDefId, GenericParamId, HasModule, @@ -73,13 +76,15 @@ enum Scope { /// All the items and imported names of a module BlockScope(ModuleItemMap), /// Brings the generic parameters of an item into scope - GenericParams { def: GenericDefId, params: Interned<GenericParams> }, + GenericParams { def: GenericDefId, params: Arc<GenericParams> }, /// Brings `Self` in `impl` block into scope ImplDefScope(ImplId), /// Brings `Self` in enum, struct and union definitions into scope AdtScope(AdtId), /// Local bindings ExprScope(ExprScope), + /// Macro definition inside bodies that affects all paths after it in the same block. + MacroDefScope(Box<MacroDefId>), } #[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)] @@ -162,7 +167,8 @@ impl Resolver { path: &Path, ) -> Option<(TypeNs, Option<usize>, Option<ImportOrExternCrate>)> { let path = match path { - Path::Normal { mod_path, .. } => mod_path, + Path::BarePath(mod_path) => mod_path, + Path::Normal(it) => it.mod_path(), Path::LangItem(l, seg) => { let type_ns = match *l { LangItemTarget::Union(it) => TypeNs::AdtId(it.into()), @@ -188,7 +194,7 @@ impl Resolver { for scope in self.scopes() { match scope { - Scope::ExprScope(_) => continue, + Scope::ExprScope(_) | Scope::MacroDefScope(_) => continue, Scope::GenericParams { params, def } => { if let Some(id) = params.find_type_by_name(first_name, *def) { return Some((TypeNs::GenericParam(id), remaining_idx(), None)); @@ -257,9 +263,11 @@ impl Resolver { &self, db: &dyn DefDatabase, path: &Path, + mut hygiene_id: HygieneId, ) -> Option<ResolveValueResult> { let path = match path { - Path::Normal { mod_path, .. } => mod_path, + Path::BarePath(mod_path) => mod_path, + Path::Normal(it) => it.mod_path(), Path::LangItem(l, None) => { return Some(ResolveValueResult::ValueNs( match *l { @@ -300,14 +308,22 @@ impl Resolver { } if n_segments <= 1 { + let mut hygiene_info = if !hygiene_id.is_root() { + let ctx = db.lookup_intern_syntax_context(hygiene_id.0); + ctx.outer_expn.map(|expansion| { + let expansion = db.lookup_intern_macro_call(expansion); + (ctx.parent, expansion.def) + }) + } else { + None + }; for scope in self.scopes() { match scope { Scope::ExprScope(scope) => { - let entry = scope - .expr_scopes - .entries(scope.scope_id) - .iter() - .find(|entry| entry.name() == first_name); + let entry = + scope.expr_scopes.entries(scope.scope_id).iter().find(|entry| { + entry.name() == first_name && entry.hygiene() == hygiene_id + }); if let Some(e) = entry { return Some(ResolveValueResult::ValueNs( @@ -316,6 +332,21 @@ impl Resolver { )); } } + Scope::MacroDefScope(macro_id) => { + if let Some((parent_ctx, label_macro_id)) = hygiene_info { + if label_macro_id == **macro_id { + // A macro is allowed to refer to variables from before its declaration. + // Therefore, if we got to the rib of its declaration, give up its hygiene + // and use its parent expansion. + let parent_ctx = db.lookup_intern_syntax_context(parent_ctx); + hygiene_id = HygieneId::new(parent_ctx.opaque_and_semitransparent); + hygiene_info = parent_ctx.outer_expn.map(|expansion| { + let expansion = db.lookup_intern_macro_call(expansion); + (parent_ctx.parent, expansion.def) + }); + } + } + } Scope::GenericParams { params, def } => { if let Some(id) = params.find_const_by_name(first_name, *def) { let val = ValueNs::GenericParam(id); @@ -342,7 +373,7 @@ impl Resolver { } else { for scope in self.scopes() { match scope { - Scope::ExprScope(_) => continue, + Scope::ExprScope(_) | Scope::MacroDefScope(_) => continue, Scope::GenericParams { params, def } => { if let Some(id) = params.find_type_by_name(first_name, *def) { let ty = TypeNs::GenericParam(id); @@ -393,8 +424,9 @@ impl Resolver { &self, db: &dyn DefDatabase, path: &Path, + hygiene: HygieneId, ) -> Option<ValueNs> { - match self.resolve_path_in_value_ns(db, path)? { + match self.resolve_path_in_value_ns(db, path, hygiene)? { ResolveValueResult::ValueNs(it, _) => Some(it), ResolveValueResult::Partial(..) => None, } @@ -590,13 +622,15 @@ impl Resolver { pub fn where_predicates_in_scope( &self, - ) -> impl Iterator<Item = (&crate::generics::WherePredicate, &GenericDefId)> { + ) -> impl Iterator<Item = (&crate::generics::WherePredicate, (&GenericDefId, &TypesMap))> { self.scopes() .filter_map(|scope| match scope { Scope::GenericParams { params, def } => Some((params, def)), _ => None, }) - .flat_map(|(params, def)| params.where_predicates().zip(iter::repeat(def))) + .flat_map(|(params, def)| { + params.where_predicates().zip(iter::repeat((def, ¶ms.types_map))) + }) } pub fn generic_def(&self) -> Option<GenericDefId> { @@ -606,13 +640,20 @@ impl Resolver { }) } - pub fn generic_params(&self) -> Option<&Interned<GenericParams>> { + pub fn generic_params(&self) -> Option<&Arc<GenericParams>> { self.scopes().find_map(|scope| match scope { Scope::GenericParams { params, .. } => Some(params), _ => None, }) } + pub fn all_generic_params(&self) -> impl Iterator<Item = (&GenericParams, &GenericDefId)> { + self.scopes().filter_map(|scope| match scope { + Scope::GenericParams { params, def } => Some((&**params, def)), + _ => None, + }) + } + pub fn body_owner(&self) -> Option<DefWithBodyId> { self.scopes().find_map(|scope| match scope { Scope::ExprScope(it) => Some(it.owner), @@ -622,7 +663,7 @@ impl Resolver { pub fn type_owner(&self) -> Option<TypeOwnerId> { self.scopes().find_map(|scope| match scope { - Scope::BlockScope(_) => None, + Scope::BlockScope(_) | Scope::MacroDefScope(_) => None, &Scope::GenericParams { def, .. } => Some(def.into()), &Scope::ImplDefScope(id) => Some(id.into()), &Scope::AdtScope(adt) => Some(adt.into()), @@ -653,6 +694,9 @@ impl Resolver { expr_scopes: &Arc<ExprScopes>, scope_id: ScopeId, ) { + if let Some(macro_id) = expr_scopes.macro_def(scope_id) { + resolver.scopes.push(Scope::MacroDefScope(macro_id.clone())); + } resolver.scopes.push(Scope::ExprScope(ExprScope { owner, expr_scopes: expr_scopes.clone(), @@ -670,7 +714,7 @@ impl Resolver { } let start = self.scopes.len(); - let innermost_scope = self.scopes().next(); + let innermost_scope = self.scopes().find(|scope| !matches!(scope, Scope::MacroDefScope(_))); match innermost_scope { Some(&Scope::ExprScope(ExprScope { scope_id, ref expr_scopes, owner })) => { let expr_scopes = expr_scopes.clone(); @@ -794,6 +838,7 @@ impl Scope { acc.add_local(e.name(), e.binding()); }); } + Scope::MacroDefScope(_) => {} } } } @@ -833,6 +878,9 @@ fn resolver_for_scope_( // already traverses all parents, so this is O(n²). I think we could only store the // innermost module scope instead? } + if let Some(macro_id) = scopes.macro_def(scope) { + r = r.push_scope(Scope::MacroDefScope(macro_id.clone())); + } r = r.push_expr_scope(owner, Arc::clone(&scopes), scope); } @@ -1006,12 +1054,12 @@ impl HasResolver for ModuleId { fn resolver(self, db: &dyn DefDatabase) -> Resolver { let mut def_map = self.def_map(db); let mut module_id = self.local_id; - let mut modules: SmallVec<[_; 1]> = smallvec![]; if !self.is_block_module() { return Resolver { scopes: vec![], module_scope: ModuleItemMap { def_map, module_id } }; } + let mut modules: SmallVec<[_; 1]> = smallvec![]; while let Some(parent) = def_map.parent() { let block_def_map = mem::replace(&mut def_map, parent.def_map(db)); modules.push(block_def_map); diff --git a/src/tools/rust-analyzer/crates/hir-def/src/test_db.rs b/src/tools/rust-analyzer/crates/hir-def/src/test_db.rs index 4db21eb46bd..0c36c88fb09 100644 --- a/src/tools/rust-analyzer/crates/hir-def/src/test_db.rs +++ b/src/tools/rust-analyzer/crates/hir-def/src/test_db.rs @@ -198,7 +198,10 @@ impl TestDB { .filter_map(|node| { let block = ast::BlockExpr::cast(node)?; let expr = ast::Expr::from(block); - let expr_id = source_map.node_expr(InFile::new(position.file_id.into(), &expr))?; + let expr_id = source_map + .node_expr(InFile::new(position.file_id.into(), &expr))? + .as_expr() + .unwrap(); let scope = scopes.scope_for(expr_id).unwrap(); Some(scope) }); diff --git a/src/tools/rust-analyzer/crates/hir-def/src/visibility.rs b/src/tools/rust-analyzer/crates/hir-def/src/visibility.rs index 3aeb88047a0..4edb6835922 100644 --- a/src/tools/rust-analyzer/crates/hir-def/src/visibility.rs +++ b/src/tools/rust-analyzer/crates/hir-def/src/visibility.rs @@ -191,6 +191,11 @@ impl Visibility { return None; } + let def_block = def_map.block_id(); + if (mod_a.containing_block(), mod_b.containing_block()) != (def_block, def_block) { + return None; + } + let mut a_ancestors = iter::successors(Some(mod_a.local_id), |&m| def_map[m].parent); let mut b_ancestors = @@ -210,6 +215,43 @@ impl Visibility { } } } + + /// Returns the least permissive visibility of `self` and `other`. + /// + /// If there is no subset relation between `self` and `other`, returns `None` (ie. they're only + /// visible in unrelated modules). + pub(crate) fn min(self, other: Visibility, def_map: &DefMap) -> Option<Visibility> { + match (self, other) { + (vis, Visibility::Public) | (Visibility::Public, vis) => Some(vis), + (Visibility::Module(mod_a, expl_a), Visibility::Module(mod_b, expl_b)) => { + if mod_a.krate != mod_b.krate { + return None; + } + + let def_block = def_map.block_id(); + if (mod_a.containing_block(), mod_b.containing_block()) != (def_block, def_block) { + return None; + } + + let mut a_ancestors = + iter::successors(Some(mod_a.local_id), |&m| def_map[m].parent); + let mut b_ancestors = + iter::successors(Some(mod_b.local_id), |&m| def_map[m].parent); + + if a_ancestors.any(|m| m == mod_b.local_id) { + // B is above A + return Some(Visibility::Module(mod_a, expl_b)); + } + + if b_ancestors.any(|m| m == mod_a.local_id) { + // A is above B + return Some(Visibility::Module(mod_b, expl_a)); + } + + None + } + } + } } /// Whether the item was imported through an explicit `pub(crate) use` or just a `use` without diff --git a/src/tools/rust-analyzer/crates/hir-expand/src/attrs.rs b/src/tools/rust-analyzer/crates/hir-expand/src/attrs.rs index 79cfeb4cf18..12df3cf2188 100644 --- a/src/tools/rust-analyzer/crates/hir-expand/src/attrs.rs +++ b/src/tools/rust-analyzer/crates/hir-expand/src/attrs.rs @@ -26,6 +26,7 @@ use crate::{ /// Syntactical attributes, without filtering of `cfg_attr`s. #[derive(Default, Debug, Clone, PartialEq, Eq)] pub struct RawAttrs { + // FIXME: This can become `Box<[Attr]>` if https://internals.rust-lang.org/t/layout-of-dst-box/21728?u=chrefr is accepted. entries: Option<ThinArc<(), Attr>>, } @@ -169,6 +170,10 @@ impl RawAttrs { }; RawAttrs { entries } } + + pub fn is_empty(&self) -> bool { + self.entries.is_none() + } } #[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)] diff --git a/src/tools/rust-analyzer/crates/hir-expand/src/hygiene.rs b/src/tools/rust-analyzer/crates/hir-expand/src/hygiene.rs index a8191189157..f48de807c28 100644 --- a/src/tools/rust-analyzer/crates/hir-expand/src/hygiene.rs +++ b/src/tools/rust-analyzer/crates/hir-expand/src/hygiene.rs @@ -227,7 +227,7 @@ pub(crate) fn dump_syntax_contexts(db: &dyn ExpandDatabase) -> String { &'a SyntaxContextData, ); - impl<'a> std::fmt::Debug for SyntaxContextDebug<'a> { + impl std::fmt::Debug for SyntaxContextDebug<'_> { fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { fancy_debug(self.2, self.1, self.0, f) } diff --git a/src/tools/rust-analyzer/crates/hir-expand/src/lib.rs b/src/tools/rust-analyzer/crates/hir-expand/src/lib.rs index 5d5f72490d0..7d2f556406d 100644 --- a/src/tools/rust-analyzer/crates/hir-expand/src/lib.rs +++ b/src/tools/rust-analyzer/crates/hir-expand/src/lib.rs @@ -165,40 +165,73 @@ pub enum ExpandErrorKind { } impl ExpandError { - pub fn render_to_string(&self, db: &dyn ExpandDatabase) -> (String, bool) { + pub fn render_to_string(&self, db: &dyn ExpandDatabase) -> RenderedExpandError { self.inner.0.render_to_string(db) } } +pub struct RenderedExpandError { + pub message: String, + pub error: bool, + pub kind: &'static str, +} + +impl RenderedExpandError { + const GENERAL_KIND: &str = "macro-error"; +} + impl ExpandErrorKind { - pub fn render_to_string(&self, db: &dyn ExpandDatabase) -> (String, bool) { + pub fn render_to_string(&self, db: &dyn ExpandDatabase) -> RenderedExpandError { match self { - ExpandErrorKind::ProcMacroAttrExpansionDisabled => { - ("procedural attribute macro expansion is disabled".to_owned(), false) - } - ExpandErrorKind::MacroDisabled => { - ("proc-macro is explicitly disabled".to_owned(), false) - } + ExpandErrorKind::ProcMacroAttrExpansionDisabled => RenderedExpandError { + message: "procedural attribute macro expansion is disabled".to_owned(), + error: false, + kind: "proc-macros-disabled", + }, + ExpandErrorKind::MacroDisabled => RenderedExpandError { + message: "proc-macro is explicitly disabled".to_owned(), + error: false, + kind: "proc-macro-disabled", + }, &ExpandErrorKind::MissingProcMacroExpander(def_crate) => { match db.proc_macros().get_error_for_crate(def_crate) { - Some((e, hard_err)) => (e.to_owned(), hard_err), - None => ( - format!( - "internal error: proc-macro map is missing error entry for crate {def_crate:?}" - ), - true, - ), + Some((e, hard_err)) => RenderedExpandError { + message: e.to_owned(), + error: hard_err, + kind: RenderedExpandError::GENERAL_KIND, + }, + None => RenderedExpandError { + message: format!("internal error: proc-macro map is missing error entry for crate {def_crate:?}"), + error: true, + kind: RenderedExpandError::GENERAL_KIND, + }, } } - ExpandErrorKind::MacroDefinition => { - ("macro definition has parse errors".to_owned(), true) - } - ExpandErrorKind::Mbe(e) => (e.to_string(), true), - ExpandErrorKind::RecursionOverflow => { - ("overflow expanding the original macro".to_owned(), true) - } - ExpandErrorKind::Other(e) => ((**e).to_owned(), true), - ExpandErrorKind::ProcMacroPanic(e) => (format!("proc-macro panicked: {e}"), true), + ExpandErrorKind::MacroDefinition => RenderedExpandError { + message: "macro definition has parse errors".to_owned(), + error: true, + kind: RenderedExpandError::GENERAL_KIND, + }, + ExpandErrorKind::Mbe(e) => RenderedExpandError { + message: e.to_string(), + error: true, + kind: RenderedExpandError::GENERAL_KIND, + }, + ExpandErrorKind::RecursionOverflow => RenderedExpandError { + message: "overflow expanding the original macro".to_owned(), + error: true, + kind: RenderedExpandError::GENERAL_KIND, + }, + ExpandErrorKind::Other(e) => RenderedExpandError { + message: (**e).to_owned(), + error: true, + kind: RenderedExpandError::GENERAL_KIND, + }, + ExpandErrorKind::ProcMacroPanic(e) => RenderedExpandError { + message: format!("proc-macro panicked: {e}"), + error: true, + kind: RenderedExpandError::GENERAL_KIND, + }, } } } diff --git a/src/tools/rust-analyzer/crates/hir-expand/src/name.rs b/src/tools/rust-analyzer/crates/hir-expand/src/name.rs index 54313904a7e..267d5458333 100644 --- a/src/tools/rust-analyzer/crates/hir-expand/src/name.rs +++ b/src/tools/rust-analyzer/crates/hir-expand/src/name.rs @@ -18,6 +18,8 @@ use syntax::utils::is_raw_identifier; #[derive(Clone, PartialEq, Eq, Hash)] pub struct Name { symbol: Symbol, + // If you are making this carry actual hygiene, beware that the special handling for variables and labels + // in bodies can go. ctx: (), } diff --git a/src/tools/rust-analyzer/crates/hir-ty/src/autoderef.rs b/src/tools/rust-analyzer/crates/hir-ty/src/autoderef.rs index 7a3846df40e..2b5342314a6 100644 --- a/src/tools/rust-analyzer/crates/hir-ty/src/autoderef.rs +++ b/src/tools/rust-analyzer/crates/hir-ty/src/autoderef.rs @@ -114,7 +114,7 @@ impl<'table, 'db> Autoderef<'table, 'db, usize> { } #[allow(private_bounds)] -impl<'table, 'db, T: TrackAutoderefSteps> Autoderef<'table, 'db, T> { +impl<T: TrackAutoderefSteps> Autoderef<'_, '_, T> { pub(crate) fn step_count(&self) -> usize { self.steps.len() } diff --git a/src/tools/rust-analyzer/crates/hir-ty/src/chalk_db.rs b/src/tools/rust-analyzer/crates/hir-ty/src/chalk_db.rs index f7bacbd49b3..4bc78afacc0 100644 --- a/src/tools/rust-analyzer/crates/hir-ty/src/chalk_db.rs +++ b/src/tools/rust-analyzer/crates/hir-ty/src/chalk_db.rs @@ -521,7 +521,7 @@ impl chalk_solve::RustIrDatabase<Interner> for ChalkContext<'_> { } } -impl<'a> ChalkContext<'a> { +impl ChalkContext<'_> { fn edition(&self) -> Edition { self.db.crate_graph()[self.krate].edition } @@ -615,8 +615,9 @@ pub(crate) fn associated_ty_data_query( let type_alias_data = db.type_alias_data(type_alias); let generic_params = generics(db.upcast(), type_alias.into()); let resolver = hir_def::resolver::HasResolver::resolver(type_alias, db.upcast()); - let ctx = crate::TyLoweringContext::new(db, &resolver, type_alias.into()) - .with_type_param_mode(crate::lower::ParamLoweringMode::Variable); + let ctx = + crate::TyLoweringContext::new(db, &resolver, &type_alias_data.types_map, type_alias.into()) + .with_type_param_mode(crate::lower::ParamLoweringMode::Variable); let trait_subst = TyBuilder::subst_for_def(db, trait_, None) .fill_with_bound_vars(crate::DebruijnIndex::INNERMOST, generic_params.len_self()) diff --git a/src/tools/rust-analyzer/crates/hir-ty/src/consteval.rs b/src/tools/rust-analyzer/crates/hir-ty/src/consteval.rs index e41058aac2a..091cfcd4654 100644 --- a/src/tools/rust-analyzer/crates/hir-ty/src/consteval.rs +++ b/src/tools/rust-analyzer/crates/hir-ty/src/consteval.rs @@ -3,7 +3,7 @@ use base_db::{ra_salsa::Cycle, CrateId}; use chalk_ir::{cast::Cast, BoundVar, DebruijnIndex}; use hir_def::{ - body::Body, + body::{Body, HygieneId}, hir::{Expr, ExprId}, path::Path, resolver::{Resolver, ValueNs}, @@ -11,7 +11,7 @@ use hir_def::{ ConstBlockLoc, EnumVariantId, GeneralConstId, StaticId, }; use hir_expand::Lookup; -use stdx::{never, IsNoneOr}; +use stdx::never; use triomphe::Arc; use crate::{ @@ -80,7 +80,7 @@ pub(crate) fn path_to_const<'g>( debruijn: DebruijnIndex, expected_ty: Ty, ) -> Option<Const> { - match resolver.resolve_path_in_value_ns_fully(db.upcast(), path) { + match resolver.resolve_path_in_value_ns_fully(db.upcast(), path, HygieneId::ROOT) { Some(ValueNs::GenericParam(p)) => { let ty = db.const_param_ty(p); let value = match mode { @@ -287,7 +287,7 @@ pub(crate) fn const_eval_discriminant_variant( } let repr = db.enum_data(loc.parent).repr; - let is_signed = IsNoneOr::is_none_or(repr.and_then(|repr| repr.int), |int| int.is_signed()); + let is_signed = repr.and_then(|repr| repr.int).is_none_or(|int| int.is_signed()); let mir_body = db.monomorphized_mir_body( def, @@ -319,7 +319,7 @@ pub(crate) fn eval_to_const( return true; } let mut r = false; - body[expr].walk_child_exprs(|idx| r |= has_closure(body, idx)); + body.walk_child_exprs(expr, |idx| r |= has_closure(body, idx)); r } if has_closure(ctx.body, expr) { diff --git a/src/tools/rust-analyzer/crates/hir-ty/src/diagnostics/decl_check.rs b/src/tools/rust-analyzer/crates/hir-ty/src/diagnostics/decl_check.rs index 7f6b7e392b3..c9ab0acc084 100644 --- a/src/tools/rust-analyzer/crates/hir-ty/src/diagnostics/decl_check.rs +++ b/src/tools/rust-analyzer/crates/hir-ty/src/diagnostics/decl_check.rs @@ -309,7 +309,7 @@ impl<'a> DeclValidator<'a> { /// Check incorrect names for struct fields. fn validate_struct_fields(&mut self, struct_id: StructId) { let data = self.db.struct_data(struct_id); - let VariantData::Record(fields) = data.variant_data.as_ref() else { + let VariantData::Record { fields, .. } = data.variant_data.as_ref() else { return; }; let edition = self.edition(struct_id); @@ -469,7 +469,7 @@ impl<'a> DeclValidator<'a> { /// Check incorrect names for fields of enum variant. fn validate_enum_variant_fields(&mut self, variant_id: EnumVariantId) { let variant_data = self.db.enum_variant_data(variant_id); - let VariantData::Record(fields) = variant_data.variant_data.as_ref() else { + let VariantData::Record { fields, .. } = variant_data.variant_data.as_ref() else { return; }; let edition = self.edition(variant_id); diff --git a/src/tools/rust-analyzer/crates/hir-ty/src/diagnostics/expr.rs b/src/tools/rust-analyzer/crates/hir-ty/src/diagnostics/expr.rs index f8b5c7d0ce2..92404e3a10e 100644 --- a/src/tools/rust-analyzer/crates/hir-ty/src/diagnostics/expr.rs +++ b/src/tools/rust-analyzer/crates/hir-ty/src/diagnostics/expr.rs @@ -289,10 +289,12 @@ impl ExprValidator { match &self.body[scrutinee_expr] { Expr::UnaryOp { op: UnaryOp::Deref, .. } => false, Expr::Path(path) => { - let value_or_partial = self - .owner - .resolver(db.upcast()) - .resolve_path_in_value_ns_fully(db.upcast(), path); + let value_or_partial = + self.owner.resolver(db.upcast()).resolve_path_in_value_ns_fully( + db.upcast(), + path, + self.body.expr_path_hygiene(scrutinee_expr), + ); value_or_partial.map_or(true, |v| !matches!(v, ValueNs::StaticId(_))) } Expr::Field { expr, .. } => match self.infer.type_of_expr[*expr].kind(Interner) { @@ -546,10 +548,7 @@ pub fn record_literal_missing_fields( expr: &Expr, ) -> Option<(VariantId, Vec<LocalFieldId>, /*exhaustive*/ bool)> { let (fields, exhaustive) = match expr { - Expr::RecordLit { fields, spread, ellipsis, is_assignee_expr, .. } => { - let exhaustive = if *is_assignee_expr { !*ellipsis } else { spread.is_none() }; - (fields, exhaustive) - } + Expr::RecordLit { fields, spread, .. } => (fields, spread.is_none()), _ => return None, }; diff --git a/src/tools/rust-analyzer/crates/hir-ty/src/diagnostics/match_check.rs b/src/tools/rust-analyzer/crates/hir-ty/src/diagnostics/match_check.rs index 4bc07bc9ec8..c5d8c956615 100644 --- a/src/tools/rust-analyzer/crates/hir-ty/src/diagnostics/match_check.rs +++ b/src/tools/rust-analyzer/crates/hir-ty/src/diagnostics/match_check.rs @@ -341,7 +341,7 @@ impl HirDisplay for Pat { }; let variant_data = variant.variant_data(f.db.upcast()); - if let VariantData::Record(rec_fields) = &*variant_data { + if let VariantData::Record { fields: rec_fields, .. } = &*variant_data { write!(f, " {{ ")?; let mut printed = 0; diff --git a/src/tools/rust-analyzer/crates/hir-ty/src/diagnostics/match_check/pat_analysis.rs b/src/tools/rust-analyzer/crates/hir-ty/src/diagnostics/match_check/pat_analysis.rs index 1066a28c3ff..58de19ba81e 100644 --- a/src/tools/rust-analyzer/crates/hir-ty/src/diagnostics/match_check/pat_analysis.rs +++ b/src/tools/rust-analyzer/crates/hir-ty/src/diagnostics/match_check/pat_analysis.rs @@ -519,7 +519,7 @@ impl<'db> PatCx for MatchCheckCtx<'db> { } } -impl<'db> fmt::Debug for MatchCheckCtx<'db> { +impl fmt::Debug for MatchCheckCtx<'_> { fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { f.debug_struct("MatchCheckCtx").finish() } diff --git a/src/tools/rust-analyzer/crates/hir-ty/src/diagnostics/unsafe_check.rs b/src/tools/rust-analyzer/crates/hir-ty/src/diagnostics/unsafe_check.rs index bcfc37c8671..c7f7fb7ad3d 100644 --- a/src/tools/rust-analyzer/crates/hir-ty/src/diagnostics/unsafe_check.rs +++ b/src/tools/rust-analyzer/crates/hir-ty/src/diagnostics/unsafe_check.rs @@ -3,7 +3,7 @@ use hir_def::{ body::Body, - hir::{Expr, ExprId, UnaryOp}, + hir::{Expr, ExprId, ExprOrPatId, Pat, UnaryOp}, resolver::{resolver_for_expr, ResolveValueResult, Resolver, ValueNs}, type_ref::Rawness, DefWithBodyId, @@ -16,7 +16,7 @@ use crate::{ /// Returns `(unsafe_exprs, fn_is_unsafe)`. /// /// If `fn_is_unsafe` is false, `unsafe_exprs` are hard errors. If true, they're `unsafe_op_in_unsafe_fn`. -pub fn missing_unsafe(db: &dyn HirDatabase, def: DefWithBodyId) -> (Vec<ExprId>, bool) { +pub fn missing_unsafe(db: &dyn HirDatabase, def: DefWithBodyId) -> (Vec<ExprOrPatId>, bool) { let _p = tracing::info_span!("missing_unsafe").entered(); let mut res = Vec::new(); @@ -32,7 +32,7 @@ pub fn missing_unsafe(db: &dyn HirDatabase, def: DefWithBodyId) -> (Vec<ExprId>, let infer = db.infer(def); unsafe_expressions(db, &infer, def, &body, body.body_expr, &mut |expr| { if !expr.inside_unsafe_block { - res.push(expr.expr); + res.push(expr.node); } }); @@ -40,7 +40,7 @@ pub fn missing_unsafe(db: &dyn HirDatabase, def: DefWithBodyId) -> (Vec<ExprId>, } pub struct UnsafeExpr { - pub expr: ExprId, + pub node: ExprOrPatId, pub inside_unsafe_block: bool, } @@ -75,26 +75,29 @@ fn walk_unsafe( inside_unsafe_block: bool, unsafe_expr_cb: &mut dyn FnMut(UnsafeExpr), ) { + let mut mark_unsafe_path = |path, node| { + let g = resolver.update_to_inner_scope(db.upcast(), def, current); + let hygiene = body.expr_or_pat_path_hygiene(node); + let value_or_partial = resolver.resolve_path_in_value_ns(db.upcast(), path, hygiene); + if let Some(ResolveValueResult::ValueNs(ValueNs::StaticId(id), _)) = value_or_partial { + let static_data = db.static_data(id); + if static_data.mutable || (static_data.is_extern && !static_data.has_safe_kw) { + unsafe_expr_cb(UnsafeExpr { node, inside_unsafe_block }); + } + } + resolver.reset_to_guard(g); + }; + let expr = &body.exprs[current]; match expr { &Expr::Call { callee, .. } => { if let Some(func) = infer[callee].as_fn_def(db) { if is_fn_unsafe_to_call(db, func) { - unsafe_expr_cb(UnsafeExpr { expr: current, inside_unsafe_block }); - } - } - } - Expr::Path(path) => { - let g = resolver.update_to_inner_scope(db.upcast(), def, current); - let value_or_partial = resolver.resolve_path_in_value_ns(db.upcast(), path); - if let Some(ResolveValueResult::ValueNs(ValueNs::StaticId(id), _)) = value_or_partial { - let static_data = db.static_data(id); - if static_data.mutable || (static_data.is_extern && !static_data.has_safe_kw) { - unsafe_expr_cb(UnsafeExpr { expr: current, inside_unsafe_block }); + unsafe_expr_cb(UnsafeExpr { node: current.into(), inside_unsafe_block }); } } - resolver.reset_to_guard(g); } + Expr::Path(path) => mark_unsafe_path(path, current.into()), Expr::Ref { expr, rawness: Rawness::RawPtr, mutability: _ } => { if let Expr::Path(_) = body.exprs[*expr] { // Do not report unsafe for `addr_of[_mut]!(EXTERN_OR_MUT_STATIC)`, @@ -108,23 +111,30 @@ fn walk_unsafe( .map(|(func, _)| is_fn_unsafe_to_call(db, func)) .unwrap_or(false) { - unsafe_expr_cb(UnsafeExpr { expr: current, inside_unsafe_block }); + unsafe_expr_cb(UnsafeExpr { node: current.into(), inside_unsafe_block }); } } Expr::UnaryOp { expr, op: UnaryOp::Deref } => { if let TyKind::Raw(..) = &infer[*expr].kind(Interner) { - unsafe_expr_cb(UnsafeExpr { expr: current, inside_unsafe_block }); + unsafe_expr_cb(UnsafeExpr { node: current.into(), inside_unsafe_block }); } } Expr::Unsafe { .. } => { - return expr.walk_child_exprs(|child| { + return body.walk_child_exprs(current, |child| { walk_unsafe(db, infer, body, resolver, def, child, true, unsafe_expr_cb); }); } + &Expr::Assignment { target, value: _ } => { + body.walk_pats(target, &mut |pat| { + if let Pat::Path(path) = &body[pat] { + mark_unsafe_path(path, pat.into()); + } + }); + } _ => {} } - expr.walk_child_exprs(|child| { + body.walk_child_exprs(current, |child| { walk_unsafe(db, infer, body, resolver, def, child, inside_unsafe_block, unsafe_expr_cb); }); } diff --git a/src/tools/rust-analyzer/crates/hir-ty/src/display.rs b/src/tools/rust-analyzer/crates/hir-ty/src/display.rs index 10f5bcdad86..277dabe9aa3 100644 --- a/src/tools/rust-analyzer/crates/hir-ty/src/display.rs +++ b/src/tools/rust-analyzer/crates/hir-ty/src/display.rs @@ -19,7 +19,9 @@ use hir_def::{ lang_item::{LangItem, LangItemTarget}, nameres::DefMap, path::{Path, PathKind}, - type_ref::{TraitBoundModifier, TypeBound, TypeRef}, + type_ref::{ + TraitBoundModifier, TypeBound, TypeRef, TypeRefId, TypesMap, TypesSourceMap, UseArgRef, + }, visibility::Visibility, GenericDefId, HasModule, ImportPathConfig, ItemContainerId, LocalFieldId, Lookup, ModuleDefId, ModuleId, TraitId, @@ -806,7 +808,7 @@ fn render_variant_after_name( memory_map: &MemoryMap, ) -> Result<(), HirDisplayError> { match data { - VariantData::Record(fields) | VariantData::Tuple(fields) => { + VariantData::Record { fields, .. } | VariantData::Tuple { fields, .. } => { let render_field = |f: &mut HirFormatter<'_>, id: LocalFieldId| { let offset = layout.fields.offset(u32::from(id.into_raw()) as usize).bytes_usize(); let ty = field_types[id].clone().substitute(Interner, subst); @@ -817,7 +819,7 @@ fn render_variant_after_name( render_const_scalar(f, &b[offset..offset + size], memory_map, &ty) }; let mut it = fields.iter(); - if matches!(data, VariantData::Record(_)) { + if matches!(data, VariantData::Record { .. }) { write!(f, " {{")?; if let Some((id, data)) = it.next() { write!(f, " {}: ", data.name.display(f.db.upcast(), f.edition()))?; @@ -1897,100 +1899,150 @@ pub fn write_visibility( } } -impl HirDisplay for TypeRef { +pub trait HirDisplayWithTypesMap { + fn hir_fmt( + &self, + f: &mut HirFormatter<'_>, + types_map: &TypesMap, + ) -> Result<(), HirDisplayError>; +} + +impl<T: ?Sized + HirDisplayWithTypesMap> HirDisplayWithTypesMap for &'_ T { + fn hir_fmt( + &self, + f: &mut HirFormatter<'_>, + types_map: &TypesMap, + ) -> Result<(), HirDisplayError> { + T::hir_fmt(&**self, f, types_map) + } +} + +pub fn hir_display_with_types_map<'a, T: HirDisplayWithTypesMap + 'a>( + value: T, + types_map: &'a TypesMap, +) -> impl HirDisplay + 'a { + TypesMapAdapter(value, types_map) +} + +struct TypesMapAdapter<'a, T>(T, &'a TypesMap); + +impl<'a, T> TypesMapAdapter<'a, T> { + fn wrap(types_map: &'a TypesMap) -> impl Fn(T) -> TypesMapAdapter<'a, T> { + move |value| TypesMapAdapter(value, types_map) + } +} + +impl<T: HirDisplayWithTypesMap> HirDisplay for TypesMapAdapter<'_, T> { fn hir_fmt(&self, f: &mut HirFormatter<'_>) -> Result<(), HirDisplayError> { - match self { + T::hir_fmt(&self.0, f, self.1) + } +} + +impl HirDisplayWithTypesMap for TypeRefId { + fn hir_fmt( + &self, + f: &mut HirFormatter<'_>, + types_map: &TypesMap, + ) -> Result<(), HirDisplayError> { + match &types_map[*self] { TypeRef::Never => write!(f, "!")?, TypeRef::Placeholder => write!(f, "_")?, TypeRef::Tuple(elems) => { write!(f, "(")?; - f.write_joined(elems, ", ")?; + f.write_joined(elems.iter().map(TypesMapAdapter::wrap(types_map)), ", ")?; if elems.len() == 1 { write!(f, ",")?; } write!(f, ")")?; } - TypeRef::Path(path) => path.hir_fmt(f)?, + TypeRef::Path(path) => path.hir_fmt(f, types_map)?, TypeRef::RawPtr(inner, mutability) => { let mutability = match mutability { hir_def::type_ref::Mutability::Shared => "*const ", hir_def::type_ref::Mutability::Mut => "*mut ", }; write!(f, "{mutability}")?; - inner.hir_fmt(f)?; + inner.hir_fmt(f, types_map)?; } - TypeRef::Reference(inner, lifetime, mutability) => { - let mutability = match mutability { + TypeRef::Reference(ref_) => { + let mutability = match ref_.mutability { hir_def::type_ref::Mutability::Shared => "", hir_def::type_ref::Mutability::Mut => "mut ", }; write!(f, "&")?; - if let Some(lifetime) = lifetime { + if let Some(lifetime) = &ref_.lifetime { write!(f, "{} ", lifetime.name.display(f.db.upcast(), f.edition()))?; } write!(f, "{mutability}")?; - inner.hir_fmt(f)?; + ref_.ty.hir_fmt(f, types_map)?; } - TypeRef::Array(inner, len) => { + TypeRef::Array(array) => { write!(f, "[")?; - inner.hir_fmt(f)?; - write!(f, "; {}]", len.display(f.db.upcast(), f.edition()))?; + array.ty.hir_fmt(f, types_map)?; + write!(f, "; {}]", array.len.display(f.db.upcast(), f.edition()))?; } TypeRef::Slice(inner) => { write!(f, "[")?; - inner.hir_fmt(f)?; + inner.hir_fmt(f, types_map)?; write!(f, "]")?; } - &TypeRef::Fn(ref parameters, is_varargs, is_unsafe, ref abi) => { - if is_unsafe { + TypeRef::Fn(fn_) => { + if fn_.is_unsafe() { write!(f, "unsafe ")?; } - if let Some(abi) = abi { + if let Some(abi) = fn_.abi() { f.write_str("extern \"")?; f.write_str(abi.as_str())?; f.write_str("\" ")?; } write!(f, "fn(")?; - if let Some(((_, return_type), function_parameters)) = parameters.split_last() { + if let Some(((_, return_type), function_parameters)) = fn_.params().split_last() { for index in 0..function_parameters.len() { let (param_name, param_type) = &function_parameters[index]; if let Some(name) = param_name { write!(f, "{}: ", name.display(f.db.upcast(), f.edition()))?; } - param_type.hir_fmt(f)?; + param_type.hir_fmt(f, types_map)?; if index != function_parameters.len() - 1 { write!(f, ", ")?; } } - if is_varargs { - write!(f, "{}...", if parameters.len() == 1 { "" } else { ", " })?; + if fn_.is_varargs() { + write!(f, "{}...", if fn_.params().len() == 1 { "" } else { ", " })?; } write!(f, ")")?; - match &return_type { + match &types_map[*return_type] { TypeRef::Tuple(tup) if tup.is_empty() => {} _ => { write!(f, " -> ")?; - return_type.hir_fmt(f)?; + return_type.hir_fmt(f, types_map)?; } } } } TypeRef::ImplTrait(bounds) => { write!(f, "impl ")?; - f.write_joined(bounds, " + ")?; + f.write_joined(bounds.iter().map(TypesMapAdapter::wrap(types_map)), " + ")?; } TypeRef::DynTrait(bounds) => { write!(f, "dyn ")?; - f.write_joined(bounds, " + ")?; + f.write_joined(bounds.iter().map(TypesMapAdapter::wrap(types_map)), " + ")?; } TypeRef::Macro(macro_call) => { - let ctx = hir_def::lower::LowerCtx::new(f.db.upcast(), macro_call.file_id); + let (mut types_map, mut types_source_map) = + (TypesMap::default(), TypesSourceMap::default()); + let ctx = hir_def::lower::LowerCtx::new( + f.db.upcast(), + macro_call.file_id, + &mut types_map, + &mut types_source_map, + ); let macro_call = macro_call.to_node(f.db.upcast()); match macro_call.path() { Some(path) => match Path::from_src(&ctx, path) { - Some(path) => path.hir_fmt(f)?, + Some(path) => path.hir_fmt(f, &types_map)?, None => write!(f, "{{macro}}")?, }, None => write!(f, "{{macro}}")?, @@ -2003,15 +2055,19 @@ impl HirDisplay for TypeRef { } } -impl HirDisplay for TypeBound { - fn hir_fmt(&self, f: &mut HirFormatter<'_>) -> Result<(), HirDisplayError> { +impl HirDisplayWithTypesMap for TypeBound { + fn hir_fmt( + &self, + f: &mut HirFormatter<'_>, + types_map: &TypesMap, + ) -> Result<(), HirDisplayError> { match self { TypeBound::Path(path, modifier) => { match modifier { TraitBoundModifier::None => (), TraitBoundModifier::Maybe => write!(f, "?")?, } - path.hir_fmt(f) + path.hir_fmt(f, types_map) } TypeBound::Lifetime(lifetime) => { write!(f, "{}", lifetime.name.display(f.db.upcast(), f.edition())) @@ -2023,19 +2079,36 @@ impl HirDisplay for TypeBound { "for<{}> ", lifetimes.iter().map(|it| it.display(f.db.upcast(), edition)).format(", ") )?; - path.hir_fmt(f) + path.hir_fmt(f, types_map) + } + TypeBound::Use(args) => { + let edition = f.edition(); + write!( + f, + "use<{}> ", + args.iter() + .map(|it| match it { + UseArgRef::Lifetime(lt) => lt.name.display(f.db.upcast(), edition), + UseArgRef::Name(n) => n.display(f.db.upcast(), edition), + }) + .format(", ") + ) } TypeBound::Error => write!(f, "{{error}}"), } } } -impl HirDisplay for Path { - fn hir_fmt(&self, f: &mut HirFormatter<'_>) -> Result<(), HirDisplayError> { +impl HirDisplayWithTypesMap for Path { + fn hir_fmt( + &self, + f: &mut HirFormatter<'_>, + types_map: &TypesMap, + ) -> Result<(), HirDisplayError> { match (self.type_anchor(), self.kind()) { (Some(anchor), _) => { write!(f, "<")?; - anchor.hir_fmt(f)?; + anchor.hir_fmt(f, types_map)?; write!(f, ">")?; } (_, PathKind::Plain) => {} @@ -2078,7 +2151,7 @@ impl HirDisplay for Path { }); if let Some(ty) = trait_self_ty { write!(f, "<")?; - ty.hir_fmt(f)?; + ty.hir_fmt(f, types_map)?; write!(f, " as ")?; // Now format the path of the trait... } @@ -2094,21 +2167,26 @@ impl HirDisplay for Path { if generic_args.desugared_from_fn { // First argument will be a tuple, which already includes the parentheses. // If the tuple only contains 1 item, write it manually to avoid the trailing `,`. - if let hir_def::path::GenericArg::Type(TypeRef::Tuple(v)) = - &generic_args.args[0] - { + let tuple = match generic_args.args[0] { + hir_def::path::GenericArg::Type(ty) => match &types_map[ty] { + TypeRef::Tuple(it) => Some(it), + _ => None, + }, + _ => None, + }; + if let Some(v) = tuple { if v.len() == 1 { write!(f, "(")?; - v[0].hir_fmt(f)?; + v[0].hir_fmt(f, types_map)?; write!(f, ")")?; } else { - generic_args.args[0].hir_fmt(f)?; + generic_args.args[0].hir_fmt(f, types_map)?; } } - if let Some(ret) = &generic_args.bindings[0].type_ref { - if !matches!(ret, TypeRef::Tuple(v) if v.is_empty()) { + if let Some(ret) = generic_args.bindings[0].type_ref { + if !matches!(&types_map[ret], TypeRef::Tuple(v) if v.is_empty()) { write!(f, " -> ")?; - ret.hir_fmt(f)?; + ret.hir_fmt(f, types_map)?; } } return Ok(()); @@ -2123,7 +2201,7 @@ impl HirDisplay for Path { } else { write!(f, ", ")?; } - arg.hir_fmt(f)?; + arg.hir_fmt(f, types_map)?; } for binding in generic_args.bindings.iter() { if first { @@ -2136,11 +2214,14 @@ impl HirDisplay for Path { match &binding.type_ref { Some(ty) => { write!(f, " = ")?; - ty.hir_fmt(f)? + ty.hir_fmt(f, types_map)? } None => { write!(f, ": ")?; - f.write_joined(binding.bounds.iter(), " + ")?; + f.write_joined( + binding.bounds.iter().map(TypesMapAdapter::wrap(types_map)), + " + ", + )?; } } } @@ -2162,10 +2243,14 @@ impl HirDisplay for Path { } } -impl HirDisplay for hir_def::path::GenericArg { - fn hir_fmt(&self, f: &mut HirFormatter<'_>) -> Result<(), HirDisplayError> { +impl HirDisplayWithTypesMap for hir_def::path::GenericArg { + fn hir_fmt( + &self, + f: &mut HirFormatter<'_>, + types_map: &TypesMap, + ) -> Result<(), HirDisplayError> { match self { - hir_def::path::GenericArg::Type(ty) => ty.hir_fmt(f), + hir_def::path::GenericArg::Type(ty) => ty.hir_fmt(f, types_map), hir_def::path::GenericArg::Const(c) => { write!(f, "{}", c.display(f.db.upcast(), f.edition())) } diff --git a/src/tools/rust-analyzer/crates/hir-ty/src/dyn_compatibility.rs b/src/tools/rust-analyzer/crates/hir-ty/src/dyn_compatibility.rs index e0d1758210e..3d21785a70a 100644 --- a/src/tools/rust-analyzer/crates/hir-ty/src/dyn_compatibility.rs +++ b/src/tools/rust-analyzer/crates/hir-ty/src/dyn_compatibility.rs @@ -266,7 +266,7 @@ fn contains_illegal_self_type_reference<T: TypeVisitable<Interner>>( trait_self_param_idx: usize, allow_self_projection: AllowSelfProjection, } - impl<'a> TypeVisitor<Interner> for IllegalSelfTypeVisitor<'a> { + impl TypeVisitor<Interner> for IllegalSelfTypeVisitor<'_> { type BreakTy = (); fn as_dyn(&mut self) -> &mut dyn TypeVisitor<Interner, BreakTy = Self::BreakTy> { diff --git a/src/tools/rust-analyzer/crates/hir-ty/src/generics.rs b/src/tools/rust-analyzer/crates/hir-ty/src/generics.rs index 89ca707c2e6..c094bc39512 100644 --- a/src/tools/rust-analyzer/crates/hir-ty/src/generics.rs +++ b/src/tools/rust-analyzer/crates/hir-ty/src/generics.rs @@ -16,12 +16,13 @@ use hir_def::{ GenericParamDataRef, GenericParams, LifetimeParamData, TypeOrConstParamData, TypeParamProvenance, }, + type_ref::TypesMap, ConstParamId, GenericDefId, GenericParamId, ItemContainerId, LifetimeParamId, LocalLifetimeParamId, LocalTypeOrConstParamId, Lookup, TypeOrConstParamId, TypeParamId, }; -use intern::Interned; use itertools::chain; use stdx::TupleExt; +use triomphe::Arc; use crate::{db::HirDatabase, lt_to_placeholder_idx, to_placeholder_idx, Interner, Substitution}; @@ -34,7 +35,7 @@ pub(crate) fn generics(db: &dyn DefDatabase, def: GenericDefId) -> Generics { #[derive(Clone, Debug)] pub(crate) struct Generics { def: GenericDefId, - params: Interned<GenericParams>, + params: Arc<GenericParams>, parent_generics: Option<Box<Generics>>, has_trait_self_param: bool, } @@ -85,6 +86,18 @@ impl Generics { self.iter_self().chain(self.iter_parent()) } + pub(crate) fn iter_with_types_map( + &self, + ) -> impl Iterator<Item = ((GenericParamId, GenericParamDataRef<'_>), &TypesMap)> + '_ { + self.iter_self().zip(std::iter::repeat(&self.params.types_map)).chain( + self.iter_parent().zip( + self.parent_generics() + .into_iter() + .flat_map(|it| std::iter::repeat(&it.params.types_map)), + ), + ) + } + /// Iterate over the params without parent params. pub(crate) fn iter_self( &self, diff --git a/src/tools/rust-analyzer/crates/hir-ty/src/infer.rs b/src/tools/rust-analyzer/crates/hir-ty/src/infer.rs index 88334b492d5..3685ed56964 100644 --- a/src/tools/rust-analyzer/crates/hir-ty/src/infer.rs +++ b/src/tools/rust-analyzer/crates/hir-ty/src/infer.rs @@ -33,7 +33,7 @@ use chalk_ir::{ }; use either::Either; use hir_def::{ - body::Body, + body::{Body, HygieneId}, builtin_type::{BuiltinInt, BuiltinType, BuiltinUint}, data::{ConstData, StaticData}, hir::{BindingAnnotation, BindingId, ExprId, ExprOrPatId, LabelId, PatId}, @@ -41,7 +41,7 @@ use hir_def::{ layout::Integer, path::{ModPath, Path}, resolver::{HasResolver, ResolveValueResult, Resolver, TypeNs, ValueNs}, - type_ref::{LifetimeRef, TypeRef}, + type_ref::{LifetimeRef, TypeRefId, TypesMap}, AdtId, AssocItemId, DefWithBodyId, FieldId, FunctionId, ImplId, ItemContainerId, Lookup, TraitId, TupleFieldId, TupleId, TypeAliasId, VariantId, }; @@ -228,7 +228,7 @@ pub enum InferenceDiagnostic { id: ExprOrPatId, }, UnresolvedIdent { - expr: ExprId, + id: ExprOrPatId, }, // FIXME: This should be emitted in body lowering BreakOutsideOfLoop { @@ -482,12 +482,27 @@ impl InferenceResult { pub fn variant_resolution_for_pat(&self, id: PatId) -> Option<VariantId> { self.variant_resolutions.get(&id.into()).copied() } + pub fn variant_resolution_for_expr_or_pat(&self, id: ExprOrPatId) -> Option<VariantId> { + match id { + ExprOrPatId::ExprId(id) => self.variant_resolution_for_expr(id), + ExprOrPatId::PatId(id) => self.variant_resolution_for_pat(id), + } + } pub fn assoc_resolutions_for_expr(&self, id: ExprId) -> Option<(AssocItemId, Substitution)> { self.assoc_resolutions.get(&id.into()).cloned() } pub fn assoc_resolutions_for_pat(&self, id: PatId) -> Option<(AssocItemId, Substitution)> { self.assoc_resolutions.get(&id.into()).cloned() } + pub fn assoc_resolutions_for_expr_or_pat( + &self, + id: ExprOrPatId, + ) -> Option<(AssocItemId, Substitution)> { + match id { + ExprOrPatId::ExprId(id) => self.assoc_resolutions_for_expr(id), + ExprOrPatId::PatId(id) => self.assoc_resolutions_for_pat(id), + } + } pub fn type_mismatch_for_expr(&self, expr: ExprId) -> Option<&TypeMismatch> { self.type_mismatches.get(&expr.into()) } @@ -506,6 +521,12 @@ impl InferenceResult { pub fn closure_info(&self, closure: &ClosureId) -> &(Vec<CapturedItem>, FnTrait) { self.closure_info.get(closure).unwrap() } + pub fn type_of_expr_or_pat(&self, id: ExprOrPatId) -> Option<&Ty> { + match id { + ExprOrPatId::ExprId(id) => self.type_of_expr.get(id), + ExprOrPatId::PatId(id) => self.type_of_pat.get(id), + } + } } impl Index<ExprId> for InferenceResult { @@ -524,6 +545,14 @@ impl Index<PatId> for InferenceResult { } } +impl Index<ExprOrPatId> for InferenceResult { + type Output = Ty; + + fn index(&self, id: ExprOrPatId) -> &Ty { + self.type_of_expr_or_pat(id).unwrap_or(&self.standard_types.unknown) + } +} + impl Index<BindingId> for InferenceResult { type Output = Ty; @@ -561,6 +590,9 @@ pub(crate) struct InferenceContext<'a> { diverges: Diverges, breakables: Vec<BreakableContext>, + /// Whether we are inside the pattern of a destructuring assignment. + inside_assignment: bool, + deferred_cast_checks: Vec<CastCheck>, // fields related to closure capture @@ -656,6 +688,7 @@ impl<'a> InferenceContext<'a> { current_closure: None, deferred_closures: FxHashMap::default(), closure_dependencies: FxHashMap::default(), + inside_assignment: false, } } @@ -825,7 +858,7 @@ impl<'a> InferenceContext<'a> { } fn collect_const(&mut self, data: &ConstData) { - let return_ty = self.make_ty(&data.type_ref); + let return_ty = self.make_ty(data.type_ref, &data.types_map); // Constants might be defining usage sites of TAITs. self.make_tait_coercion_table(iter::once(&return_ty)); @@ -834,7 +867,7 @@ impl<'a> InferenceContext<'a> { } fn collect_static(&mut self, data: &StaticData) { - let return_ty = self.make_ty(&data.type_ref); + let return_ty = self.make_ty(data.type_ref, &data.types_map); // Statics might be defining usage sites of TAITs. self.make_tait_coercion_table(iter::once(&return_ty)); @@ -844,11 +877,11 @@ impl<'a> InferenceContext<'a> { fn collect_fn(&mut self, func: FunctionId) { let data = self.db.function_data(func); - let ctx = crate::lower::TyLoweringContext::new(self.db, &self.resolver, self.owner.into()) - .with_type_param_mode(ParamLoweringMode::Placeholder) - .with_impl_trait_mode(ImplTraitLoweringMode::Param); - let mut param_tys = - data.params.iter().map(|type_ref| ctx.lower_ty(type_ref)).collect::<Vec<_>>(); + let mut param_tys = self.with_ty_lowering(&data.types_map, |ctx| { + ctx.type_param_mode(ParamLoweringMode::Placeholder) + .impl_trait_mode(ImplTraitLoweringMode::Param); + data.params.iter().map(|&type_ref| ctx.lower_ty(type_ref)).collect::<Vec<_>>() + }); // Check if function contains a va_list, if it does then we append it to the parameter types // that are collected from the function data if data.is_varargs() { @@ -883,12 +916,13 @@ impl<'a> InferenceContext<'a> { tait_candidates.insert(ty); } } - let return_ty = &*data.ret_type; + let return_ty = data.ret_type; - let ctx = crate::lower::TyLoweringContext::new(self.db, &self.resolver, self.owner.into()) - .with_type_param_mode(ParamLoweringMode::Placeholder) - .with_impl_trait_mode(ImplTraitLoweringMode::Opaque); - let return_ty = ctx.lower_ty(return_ty); + let return_ty = self.with_ty_lowering(&data.types_map, |ctx| { + ctx.type_param_mode(ParamLoweringMode::Placeholder) + .impl_trait_mode(ImplTraitLoweringMode::Opaque) + .lower_ty(return_ty) + }); let return_ty = self.insert_type_vars(return_ty); let return_ty = if let Some(rpits) = self.db.return_type_impl_traits(func) { @@ -1022,7 +1056,7 @@ impl<'a> InferenceContext<'a> { non_assocs: FxHashMap<OpaqueTyId, Ty>, } - impl<'a, 'b> TypeVisitor<Interner> for TypeAliasImplTraitCollector<'a, 'b> { + impl TypeVisitor<Interner> for TypeAliasImplTraitCollector<'_, '_> { type BreakTy = (); fn as_dyn(&mut self) -> &mut dyn TypeVisitor<Interner, BreakTy = Self::BreakTy> { @@ -1192,20 +1226,43 @@ impl<'a> InferenceContext<'a> { self.result.diagnostics.push(diagnostic); } - fn make_ty(&mut self, type_ref: &TypeRef) -> Ty { - let ctx = crate::lower::TyLoweringContext::new(self.db, &self.resolver, self.owner.into()); - let ty = ctx.lower_ty(type_ref); + fn with_ty_lowering<R>( + &self, + types_map: &TypesMap, + f: impl FnOnce(&mut crate::lower::TyLoweringContext<'_>) -> R, + ) -> R { + let mut ctx = crate::lower::TyLoweringContext::new( + self.db, + &self.resolver, + types_map, + self.owner.into(), + ); + f(&mut ctx) + } + + fn with_body_ty_lowering<R>( + &self, + f: impl FnOnce(&mut crate::lower::TyLoweringContext<'_>) -> R, + ) -> R { + self.with_ty_lowering(&self.body.types, f) + } + + fn make_ty(&mut self, type_ref: TypeRefId, types_map: &TypesMap) -> Ty { + let ty = self.with_ty_lowering(types_map, |ctx| ctx.lower_ty(type_ref)); let ty = self.insert_type_vars(ty); self.normalize_associated_types_in(ty) } + fn make_body_ty(&mut self, type_ref: TypeRefId) -> Ty { + self.make_ty(type_ref, &self.body.types) + } + fn err_ty(&self) -> Ty { self.result.standard_types.unknown.clone() } fn make_lifetime(&mut self, lifetime_ref: &LifetimeRef) -> Lifetime { - let ctx = crate::lower::TyLoweringContext::new(self.db, &self.resolver, self.owner.into()); - let lt = ctx.lower_lifetime(lifetime_ref); + let lt = self.with_ty_lowering(TypesMap::EMPTY, |ctx| ctx.lower_lifetime(lifetime_ref)); self.insert_type_vars(lt) } @@ -1363,9 +1420,14 @@ impl<'a> InferenceContext<'a> { Some(path) => path, None => return (self.err_ty(), None), }; - let ctx = crate::lower::TyLoweringContext::new(self.db, &self.resolver, self.owner.into()); + let ctx = crate::lower::TyLoweringContext::new( + self.db, + &self.resolver, + &self.body.types, + self.owner.into(), + ); let (resolution, unresolved) = if value_ns { - match self.resolver.resolve_path_in_value_ns(self.db.upcast(), path) { + match self.resolver.resolve_path_in_value_ns(self.db.upcast(), path, HygieneId::ROOT) { Some(ResolveValueResult::ValueNs(value, _)) => match value { ValueNs::EnumVariantId(var) => { let substs = ctx.substs_from_path(path, var.into(), true); diff --git a/src/tools/rust-analyzer/crates/hir-ty/src/infer/closure.rs b/src/tools/rust-analyzer/crates/hir-ty/src/infer/closure.rs index e9825cf0998..5a251683b96 100644 --- a/src/tools/rust-analyzer/crates/hir-ty/src/infer/closure.rs +++ b/src/tools/rust-analyzer/crates/hir-ty/src/infer/closure.rs @@ -11,11 +11,12 @@ use either::Either; use hir_def::{ data::adt::VariantData, hir::{ - Array, AsmOperand, BinaryOp, BindingId, CaptureBy, Expr, ExprId, Pat, PatId, Statement, - UnaryOp, + Array, AsmOperand, BinaryOp, BindingId, CaptureBy, Expr, ExprId, ExprOrPatId, Pat, PatId, + Statement, UnaryOp, }, lang_item::LangItem, - resolver::{resolver_for_expr, ResolveValueResult, ValueNs}, + path::Path, + resolver::ValueNs, DefWithBodyId, FieldId, HasModule, TupleFieldId, TupleId, VariantId, }; use hir_expand::name::Name; @@ -282,11 +283,11 @@ impl CapturedItem { ProjectionElem::Deref => {} ProjectionElem::Field(Either::Left(f)) => { match &*f.parent.variant_data(db.upcast()) { - VariantData::Record(fields) => { + VariantData::Record { fields, .. } => { result.push('_'); result.push_str(fields[f.local_id].name.as_str()) } - VariantData::Tuple(fields) => { + VariantData::Tuple { fields, .. } => { let index = fields.iter().position(|it| it.0 == f.local_id); if let Some(index) = index { format_to!(result, "_{index}"); @@ -324,12 +325,12 @@ impl CapturedItem { ProjectionElem::Field(Either::Left(f)) => { let variant_data = f.parent.variant_data(db.upcast()); match &*variant_data { - VariantData::Record(fields) => format_to!( + VariantData::Record { fields, .. } => format_to!( result, ".{}", fields[f.local_id].name.display(db.upcast(), edition) ), - VariantData::Tuple(fields) => format_to!( + VariantData::Tuple { fields, .. } => format_to!( result, ".{}", fields.iter().position(|it| it.0 == f.local_id).unwrap_or_default() @@ -382,8 +383,10 @@ impl CapturedItem { } let variant_data = f.parent.variant_data(db.upcast()); let field = match &*variant_data { - VariantData::Record(fields) => fields[f.local_id].name.as_str().to_owned(), - VariantData::Tuple(fields) => fields + VariantData::Record { fields, .. } => { + fields[f.local_id].name.as_str().to_owned() + } + VariantData::Tuple { fields, .. } => fields .iter() .position(|it| it.0 == f.local_id) .unwrap_or_default() @@ -508,18 +511,39 @@ impl InferenceContext<'_> { apply_adjusts_to_place(&mut self.current_capture_span_stack, r, adjustments) } + /// Pushes the span into `current_capture_span_stack`, *without clearing it first*. + fn path_place(&mut self, path: &Path, id: ExprOrPatId) -> Option<HirPlace> { + if path.type_anchor().is_some() { + return None; + } + let hygiene = self.body.expr_or_pat_path_hygiene(id); + let result = self + .resolver + .resolve_path_in_value_ns_fully(self.db.upcast(), path, hygiene) + .and_then(|result| match result { + ValueNs::LocalBinding(binding) => { + let mir_span = match id { + ExprOrPatId::ExprId(id) => MirSpan::ExprId(id), + ExprOrPatId::PatId(id) => MirSpan::PatId(id), + }; + self.current_capture_span_stack.push(mir_span); + Some(HirPlace { local: binding, projections: Vec::new() }) + } + _ => None, + }); + result + } + /// Changes `current_capture_span_stack` to contain the stack of spans for this expr. fn place_of_expr_without_adjust(&mut self, tgt_expr: ExprId) -> Option<HirPlace> { self.current_capture_span_stack.clear(); match &self.body[tgt_expr] { Expr::Path(p) => { - let resolver = resolver_for_expr(self.db.upcast(), self.owner, tgt_expr); - if let Some(ResolveValueResult::ValueNs(ValueNs::LocalBinding(b), _)) = - resolver.resolve_path_in_value_ns(self.db.upcast(), p) - { - self.current_capture_span_stack.push(MirSpan::ExprId(tgt_expr)); - return Some(HirPlace { local: b, projections: vec![] }); - } + let resolver_guard = + self.resolver.update_to_inner_scope(self.db.upcast(), self.owner, tgt_expr); + let result = self.path_place(p, tgt_expr.into()); + self.resolver.reset_to_guard(resolver_guard); + return result; } Expr::Field { expr, name: _ } => { let mut place = self.place_of_expr(*expr)?; @@ -590,6 +614,16 @@ impl InferenceContext<'_> { } } + fn mutate_path_pat(&mut self, path: &Path, id: PatId) { + if let Some(place) = self.path_place(path, id.into()) { + self.add_capture( + place, + CaptureKind::ByRef(BorrowKind::Mut { kind: MutBorrowKind::Default }), + ); + self.current_capture_span_stack.pop(); // Remove the pattern span. + } + } + fn mutate_expr(&mut self, expr: ExprId, place: Option<HirPlace>) { if let Some(place) = place { self.add_capture( @@ -715,14 +749,14 @@ impl InferenceContext<'_> { Statement::Expr { expr, has_semi: _ } => { self.consume_expr(*expr); } - Statement::Item => (), + Statement::Item(_) => (), } } if let Some(tail) = tail { self.consume_expr(*tail); } } - Expr::Call { callee, args, is_assignee_expr: _ } => { + Expr::Call { callee, args } => { self.consume_expr(*callee); self.consume_exprs(args.iter().copied()); } @@ -838,7 +872,7 @@ impl InferenceContext<'_> { self.consume_expr(expr); } } - Expr::Index { base, index, is_assignee_expr: _ } => { + Expr::Index { base, index } => { self.select_from_expr(*base); self.consume_expr(*index); } @@ -862,10 +896,30 @@ impl InferenceContext<'_> { })); self.current_captures = cc; } - Expr::Array(Array::ElementList { elements: exprs, is_assignee_expr: _ }) - | Expr::Tuple { exprs, is_assignee_expr: _ } => { + Expr::Array(Array::ElementList { elements: exprs }) | Expr::Tuple { exprs } => { self.consume_exprs(exprs.iter().copied()) } + &Expr::Assignment { target, value } => { + self.walk_expr(value); + let resolver_guard = + self.resolver.update_to_inner_scope(self.db.upcast(), self.owner, tgt_expr); + match self.place_of_expr(value) { + Some(rhs_place) => { + self.inside_assignment = true; + self.consume_with_pat(rhs_place, target); + self.inside_assignment = false; + } + None => self.body.walk_pats(target, &mut |pat| match &self.body[pat] { + Pat::Path(path) => self.mutate_path_pat(path, pat), + &Pat::Expr(expr) => { + let place = self.place_of_expr(expr); + self.mutate_expr(expr, place); + } + _ => {} + }), + } + self.resolver.reset_to_guard(resolver_guard); + } Expr::Missing | Expr::Continue { .. } @@ -903,6 +957,7 @@ impl InferenceContext<'_> { | Pat::Missing | Pat::Wild | Pat::Tuple { .. } + | Pat::Expr(_) | Pat::Or(_) => (), Pat::TupleStruct { .. } | Pat::Record { .. } => { if let Some(variant) = self.result.variant_resolution_for_pat(p) { @@ -1122,11 +1177,15 @@ impl InferenceContext<'_> { } } } - Pat::Range { .. } - | Pat::Slice { .. } - | Pat::ConstBlock(_) - | Pat::Path(_) - | Pat::Lit(_) => self.consume_place(place), + Pat::Range { .. } | Pat::Slice { .. } | Pat::ConstBlock(_) | Pat::Lit(_) => { + self.consume_place(place) + } + Pat::Path(path) => { + if self.inside_assignment { + self.mutate_path_pat(path, tgt_pat); + } + self.consume_place(place); + } &Pat::Bind { id, subpat: _ } => { let mode = self.result.binding_modes[tgt_pat]; let capture_kind = match mode { @@ -1180,6 +1239,15 @@ impl InferenceContext<'_> { self.current_capture_span_stack.pop(); } Pat::Box { .. } => (), // not supported + &Pat::Expr(expr) => { + self.consume_place(place); + let pat_capture_span_stack = mem::take(&mut self.current_capture_span_stack); + let old_inside_assignment = mem::replace(&mut self.inside_assignment, false); + let lhs_place = self.place_of_expr(expr); + self.mutate_expr(expr, lhs_place); + self.inside_assignment = old_inside_assignment; + self.current_capture_span_stack = pat_capture_span_stack; + } } } self.current_capture_span_stack diff --git a/src/tools/rust-analyzer/crates/hir-ty/src/infer/expr.rs b/src/tools/rust-analyzer/crates/hir-ty/src/infer/expr.rs index 657e4d77966..32b4ea2f28b 100644 --- a/src/tools/rust-analyzer/crates/hir-ty/src/infer/expr.rs +++ b/src/tools/rust-analyzer/crates/hir-ty/src/infer/expr.rs @@ -9,8 +9,8 @@ use chalk_ir::{cast::Cast, fold::Shift, DebruijnIndex, Mutability, TyVariableKin use either::Either; use hir_def::{ hir::{ - ArithOp, Array, AsmOperand, AsmOptions, BinaryOp, ClosureKind, Expr, ExprId, LabelId, - Literal, Pat, PatId, Statement, UnaryOp, + ArithOp, Array, AsmOperand, AsmOptions, BinaryOp, ClosureKind, Expr, ExprId, ExprOrPatId, + LabelId, Literal, Pat, PatId, Statement, UnaryOp, }, lang_item::{LangItem, LangItemTarget}, path::{GenericArg, GenericArgs, Path}, @@ -188,6 +188,9 @@ impl InferenceContext<'_> { | Pat::ConstBlock(_) | Pat::Record { .. } | Pat::Missing => true, + Pat::Expr(_) => unreachable!( + "we don't call pat_guaranteed_to_constitute_read_for_never() with assignments" + ), } } @@ -195,10 +198,14 @@ impl InferenceContext<'_> { match &self.body[expr] { // Lang item paths cannot currently be local variables or statics. Expr::Path(Path::LangItem(_, _)) => false, - Expr::Path(Path::Normal { type_anchor: Some(_), .. }) => false, + Expr::Path(Path::Normal(path)) => path.type_anchor().is_none(), Expr::Path(path) => self .resolver - .resolve_path_in_value_ns_fully(self.db.upcast(), path) + .resolve_path_in_value_ns_fully( + self.db.upcast(), + path, + self.body.expr_path_hygiene(expr), + ) .map_or(true, |res| matches!(res, ValueNs::LocalBinding(_) | ValueNs::StaticId(_))), Expr::Underscore => true, Expr::UnaryOp { op: UnaryOp::Deref, .. } => true, @@ -223,6 +230,7 @@ impl InferenceContext<'_> { | Expr::Const(..) | Expr::UnaryOp { .. } | Expr::BinaryOp { .. } + | Expr::Assignment { .. } | Expr::Yield { .. } | Expr::Cast { .. } | Expr::Async { .. } @@ -374,7 +382,7 @@ impl InferenceContext<'_> { // collect explicitly written argument types for arg_type in arg_types.iter() { let arg_ty = match arg_type { - Some(type_ref) => self.make_ty(type_ref), + Some(type_ref) => self.make_body_ty(*type_ref), None => self.table.new_type_var(), }; sig_tys.push(arg_ty); @@ -382,7 +390,7 @@ impl InferenceContext<'_> { // add return type let ret_ty = match ret_type { - Some(type_ref) => self.make_ty(type_ref), + Some(type_ref) => self.make_body_ty(*type_ref), None => self.table.new_type_var(), }; if let ClosureKind::Async = closure_kind { @@ -609,23 +617,7 @@ impl InferenceContext<'_> { coerce.complete(self) } } - Expr::Path(p) => { - let g = self.resolver.update_to_inner_scope(self.db.upcast(), self.owner, tgt_expr); - let ty = match self.infer_path(p, tgt_expr.into()) { - Some(ty) => ty, - None => { - if matches!(p, Path::Normal { mod_path, .. } if mod_path.is_ident() || mod_path.is_self()) - { - self.push_diagnostic(InferenceDiagnostic::UnresolvedIdent { - expr: tgt_expr, - }); - } - self.err_ty() - } - }; - self.resolver.reset_to_guard(g); - ty - } + Expr::Path(p) => self.infer_expr_path(p, tgt_expr.into(), tgt_expr), &Expr::Continue { label } => { if find_continuable(&mut self.breakables, label).is_none() { self.push_diagnostic(InferenceDiagnostic::BreakOutsideOfLoop { @@ -794,7 +786,7 @@ impl InferenceContext<'_> { self.resolve_associated_type(inner_ty, self.resolve_future_future_output()) } Expr::Cast { expr, type_ref } => { - let cast_ty = self.make_ty(type_ref); + let cast_ty = self.make_body_ty(*type_ref); let expr_ty = self.infer_expr( *expr, &Expectation::Castable(cast_ty.clone()), @@ -892,36 +884,6 @@ impl InferenceContext<'_> { } } Expr::BinaryOp { lhs, rhs, op } => match op { - Some(BinaryOp::Assignment { op: None }) => { - let lhs = *lhs; - let is_ordinary = match &self.body[lhs] { - Expr::Array(_) - | Expr::RecordLit { .. } - | Expr::Tuple { .. } - | Expr::Underscore => false, - Expr::Call { callee, .. } => !matches!(&self.body[*callee], Expr::Path(_)), - _ => true, - }; - - // In ordinary (non-destructuring) assignments, the type of - // `lhs` must be inferred first so that the ADT fields - // instantiations in RHS can be coerced to it. Note that this - // cannot happen in destructuring assignments because of how - // they are desugared. - if is_ordinary { - // LHS of assignment doesn't constitute reads. - let lhs_ty = self.infer_expr(lhs, &Expectation::none(), ExprIsRead::No); - self.infer_expr_coerce( - *rhs, - &Expectation::has_type(lhs_ty), - ExprIsRead::No, - ); - } else { - let rhs_ty = self.infer_expr(*rhs, &Expectation::none(), ExprIsRead::Yes); - self.infer_assignee_expr(lhs, &rhs_ty); - } - self.result.standard_types.unit.clone() - } Some(BinaryOp::LogicOp(_)) => { let bool_ty = self.result.standard_types.bool_.clone(); self.infer_expr_coerce( @@ -942,6 +904,35 @@ impl InferenceContext<'_> { Some(op) => self.infer_overloadable_binop(*lhs, *op, *rhs, tgt_expr), _ => self.err_ty(), }, + &Expr::Assignment { target, value } => { + // In ordinary (non-destructuring) assignments, the type of + // `lhs` must be inferred first so that the ADT fields + // instantiations in RHS can be coerced to it. Note that this + // cannot happen in destructuring assignments because of how + // they are desugared. + let lhs_ty = match &self.body[target] { + // LHS of assignment doesn't constitute reads. + &Pat::Expr(expr) => { + Some(self.infer_expr(expr, &Expectation::none(), ExprIsRead::No)) + } + Pat::Path(path) => Some(self.infer_expr_path(path, target.into(), tgt_expr)), + _ => None, + }; + + if let Some(lhs_ty) = lhs_ty { + self.write_pat_ty(target, lhs_ty.clone()); + self.infer_expr_coerce(value, &Expectation::has_type(lhs_ty), ExprIsRead::No); + } else { + let rhs_ty = self.infer_expr(value, &Expectation::none(), ExprIsRead::Yes); + let resolver_guard = + self.resolver.update_to_inner_scope(self.db.upcast(), self.owner, tgt_expr); + self.inside_assignment = true; + self.infer_top_pat(target, &rhs_ty); + self.inside_assignment = false; + self.resolver.reset_to_guard(resolver_guard); + } + self.result.standard_types.unit.clone() + } Expr::Range { lhs, rhs, range_type } => { let lhs_ty = lhs.map(|e| self.infer_expr_inner(e, &Expectation::none(), ExprIsRead::Yes)); @@ -981,7 +972,7 @@ impl InferenceContext<'_> { (RangeOp::Inclusive, _, None) => self.err_ty(), } } - Expr::Index { base, index, is_assignee_expr } => { + Expr::Index { base, index } => { let base_ty = self.infer_expr_inner(*base, &Expectation::none(), ExprIsRead::Yes); let index_ty = self.infer_expr(*index, &Expectation::none(), ExprIsRead::Yes); @@ -1017,23 +1008,11 @@ impl InferenceContext<'_> { self.write_method_resolution(tgt_expr, func, subst); } let assoc = self.resolve_ops_index_output(); - let res = self.resolve_associated_type_with_params( + self.resolve_associated_type_with_params( self_ty.clone(), assoc, &[index_ty.clone().cast(Interner)], - ); - - if *is_assignee_expr { - if let Some(index_trait) = self.resolve_lang_trait(LangItem::IndexMut) { - let trait_ref = TyBuilder::trait_ref(self.db, index_trait) - .push(self_ty) - .fill(|_| index_ty.clone().cast(Interner)) - .build(); - self.push_obligation(trait_ref.cast(Interner)); - } - } - - res + ) } else { self.err_ty() } @@ -1151,9 +1130,7 @@ impl InferenceContext<'_> { }, }, Expr::Underscore => { - // Underscore expressions may only appear in assignee expressions, - // which are handled by `infer_assignee_expr()`. - // Any other underscore expression is an error, we render a specialized diagnostic + // Underscore expression is an error, we render a specialized diagnostic // to let the user know what type is expected though. let expected = expected.to_option(&mut self.table).unwrap_or_else(|| self.err_ty()); self.push_diagnostic(InferenceDiagnostic::TypedHole { @@ -1232,6 +1209,22 @@ impl InferenceContext<'_> { ty } + fn infer_expr_path(&mut self, path: &Path, id: ExprOrPatId, scope_id: ExprId) -> Ty { + let g = self.resolver.update_to_inner_scope(self.db.upcast(), self.owner, scope_id); + let ty = match self.infer_path(path, id) { + Some(ty) => ty, + None => { + if path.mod_path().is_some_and(|mod_path| mod_path.is_ident() || mod_path.is_self()) + { + self.push_diagnostic(InferenceDiagnostic::UnresolvedIdent { id }); + } + self.err_ty() + } + }; + self.resolver.reset_to_guard(g); + ty + } + fn infer_async_block( &mut self, tgt_expr: ExprId, @@ -1482,107 +1475,6 @@ impl InferenceContext<'_> { } } - pub(super) fn infer_assignee_expr(&mut self, lhs: ExprId, rhs_ty: &Ty) -> Ty { - let is_rest_expr = |expr| { - matches!( - &self.body[expr], - Expr::Range { lhs: None, rhs: None, range_type: RangeOp::Exclusive }, - ) - }; - - let rhs_ty = self.resolve_ty_shallow(rhs_ty); - - let ty = match &self.body[lhs] { - Expr::Tuple { exprs, .. } => { - // We don't consider multiple ellipses. This is analogous to - // `hir_def::body::lower::ExprCollector::collect_tuple_pat()`. - let ellipsis = exprs.iter().position(|e| is_rest_expr(*e)).map(|it| it as u32); - let exprs: Vec<_> = exprs.iter().filter(|e| !is_rest_expr(**e)).copied().collect(); - - self.infer_tuple_pat_like(&rhs_ty, (), ellipsis, &exprs) - } - Expr::Call { callee, args, .. } => { - // Tuple structs - let path = match &self.body[*callee] { - Expr::Path(path) => Some(path), - _ => None, - }; - - // We don't consider multiple ellipses. This is analogous to - // `hir_def::body::lower::ExprCollector::collect_tuple_pat()`. - let ellipsis = args.iter().position(|e| is_rest_expr(*e)).map(|it| it as u32); - let args: Vec<_> = args.iter().filter(|e| !is_rest_expr(**e)).copied().collect(); - - self.infer_tuple_struct_pat_like(path, &rhs_ty, (), lhs, ellipsis, &args) - } - Expr::Array(Array::ElementList { elements, .. }) => { - let elem_ty = match rhs_ty.kind(Interner) { - TyKind::Array(st, _) => st.clone(), - _ => self.err_ty(), - }; - - // There's no need to handle `..` as it cannot be bound. - let sub_exprs = elements.iter().filter(|e| !is_rest_expr(**e)); - - for e in sub_exprs { - self.infer_assignee_expr(*e, &elem_ty); - } - - match rhs_ty.kind(Interner) { - TyKind::Array(_, _) => rhs_ty.clone(), - // Even when `rhs_ty` is not an array type, this assignee - // expression is inferred to be an array (of unknown element - // type and length). This should not be just an error type, - // because we are to compute the unifiability of this type and - // `rhs_ty` in the end of this function to issue type mismatches. - _ => TyKind::Array( - self.err_ty(), - crate::consteval::usize_const(self.db, None, self.resolver.krate()), - ) - .intern(Interner), - } - } - Expr::RecordLit { path, fields, .. } => { - let subs = fields.iter().map(|f| (f.name.clone(), f.expr)); - - self.infer_record_pat_like(path.as_deref(), &rhs_ty, (), lhs, subs) - } - Expr::Underscore => rhs_ty.clone(), - _ => { - // `lhs` is a place expression, a unit struct, or an enum variant. - // LHS of assignment doesn't constitute reads. - let lhs_ty = self.infer_expr_inner(lhs, &Expectation::none(), ExprIsRead::No); - - // This is the only branch where this function may coerce any type. - // We are returning early to avoid the unifiability check below. - let lhs_ty = self.insert_type_vars_shallow(lhs_ty); - let ty = match self.coerce(None, &rhs_ty, &lhs_ty, CoerceNever::Yes) { - Ok(ty) => ty, - Err(_) => { - self.result.type_mismatches.insert( - lhs.into(), - TypeMismatch { expected: rhs_ty.clone(), actual: lhs_ty.clone() }, - ); - // `rhs_ty` is returned so no further type mismatches are - // reported because of this mismatch. - rhs_ty - } - }; - self.write_expr_ty(lhs, ty.clone()); - return ty; - } - }; - - let ty = self.insert_type_vars_shallow(ty); - if !self.unify(&ty, &rhs_ty) { - self.result - .type_mismatches - .insert(lhs.into(), TypeMismatch { expected: rhs_ty.clone(), actual: ty.clone() }); - } - self.write_expr_ty(lhs, ty.clone()); - ty - } - fn infer_overloadable_binop( &mut self, lhs: ExprId, @@ -1706,7 +1598,7 @@ impl InferenceContext<'_> { Statement::Let { pat, type_ref, initializer, else_branch } => { let decl_ty = type_ref .as_ref() - .map(|tr| this.make_ty(tr)) + .map(|&tr| this.make_body_ty(tr)) .unwrap_or_else(|| this.table.new_type_var()); let ty = if let Some(expr) = initializer { @@ -1764,7 +1656,7 @@ impl InferenceContext<'_> { ); } } - Statement::Item => (), + Statement::Item(_) => (), } } @@ -2249,7 +2141,8 @@ impl InferenceContext<'_> { kind_id, args.next().unwrap(), // `peek()` is `Some(_)`, so guaranteed no panic self, - |this, type_ref| this.make_ty(type_ref), + &self.body.types, + |this, type_ref| this.make_body_ty(type_ref), |this, c, ty| { const_or_path_to_chalk( this.db, diff --git a/src/tools/rust-analyzer/crates/hir-ty/src/infer/mutability.rs b/src/tools/rust-analyzer/crates/hir-ty/src/infer/mutability.rs index 6a0daee6ea9..d74a383f44e 100644 --- a/src/tools/rust-analyzer/crates/hir-ty/src/infer/mutability.rs +++ b/src/tools/rust-analyzer/crates/hir-ty/src/infer/mutability.rs @@ -4,7 +4,8 @@ use chalk_ir::{cast::Cast, Mutability}; use hir_def::{ hir::{ - Array, AsmOperand, BinaryOp, BindingAnnotation, Expr, ExprId, PatId, Statement, UnaryOp, + Array, AsmOperand, BinaryOp, BindingAnnotation, Expr, ExprId, Pat, PatId, Statement, + UnaryOp, }, lang_item::LangItem, }; @@ -88,7 +89,7 @@ impl InferenceContext<'_> { Statement::Expr { expr, has_semi: _ } => { self.infer_mut_expr(*expr, Mutability::Not); } - Statement::Item => (), + Statement::Item(_) => (), } } if let Some(tail) = tail { @@ -96,7 +97,7 @@ impl InferenceContext<'_> { } } Expr::MethodCall { receiver: it, method_name: _, args, generic_args: _ } - | Expr::Call { callee: it, args, is_assignee_expr: _ } => { + | Expr::Call { callee: it, args } => { self.infer_mut_not_expr_iter(args.iter().copied().chain(Some(*it))); } Expr::Match { expr, arms } => { @@ -120,10 +121,10 @@ impl InferenceContext<'_> { Expr::Become { expr } => { self.infer_mut_expr(*expr, Mutability::Not); } - Expr::RecordLit { path: _, fields, spread, ellipsis: _, is_assignee_expr: _ } => { + Expr::RecordLit { path: _, fields, spread } => { self.infer_mut_not_expr_iter(fields.iter().map(|it| it.expr).chain(*spread)) } - &Expr::Index { base, index, is_assignee_expr } => { + &Expr::Index { base, index } => { if mutability == Mutability::Mut { if let Some((f, _)) = self.result.method_resolutions.get_mut(&tgt_expr) { if let Some(index_trait) = self @@ -148,11 +149,8 @@ impl InferenceContext<'_> { target, }) = base_adjustments { - // For assignee exprs `IndexMut` obligations are already applied - if !is_assignee_expr { - if let TyKind::Ref(_, _, ty) = target.kind(Interner) { - base_ty = Some(ty.clone()); - } + if let TyKind::Ref(_, _, ty) = target.kind(Interner) { + base_ty = Some(ty.clone()); } *mutability = Mutability::Mut; } @@ -233,6 +231,14 @@ impl InferenceContext<'_> { self.infer_mut_expr(*lhs, Mutability::Mut); self.infer_mut_expr(*rhs, Mutability::Not); } + &Expr::Assignment { target, value } => { + self.body.walk_pats(target, &mut |pat| match self.body[pat] { + Pat::Expr(expr) => self.infer_mut_expr(expr, Mutability::Mut), + Pat::ConstBlock(block) => self.infer_mut_expr(block, Mutability::Not), + _ => {} + }); + self.infer_mut_expr(value, Mutability::Not); + } Expr::Array(Array::Repeat { initializer: lhs, repeat: rhs }) | Expr::BinaryOp { lhs, rhs, op: _ } | Expr::Range { lhs: Some(lhs), rhs: Some(rhs), range_type: _ } => { @@ -242,8 +248,7 @@ impl InferenceContext<'_> { Expr::Closure { body, .. } => { self.infer_mut_expr(*body, Mutability::Not); } - Expr::Tuple { exprs, is_assignee_expr: _ } - | Expr::Array(Array::ElementList { elements: exprs, is_assignee_expr: _ }) => { + Expr::Tuple { exprs } | Expr::Array(Array::ElementList { elements: exprs }) => { self.infer_mut_not_expr_iter(exprs.iter().copied()); } // These don't need any action, as they don't have sub expressions diff --git a/src/tools/rust-analyzer/crates/hir-ty/src/infer/pat.rs b/src/tools/rust-analyzer/crates/hir-ty/src/infer/pat.rs index fee6755408e..50e761196ec 100644 --- a/src/tools/rust-analyzer/crates/hir-ty/src/infer/pat.rs +++ b/src/tools/rust-analyzer/crates/hir-ty/src/infer/pat.rs @@ -4,7 +4,7 @@ use std::iter::repeat_with; use hir_def::{ body::Body, - hir::{Binding, BindingAnnotation, BindingId, Expr, ExprId, ExprOrPatId, Literal, Pat, PatId}, + hir::{Binding, BindingAnnotation, BindingId, Expr, ExprId, Literal, Pat, PatId}, path::Path, }; use hir_expand::name::Name; @@ -12,63 +12,28 @@ use stdx::TupleExt; use crate::{ consteval::{try_const_usize, usize_const}, - infer::{expr::ExprIsRead, BindingMode, Expectation, InferenceContext, TypeMismatch}, + infer::{ + coerce::CoerceNever, expr::ExprIsRead, BindingMode, Expectation, InferenceContext, + TypeMismatch, + }, lower::lower_to_chalk_mutability, primitive::UintTy, static_lifetime, InferenceDiagnostic, Interner, Mutability, Scalar, Substitution, Ty, TyBuilder, TyExt, TyKind, }; -/// Used to generalize patterns and assignee expressions. -pub(super) trait PatLike: Into<ExprOrPatId> + Copy { - type BindingMode: Copy; - - fn infer( - this: &mut InferenceContext<'_>, - id: Self, - expected_ty: &Ty, - default_bm: Self::BindingMode, - ) -> Ty; -} - -impl PatLike for ExprId { - type BindingMode = (); - - fn infer( - this: &mut InferenceContext<'_>, - id: Self, - expected_ty: &Ty, - (): Self::BindingMode, - ) -> Ty { - this.infer_assignee_expr(id, expected_ty) - } -} - -impl PatLike for PatId { - type BindingMode = BindingMode; - - fn infer( - this: &mut InferenceContext<'_>, - id: Self, - expected_ty: &Ty, - default_bm: Self::BindingMode, - ) -> Ty { - this.infer_pat(id, expected_ty, default_bm) - } -} - impl InferenceContext<'_> { /// Infers type for tuple struct pattern or its corresponding assignee expression. /// /// Ellipses found in the original pattern or expression must be filtered out. - pub(super) fn infer_tuple_struct_pat_like<T: PatLike>( + pub(super) fn infer_tuple_struct_pat_like( &mut self, path: Option<&Path>, expected: &Ty, - default_bm: T::BindingMode, - id: T, + default_bm: BindingMode, + id: PatId, ellipsis: Option<u32>, - subs: &[T], + subs: &[PatId], ) -> Ty { let (ty, def) = self.resolve_variant(path, true); let var_data = def.map(|it| it.variant_data(self.db.upcast())); @@ -127,13 +92,13 @@ impl InferenceContext<'_> { } }; - T::infer(self, subpat, &expected_ty, default_bm); + self.infer_pat(subpat, &expected_ty, default_bm); } } None => { let err_ty = self.err_ty(); for &inner in subs { - T::infer(self, inner, &err_ty, default_bm); + self.infer_pat(inner, &err_ty, default_bm); } } } @@ -142,13 +107,13 @@ impl InferenceContext<'_> { } /// Infers type for record pattern or its corresponding assignee expression. - pub(super) fn infer_record_pat_like<T: PatLike>( + pub(super) fn infer_record_pat_like( &mut self, path: Option<&Path>, expected: &Ty, - default_bm: T::BindingMode, - id: T, - subs: impl ExactSizeIterator<Item = (Name, T)>, + default_bm: BindingMode, + id: PatId, + subs: impl ExactSizeIterator<Item = (Name, PatId)>, ) -> Ty { let (ty, def) = self.resolve_variant(path, false); if let Some(variant) = def { @@ -197,13 +162,13 @@ impl InferenceContext<'_> { } }; - T::infer(self, inner, &expected_ty, default_bm); + self.infer_pat(inner, &expected_ty, default_bm); } } None => { let err_ty = self.err_ty(); for (_, inner) in subs { - T::infer(self, inner, &err_ty, default_bm); + self.infer_pat(inner, &err_ty, default_bm); } } } @@ -214,12 +179,12 @@ impl InferenceContext<'_> { /// Infers type for tuple pattern or its corresponding assignee expression. /// /// Ellipses found in the original pattern or expression must be filtered out. - pub(super) fn infer_tuple_pat_like<T: PatLike>( + pub(super) fn infer_tuple_pat_like( &mut self, expected: &Ty, - default_bm: T::BindingMode, + default_bm: BindingMode, ellipsis: Option<u32>, - subs: &[T], + subs: &[PatId], ) -> Ty { let expected = self.resolve_ty_shallow(expected); let expectations = match expected.as_tuple() { @@ -244,18 +209,20 @@ impl InferenceContext<'_> { // Process pre for (ty, pat) in inner_tys.iter_mut().zip(pre) { - *ty = T::infer(self, *pat, ty, default_bm); + *ty = self.infer_pat(*pat, ty, default_bm); } // Process post for (ty, pat) in inner_tys.iter_mut().skip(pre.len() + n_uncovered_patterns).zip(post) { - *ty = T::infer(self, *pat, ty, default_bm); + *ty = self.infer_pat(*pat, ty, default_bm); } TyKind::Tuple(inner_tys.len(), Substitution::from_iter(Interner, inner_tys)) .intern(Interner) } + /// The resolver needs to be updated to the surrounding expression when inside assignment + /// (because there, `Pat::Path` can refer to a variable). pub(super) fn infer_top_pat(&mut self, pat: PatId, expected: &Ty) { self.infer_pat(pat, expected, BindingMode::default()); } @@ -263,7 +230,14 @@ impl InferenceContext<'_> { fn infer_pat(&mut self, pat: PatId, expected: &Ty, mut default_bm: BindingMode) -> Ty { let mut expected = self.resolve_ty_shallow(expected); - if self.is_non_ref_pat(self.body, pat) { + if matches!(&self.body[pat], Pat::Ref { .. }) || self.inside_assignment { + cov_mark::hit!(match_ergonomics_ref); + // When you encounter a `&pat` pattern, reset to Move. + // This is so that `w` is by value: `let (_, &w) = &(1, &2);` + // Destructuring assignments also reset the binding mode and + // don't do match ergonomics. + default_bm = BindingMode::Move; + } else if self.is_non_ref_pat(self.body, pat) { let mut pat_adjustments = Vec::new(); while let Some((inner, _lifetime, mutability)) = expected.as_reference() { pat_adjustments.push(expected.clone()); @@ -279,11 +253,6 @@ impl InferenceContext<'_> { pat_adjustments.shrink_to_fit(); self.result.pat_adjustments.insert(pat, pat_adjustments); } - } else if let Pat::Ref { .. } = &self.body[pat] { - cov_mark::hit!(match_ergonomics_ref); - // When you encounter a `&pat` pattern, reset to Move. - // This is so that `w` is by value: `let (_, &w) = &(1, &2);` - default_bm = BindingMode::Move; } // Lose mutability. @@ -320,8 +289,34 @@ impl InferenceContext<'_> { self.infer_record_pat_like(p.as_deref(), &expected, default_bm, pat, subs) } Pat::Path(path) => { - // FIXME update resolver for the surrounding expression - self.infer_path(path, pat.into()).unwrap_or_else(|| self.err_ty()) + let ty = self.infer_path(path, pat.into()).unwrap_or_else(|| self.err_ty()); + let ty_inserted_vars = self.insert_type_vars_shallow(ty.clone()); + match self.table.coerce(&expected, &ty_inserted_vars, CoerceNever::Yes) { + Ok((adjustments, coerced_ty)) => { + if !adjustments.is_empty() { + self.result + .pat_adjustments + .entry(pat) + .or_default() + .extend(adjustments.into_iter().map(|adjust| adjust.target)); + } + self.write_pat_ty(pat, coerced_ty); + return self.pat_ty_after_adjustment(pat); + } + Err(_) => { + self.result.type_mismatches.insert( + pat.into(), + TypeMismatch { + expected: expected.clone(), + actual: ty_inserted_vars.clone(), + }, + ); + self.write_pat_ty(pat, ty); + // We return `expected` to prevent cascading errors. I guess an alternative is to + // not emit type mismatches for error types and emit an error type here. + return expected; + } + } } Pat::Bind { id, subpat } => { return self.infer_bind_pat(pat, *id, default_bm, *subpat, &expected); @@ -361,7 +356,40 @@ impl InferenceContext<'_> { None => self.err_ty(), }, Pat::ConstBlock(expr) => { - self.infer_expr(*expr, &Expectation::has_type(expected.clone()), ExprIsRead::Yes) + let old_inside_assign = std::mem::replace(&mut self.inside_assignment, false); + let result = self.infer_expr( + *expr, + &Expectation::has_type(expected.clone()), + ExprIsRead::Yes, + ); + self.inside_assignment = old_inside_assign; + result + } + Pat::Expr(expr) => { + let old_inside_assign = std::mem::replace(&mut self.inside_assignment, false); + // LHS of assignment doesn't constitute reads. + let result = self.infer_expr_coerce( + *expr, + &Expectation::has_type(expected.clone()), + ExprIsRead::No, + ); + // We are returning early to avoid the unifiability check below. + let lhs_ty = self.insert_type_vars_shallow(result); + let ty = match self.coerce(None, &expected, &lhs_ty, CoerceNever::Yes) { + Ok(ty) => ty, + Err(_) => { + self.result.type_mismatches.insert( + pat.into(), + TypeMismatch { expected: expected.clone(), actual: lhs_ty.clone() }, + ); + // `rhs_ty` is returned so no further type mismatches are + // reported because of this mismatch. + expected + } + }; + self.write_pat_ty(pat, ty.clone()); + self.inside_assignment = old_inside_assign; + return ty; } Pat::Missing => self.err_ty(), }; @@ -517,9 +545,12 @@ impl InferenceContext<'_> { body[*expr], Expr::Literal(Literal::String(..) | Literal::CString(..) | Literal::ByteString(..)) ), - Pat::Wild | Pat::Bind { .. } | Pat::Ref { .. } | Pat::Box { .. } | Pat::Missing => { - false - } + Pat::Wild + | Pat::Bind { .. } + | Pat::Ref { .. } + | Pat::Box { .. } + | Pat::Missing + | Pat::Expr(_) => false, } } } diff --git a/src/tools/rust-analyzer/crates/hir-ty/src/infer/path.rs b/src/tools/rust-analyzer/crates/hir-ty/src/infer/path.rs index e4841c7b15b..442daa9f9ee 100644 --- a/src/tools/rust-analyzer/crates/hir-ty/src/infer/path.rs +++ b/src/tools/rust-analyzer/crates/hir-ty/src/infer/path.rs @@ -94,8 +94,7 @@ impl InferenceContext<'_> { return Some(ValuePathResolution::NonGeneric(ty)); }; - let ctx = crate::lower::TyLoweringContext::new(self.db, &self.resolver, self.owner.into()); - let substs = ctx.substs_from_path(path, value_def, true); + let substs = self.with_body_ty_lowering(|ctx| ctx.substs_from_path(path, value_def, true)); let substs = substs.as_slice(Interner); if let ValueNs::EnumVariantId(_) = value { @@ -152,8 +151,12 @@ impl InferenceContext<'_> { let last = path.segments().last()?; // Don't use `self.make_ty()` here as we need `orig_ns`. - let ctx = - crate::lower::TyLoweringContext::new(self.db, &self.resolver, self.owner.into()); + let ctx = crate::lower::TyLoweringContext::new( + self.db, + &self.resolver, + &self.body.types, + self.owner.into(), + ); let (ty, orig_ns) = ctx.lower_ty_ext(type_ref); let ty = self.table.insert_type_vars(ty); let ty = self.table.normalize_associated_types_in(ty); @@ -164,9 +167,10 @@ impl InferenceContext<'_> { let ty = self.table.normalize_associated_types_in(ty); self.resolve_ty_assoc_item(ty, last.name, id).map(|(it, substs)| (it, Some(substs)))? } else { + let hygiene = self.body.expr_or_pat_path_hygiene(id); // FIXME: report error, unresolved first path segment let value_or_partial = - self.resolver.resolve_path_in_value_ns(self.db.upcast(), path)?; + self.resolver.resolve_path_in_value_ns(self.db.upcast(), path, hygiene)?; match value_or_partial { ResolveValueResult::ValueNs(it, _) => (it, None), @@ -218,7 +222,7 @@ impl InferenceContext<'_> { let _d; let (resolved_segment, remaining_segments) = match path { - Path::Normal { .. } => { + Path::Normal { .. } | Path::BarePath(_) => { assert!(remaining_index < path.segments().len()); ( path.segments().get(remaining_index - 1).unwrap(), @@ -242,17 +246,10 @@ impl InferenceContext<'_> { (TypeNs::TraitId(trait_), true) => { let segment = remaining_segments.last().expect("there should be at least one segment here"); - let ctx = crate::lower::TyLoweringContext::new( - self.db, - &self.resolver, - self.owner.into(), - ); - let trait_ref = ctx.lower_trait_ref_from_resolved_path( - trait_, - resolved_segment, - self.table.new_type_var(), - ); - + let self_ty = self.table.new_type_var(); + let trait_ref = self.with_body_ty_lowering(|ctx| { + ctx.lower_trait_ref_from_resolved_path(trait_, resolved_segment, self_ty) + }); self.resolve_trait_assoc_item(trait_ref, segment, id) } (def, _) => { @@ -262,17 +259,14 @@ impl InferenceContext<'_> { // as Iterator>::Item::default`) let remaining_segments_for_ty = remaining_segments.take(remaining_segments.len() - 1); - let ctx = crate::lower::TyLoweringContext::new( - self.db, - &self.resolver, - self.owner.into(), - ); - let (ty, _) = ctx.lower_partly_resolved_path( - def, - resolved_segment, - remaining_segments_for_ty, - true, - ); + let (ty, _) = self.with_body_ty_lowering(|ctx| { + ctx.lower_partly_resolved_path( + def, + resolved_segment, + remaining_segments_for_ty, + true, + ) + }); if ty.is_unknown() { return None; } diff --git a/src/tools/rust-analyzer/crates/hir-ty/src/layout.rs b/src/tools/rust-analyzer/crates/hir-ty/src/layout.rs index 80831440720..9f4cc98993e 100644 --- a/src/tools/rust-analyzer/crates/hir-ty/src/layout.rs +++ b/src/tools/rust-analyzer/crates/hir-ty/src/layout.rs @@ -6,7 +6,7 @@ use base_db::ra_salsa::Cycle; use chalk_ir::{AdtId, FloatTy, IntTy, TyKind, UintTy}; use hir_def::{ layout::{ - Abi, FieldsShape, Float, Integer, LayoutCalculator, LayoutCalculatorError, LayoutS, + Abi, FieldsShape, Float, Integer, LayoutCalculator, LayoutCalculatorError, LayoutData, Primitive, ReprOptions, Scalar, Size, StructKind, TargetDataLayout, WrappingRange, }, LocalFieldId, StructId, @@ -66,7 +66,7 @@ impl rustc_index::Idx for RustcFieldIdx { } } -pub type Layout = LayoutS<RustcFieldIdx, RustcEnumVariantIdx>; +pub type Layout = LayoutData<RustcFieldIdx, RustcEnumVariantIdx>; pub type TagEncoding = hir_def::layout::TagEncoding<RustcEnumVariantIdx>; pub type Variants = hir_def::layout::Variants<RustcFieldIdx, RustcEnumVariantIdx>; diff --git a/src/tools/rust-analyzer/crates/hir-ty/src/lower.rs b/src/tools/rust-analyzer/crates/hir-ty/src/lower.rs index c7ed68448bb..e3a92e52f61 100644 --- a/src/tools/rust-analyzer/crates/hir-ty/src/lower.rs +++ b/src/tools/rust-analyzer/crates/hir-ty/src/lower.rs @@ -34,6 +34,7 @@ use hir_def::{ resolver::{HasResolver, LifetimeNs, Resolver, TypeNs}, type_ref::{ ConstRef, LifetimeRef, TraitBoundModifier, TraitRef as HirTraitRef, TypeBound, TypeRef, + TypeRefId, TypesMap, TypesSourceMap, }, AdtId, AssocItemId, CallableDefId, ConstId, ConstParamId, DefWithBodyId, EnumId, EnumVariantId, FunctionId, GenericDefId, GenericParamId, HasModule, ImplId, InTypeConstLoc, ItemContainerId, @@ -41,7 +42,6 @@ use hir_def::{ TypeOwnerId, UnionId, VariantId, }; use hir_expand::{name::Name, ExpandResult}; -use intern::Interned; use la_arena::{Arena, ArenaMap}; use rustc_hash::FxHashSet; use rustc_pattern_analysis::Captures; @@ -122,6 +122,11 @@ pub struct TyLoweringContext<'a> { pub db: &'a dyn HirDatabase, resolver: &'a Resolver, generics: OnceCell<Option<Generics>>, + types_map: &'a TypesMap, + /// If this is set, that means we're in a context of a freshly expanded macro, and that means + /// we should not use `TypeRefId` in diagnostics because the caller won't have the `TypesMap`, + /// instead we need to put `TypeSource` from the source map. + types_source_map: Option<&'a TypesSourceMap>, in_binders: DebruijnIndex, // FIXME: Should not be an `Option` but `Resolver` currently does not return owners in all cases // where expected @@ -138,13 +143,20 @@ pub struct TyLoweringContext<'a> { } impl<'a> TyLoweringContext<'a> { - pub fn new(db: &'a dyn HirDatabase, resolver: &'a Resolver, owner: TypeOwnerId) -> Self { - Self::new_maybe_unowned(db, resolver, Some(owner)) + pub fn new( + db: &'a dyn HirDatabase, + resolver: &'a Resolver, + types_map: &'a TypesMap, + owner: TypeOwnerId, + ) -> Self { + Self::new_maybe_unowned(db, resolver, types_map, None, Some(owner)) } pub fn new_maybe_unowned( db: &'a dyn HirDatabase, resolver: &'a Resolver, + types_map: &'a TypesMap, + types_source_map: Option<&'a TypesSourceMap>, owner: Option<TypeOwnerId>, ) -> Self { let impl_trait_mode = ImplTraitLoweringState::Disallowed; @@ -154,6 +166,8 @@ impl<'a> TyLoweringContext<'a> { db, resolver, generics: OnceCell::new(), + types_map, + types_source_map, owner, in_binders, impl_trait_mode, @@ -201,6 +215,16 @@ impl<'a> TyLoweringContext<'a> { pub fn with_type_param_mode(self, type_param_mode: ParamLoweringMode) -> Self { Self { type_param_mode, ..self } } + + pub fn impl_trait_mode(&mut self, impl_trait_mode: ImplTraitLoweringMode) -> &mut Self { + self.impl_trait_mode = ImplTraitLoweringState::new(impl_trait_mode); + self + } + + pub fn type_param_mode(&mut self, type_param_mode: ParamLoweringMode) -> &mut Self { + self.type_param_mode = type_param_mode; + self + } } #[derive(Copy, Clone, Debug, PartialEq, Eq)] @@ -230,7 +254,7 @@ pub enum ParamLoweringMode { } impl<'a> TyLoweringContext<'a> { - pub fn lower_ty(&self, type_ref: &TypeRef) -> Ty { + pub fn lower_ty(&self, type_ref: TypeRefId) -> Ty { self.lower_ty_ext(type_ref).0 } @@ -254,12 +278,13 @@ impl<'a> TyLoweringContext<'a> { .as_ref() } - pub fn lower_ty_ext(&self, type_ref: &TypeRef) -> (Ty, Option<TypeNs>) { + pub fn lower_ty_ext(&self, type_ref_id: TypeRefId) -> (Ty, Option<TypeNs>) { let mut res = None; + let type_ref = &self.types_map[type_ref_id]; let ty = match type_ref { TypeRef::Never => TyKind::Never.intern(Interner), TypeRef::Tuple(inner) => { - let inner_tys = inner.iter().map(|tr| self.lower_ty(tr)); + let inner_tys = inner.iter().map(|&tr| self.lower_ty(tr)); TyKind::Tuple(inner_tys.len(), Substitution::from_iter(Interner, inner_tys)) .intern(Interner) } @@ -268,38 +293,43 @@ impl<'a> TyLoweringContext<'a> { res = res_; ty } - TypeRef::RawPtr(inner, mutability) => { + &TypeRef::RawPtr(inner, mutability) => { let inner_ty = self.lower_ty(inner); - TyKind::Raw(lower_to_chalk_mutability(*mutability), inner_ty).intern(Interner) + TyKind::Raw(lower_to_chalk_mutability(mutability), inner_ty).intern(Interner) } - TypeRef::Array(inner, len) => { - let inner_ty = self.lower_ty(inner); - let const_len = self.lower_const(len, TyBuilder::usize()); + TypeRef::Array(array) => { + let inner_ty = self.lower_ty(array.ty); + let const_len = self.lower_const(&array.len, TyBuilder::usize()); TyKind::Array(inner_ty, const_len).intern(Interner) } - TypeRef::Slice(inner) => { + &TypeRef::Slice(inner) => { let inner_ty = self.lower_ty(inner); TyKind::Slice(inner_ty).intern(Interner) } - TypeRef::Reference(inner, lifetime, mutability) => { - let inner_ty = self.lower_ty(inner); + TypeRef::Reference(ref_) => { + let inner_ty = self.lower_ty(ref_.ty); // FIXME: It should infer the eldided lifetimes instead of stubbing with static - let lifetime = - lifetime.as_ref().map_or_else(error_lifetime, |lr| self.lower_lifetime(lr)); - TyKind::Ref(lower_to_chalk_mutability(*mutability), lifetime, inner_ty) + let lifetime = ref_ + .lifetime + .as_ref() + .map_or_else(error_lifetime, |lr| self.lower_lifetime(lr)); + TyKind::Ref(lower_to_chalk_mutability(ref_.mutability), lifetime, inner_ty) .intern(Interner) } TypeRef::Placeholder => TyKind::Error.intern(Interner), - &TypeRef::Fn(ref params, variadic, is_unsafe, ref abi) => { + TypeRef::Fn(fn_) => { let substs = self.with_shifted_in(DebruijnIndex::ONE, |ctx| { - Substitution::from_iter(Interner, params.iter().map(|(_, tr)| ctx.lower_ty(tr))) + Substitution::from_iter( + Interner, + fn_.params().iter().map(|&(_, tr)| ctx.lower_ty(tr)), + ) }); TyKind::Function(FnPointer { num_binders: 0, // FIXME lower `for<'a> fn()` correctly sig: FnSig { - abi: abi.as_ref().map_or(FnAbi::Rust, FnAbi::from_symbol), - safety: if is_unsafe { Safety::Unsafe } else { Safety::Safe }, - variadic, + abi: fn_.abi().as_ref().map_or(FnAbi::Rust, FnAbi::from_symbol), + safety: if fn_.is_unsafe() { Safety::Unsafe } else { Safety::Safe }, + variadic: fn_.is_varargs(), }, substitution: FnSubst(substs), }) @@ -351,8 +381,8 @@ impl<'a> TyLoweringContext<'a> { ImplTraitLoweringState::Param(counter) => { let idx = counter.get(); // Count the number of `impl Trait` things that appear within our bounds. - // Since t hose have been emitted as implicit type args already. - counter.set(idx + count_impl_traits(type_ref) as u16); + // Since those have been emitted as implicit type args already. + counter.set(idx + self.count_impl_traits(type_ref_id) as u16); let kind = self .generics() .expect("param impl trait lowering must be in a generic def") @@ -376,7 +406,7 @@ impl<'a> TyLoweringContext<'a> { let idx = counter.get(); // Count the number of `impl Trait` things that appear within our bounds. // Since t hose have been emitted as implicit type args already. - counter.set(idx + count_impl_traits(type_ref) as u16); + counter.set(idx + self.count_impl_traits(type_ref_id) as u16); let kind = self .generics() .expect("variable impl trait lowering must be in a generic def") @@ -432,12 +462,40 @@ impl<'a> TyLoweringContext<'a> { match expander.enter_expand::<ast::Type>(self.db.upcast(), macro_call, resolver) { Ok(ExpandResult { value: Some((mark, expanded)), .. }) => { - let ctx = expander.ctx(self.db.upcast()); + let (mut types_map, mut types_source_map) = + (TypesMap::default(), TypesSourceMap::default()); + + let ctx = expander.ctx( + self.db.upcast(), + &mut types_map, + &mut types_source_map, + ); // FIXME: Report syntax errors in expansion here let type_ref = TypeRef::from_ast(&ctx, expanded.tree()); drop(expander); - let ty = self.lower_ty(&type_ref); + + // FIXME: That may be better served by mutating `self` then restoring, but this requires + // making it `&mut self`. + let inner_ctx = TyLoweringContext { + db: self.db, + resolver: self.resolver, + generics: self.generics.clone(), + types_map: &types_map, + types_source_map: Some(&types_source_map), + in_binders: self.in_binders, + owner: self.owner, + type_param_mode: self.type_param_mode, + impl_trait_mode: self.impl_trait_mode.take(), + expander: RefCell::new(self.expander.take()), + unsized_types: RefCell::new(self.unsized_types.take()), + }; + + let ty = inner_ctx.lower_ty(type_ref); + + self.impl_trait_mode.swap(&inner_ctx.impl_trait_mode); + *self.expander.borrow_mut() = inner_ctx.expander.into_inner(); + *self.unsized_types.borrow_mut() = inner_ctx.unsized_types.into_inner(); self.expander.borrow_mut().as_mut().unwrap().exit(mark); Some(ty) @@ -463,7 +521,8 @@ impl<'a> TyLoweringContext<'a> { /// This is only for `generic_predicates_for_param`, where we can't just /// lower the self types of the predicates since that could lead to cycles. /// So we just check here if the `type_ref` resolves to a generic param, and which. - fn lower_ty_only_param(&self, type_ref: &TypeRef) -> Option<TypeOrConstParamId> { + fn lower_ty_only_param(&self, type_ref: TypeRefId) -> Option<TypeOrConstParamId> { + let type_ref = &self.types_map[type_ref]; let path = match type_ref { TypeRef::Path(path) => path, _ => return None, @@ -663,7 +722,7 @@ impl<'a> TyLoweringContext<'a> { if matches!(resolution, TypeNs::TraitId(_)) && remaining_index.is_none() { // trait object type without dyn let bound = TypeBound::Path(path.clone(), TraitBoundModifier::None); - let ty = self.lower_dyn_trait(&[Interned::new(bound)]); + let ty = self.lower_dyn_trait(&[bound]); return (ty, None); } @@ -864,7 +923,7 @@ impl<'a> TyLoweringContext<'a> { assert!(matches!(id, GenericParamId::TypeParamId(_))); had_explicit_args = true; if let GenericArg::Type(ty) = &args[0] { - substs.push(self.lower_ty(ty).cast(Interner)); + substs.push(self.lower_ty(*ty).cast(Interner)); } } } else { @@ -901,6 +960,7 @@ impl<'a> TyLoweringContext<'a> { id, arg, &mut (), + self.types_map, |_, type_ref| self.lower_ty(type_ref), |_, const_ref, ty| self.lower_const(const_ref, ty), |_, lifetime_ref| self.lower_lifetime(lifetime_ref), @@ -998,7 +1058,7 @@ impl<'a> TyLoweringContext<'a> { WherePredicate::ForLifetime { target, bound, .. } | WherePredicate::TypeBound { target, bound } => { let self_ty = match target { - WherePredicateTypeTarget::TypeRef(type_ref) => self.lower_ty(type_ref), + WherePredicateTypeTarget::TypeRef(type_ref) => self.lower_ty(*type_ref), &WherePredicateTypeTarget::TypeOrConstParam(local_id) => { let param_id = hir_def::TypeOrConstParamId { parent: def, local_id }; match self.type_param_mode { @@ -1029,12 +1089,12 @@ impl<'a> TyLoweringContext<'a> { pub(crate) fn lower_type_bound( &'a self, - bound: &'a Interned<TypeBound>, + bound: &'a TypeBound, self_ty: Ty, ignore_bindings: bool, ) -> impl Iterator<Item = QuantifiedWhereClause> + 'a { let mut trait_ref = None; - let clause = match bound.as_ref() { + let clause = match bound { TypeBound::Path(path, TraitBoundModifier::None) => { trait_ref = self.lower_trait_ref_from_path(path, self_ty); trait_ref.clone().map(WhereClause::Implemented).map(crate::wrap_empty_binders) @@ -1067,7 +1127,7 @@ impl<'a> TyLoweringContext<'a> { lifetime, }))) } - TypeBound::Error => None, + TypeBound::Use(_) | TypeBound::Error => None, }; clause.into_iter().chain( trait_ref @@ -1079,14 +1139,15 @@ impl<'a> TyLoweringContext<'a> { fn assoc_type_bindings_from_type_bound( &'a self, - bound: &'a Interned<TypeBound>, + bound: &'a TypeBound, trait_ref: TraitRef, ) -> impl Iterator<Item = QuantifiedWhereClause> + 'a { - let last_segment = match bound.as_ref() { + let last_segment = match bound { TypeBound::Path(path, TraitBoundModifier::None) | TypeBound::ForLifetime(_, path) => { path.segments().last() } TypeBound::Path(_, TraitBoundModifier::Maybe) + | TypeBound::Use(_) | TypeBound::Error | TypeBound::Lifetime(_) => None, }; @@ -1110,7 +1171,7 @@ impl<'a> TyLoweringContext<'a> { // this point (`super_trait_ref.substitution`). let substitution = self.substs_from_path_segment( // FIXME: This is hack. We shouldn't really build `PathSegment` directly. - PathSegment { name: &binding.name, args_and_bindings: binding.args.as_deref() }, + PathSegment { name: &binding.name, args_and_bindings: binding.args.as_ref() }, Some(associated_ty.into()), false, // this is not relevant Some(super_trait_ref.self_type_parameter(Interner)), @@ -1130,8 +1191,8 @@ impl<'a> TyLoweringContext<'a> { let mut predicates: SmallVec<[_; 1]> = SmallVec::with_capacity( binding.type_ref.as_ref().map_or(0, |_| 1) + binding.bounds.len(), ); - if let Some(type_ref) = &binding.type_ref { - match (type_ref, &self.impl_trait_mode) { + if let Some(type_ref) = binding.type_ref { + match (&self.types_map[type_ref], &self.impl_trait_mode) { (TypeRef::ImplTrait(_), ImplTraitLoweringState::Disallowed) => (), ( _, @@ -1178,6 +1239,8 @@ impl<'a> TyLoweringContext<'a> { let mut ext = TyLoweringContext::new_maybe_unowned( self.db, self.resolver, + self.types_map, + self.types_source_map, self.owner, ) .with_type_param_mode(self.type_param_mode); @@ -1215,7 +1278,7 @@ impl<'a> TyLoweringContext<'a> { }) } - fn lower_dyn_trait(&self, bounds: &[Interned<TypeBound>]) -> Ty { + fn lower_dyn_trait(&self, bounds: &[TypeBound]) -> Ty { let self_ty = TyKind::BoundVar(BoundVar::new(DebruijnIndex::INNERMOST, 0)).intern(Interner); // INVARIANT: The principal trait bound, if present, must come first. Others may be in any // order but should be in the same order for the same set but possibly different order of @@ -1313,7 +1376,7 @@ impl<'a> TyLoweringContext<'a> { } } - fn lower_impl_trait(&self, bounds: &[Interned<TypeBound>], krate: CrateId) -> ImplTrait { + fn lower_impl_trait(&self, bounds: &[TypeBound], krate: CrateId) -> ImplTrait { cov_mark::hit!(lower_rpit); let self_ty = TyKind::BoundVar(BoundVar::new(DebruijnIndex::INNERMOST, 0)).intern(Interner); let predicates = self.with_shifted_in(DebruijnIndex::ONE, |ctx| { @@ -1365,6 +1428,17 @@ impl<'a> TyLoweringContext<'a> { None => error_lifetime(), } } + + // FIXME: This does not handle macros! + fn count_impl_traits(&self, type_ref: TypeRefId) -> usize { + let mut count = 0; + TypeRef::walk(type_ref, self.types_map, &mut |type_ref| { + if matches!(type_ref, TypeRef::ImplTrait(_)) { + count += 1; + } + }); + count + } } /// Build the signature of a callable item (function, struct or enum variant). @@ -1385,17 +1459,6 @@ pub fn associated_type_shorthand_candidates<R>( named_associated_type_shorthand_candidates(db, def, res, None, |name, _, id| cb(name, id)) } -// FIXME: This does not handle macros! -fn count_impl_traits(type_ref: &TypeRef) -> usize { - let mut count = 0; - type_ref.walk(&mut |type_ref| { - if matches!(type_ref, TypeRef::ImplTrait(_)) { - count += 1; - } - }); - count -} - fn named_associated_type_shorthand_candidates<R>( db: &dyn HirDatabase, // If the type parameter is defined in an impl and we're in a method, there @@ -1499,10 +1562,10 @@ pub(crate) fn field_types_query( }; let generics = generics(db.upcast(), def); let mut res = ArenaMap::default(); - let ctx = TyLoweringContext::new(db, &resolver, def.into()) + let ctx = TyLoweringContext::new(db, &resolver, var_data.types_map(), def.into()) .with_type_param_mode(ParamLoweringMode::Variable); for (field_id, field_data) in var_data.fields().iter() { - res.insert(field_id, make_binders(db, &generics, ctx.lower_ty(&field_data.type_ref))); + res.insert(field_id, make_binders(db, &generics, ctx.lower_ty(field_data.type_ref))); } Arc::new(res) } @@ -1522,38 +1585,38 @@ pub(crate) fn generic_predicates_for_param_query( assoc_name: Option<Name>, ) -> GenericPredicates { let resolver = def.resolver(db.upcast()); - let ctx = if let GenericDefId::FunctionId(_) = def { - TyLoweringContext::new(db, &resolver, def.into()) + let mut ctx = if let GenericDefId::FunctionId(_) = def { + TyLoweringContext::new(db, &resolver, TypesMap::EMPTY, def.into()) .with_impl_trait_mode(ImplTraitLoweringMode::Variable) .with_type_param_mode(ParamLoweringMode::Variable) } else { - TyLoweringContext::new(db, &resolver, def.into()) + TyLoweringContext::new(db, &resolver, TypesMap::EMPTY, def.into()) .with_type_param_mode(ParamLoweringMode::Variable) }; let generics = generics(db.upcast(), def); // we have to filter out all other predicates *first*, before attempting to lower them - let predicate = |(pred, &def): &(&_, _)| match pred { + let predicate = |pred: &_, def: &_, ctx: &TyLoweringContext<'_>| match pred { WherePredicate::ForLifetime { target, bound, .. } | WherePredicate::TypeBound { target, bound, .. } => { let invalid_target = match target { WherePredicateTypeTarget::TypeRef(type_ref) => { - ctx.lower_ty_only_param(type_ref) != Some(param_id) + ctx.lower_ty_only_param(*type_ref) != Some(param_id) } &WherePredicateTypeTarget::TypeOrConstParam(local_id) => { - let target_id = TypeOrConstParamId { parent: def, local_id }; + let target_id = TypeOrConstParamId { parent: *def, local_id }; target_id != param_id } }; if invalid_target { // If this is filtered out without lowering, `?Sized` is not gathered into `ctx.unsized_types` - if let TypeBound::Path(_, TraitBoundModifier::Maybe) = &**bound { - ctx.lower_where_predicate(pred, &def, true).for_each(drop); + if let TypeBound::Path(_, TraitBoundModifier::Maybe) = bound { + ctx.lower_where_predicate(pred, def, true).for_each(drop); } return false; } - match &**bound { + match bound { TypeBound::ForLifetime(_, path) | TypeBound::Path(path, _) => { // Only lower the bound if the trait could possibly define the associated // type we're looking for. @@ -1571,18 +1634,20 @@ pub(crate) fn generic_predicates_for_param_query( }) }) } - TypeBound::Lifetime(_) | TypeBound::Error => false, + TypeBound::Use(_) | TypeBound::Lifetime(_) | TypeBound::Error => false, } } WherePredicate::Lifetime { .. } => false, }; - let mut predicates: Vec<_> = resolver - .where_predicates_in_scope() - .filter(predicate) - .flat_map(|(pred, def)| { - ctx.lower_where_predicate(pred, def, true).map(|p| make_binders(db, &generics, p)) - }) - .collect(); + let mut predicates = Vec::new(); + for (params, def) in resolver.all_generic_params() { + ctx.types_map = ¶ms.types_map; + predicates.extend( + params.where_predicates().filter(|pred| predicate(pred, def, &ctx)).flat_map(|pred| { + ctx.lower_where_predicate(pred, def, true).map(|p| make_binders(db, &generics, p)) + }), + ); + } let subst = generics.bound_vars_subst(db, DebruijnIndex::INNERMOST); if !subst.is_empty(Interner) { @@ -1629,23 +1694,27 @@ pub(crate) fn trait_environment_query( def: GenericDefId, ) -> Arc<TraitEnvironment> { let resolver = def.resolver(db.upcast()); - let ctx = if let GenericDefId::FunctionId(_) = def { - TyLoweringContext::new(db, &resolver, def.into()) + let mut ctx = if let GenericDefId::FunctionId(_) = def { + TyLoweringContext::new(db, &resolver, TypesMap::EMPTY, def.into()) .with_impl_trait_mode(ImplTraitLoweringMode::Param) .with_type_param_mode(ParamLoweringMode::Placeholder) } else { - TyLoweringContext::new(db, &resolver, def.into()) + TyLoweringContext::new(db, &resolver, TypesMap::EMPTY, def.into()) .with_type_param_mode(ParamLoweringMode::Placeholder) }; let mut traits_in_scope = Vec::new(); let mut clauses = Vec::new(); - for (pred, def) in resolver.where_predicates_in_scope() { - for pred in ctx.lower_where_predicate(pred, def, false) { - if let WhereClause::Implemented(tr) = &pred.skip_binders() { - traits_in_scope.push((tr.self_type_parameter(Interner).clone(), tr.hir_trait_id())); + for (params, def) in resolver.all_generic_params() { + ctx.types_map = ¶ms.types_map; + for pred in params.where_predicates() { + for pred in ctx.lower_where_predicate(pred, def, false) { + if let WhereClause::Implemented(tr) = pred.skip_binders() { + traits_in_scope + .push((tr.self_type_parameter(Interner).clone(), tr.hir_trait_id())); + } + let program_clause: chalk_ir::ProgramClause<Interner> = pred.cast(Interner); + clauses.push(program_clause.into_from_env_clause(Interner)); } - let program_clause: chalk_ir::ProgramClause<Interner> = pred.cast(Interner); - clauses.push(program_clause.into_from_env_clause(Interner)); } } @@ -1724,18 +1793,20 @@ where } _ => (ImplTraitLoweringMode::Disallowed, ParamLoweringMode::Variable), }; - let ctx = TyLoweringContext::new(db, &resolver, def.into()) + let mut ctx = TyLoweringContext::new(db, &resolver, TypesMap::EMPTY, def.into()) .with_impl_trait_mode(impl_trait_lowering) .with_type_param_mode(param_lowering); let generics = generics(db.upcast(), def); - let mut predicates = resolver - .where_predicates_in_scope() - .filter(|(pred, def)| filter(pred, def)) - .flat_map(|(pred, def)| { - ctx.lower_where_predicate(pred, def, false).map(|p| make_binders(db, &generics, p)) - }) - .collect::<Vec<_>>(); + let mut predicates = Vec::new(); + for (params, def) in resolver.all_generic_params() { + ctx.types_map = ¶ms.types_map; + predicates.extend(params.where_predicates().filter(|pred| filter(pred, def)).flat_map( + |pred| { + ctx.lower_where_predicate(pred, def, false).map(|p| make_binders(db, &generics, p)) + }, + )); + } if generics.len() > 0 { let subst = generics.bound_vars_subst(db, DebruijnIndex::INNERMOST); @@ -1811,18 +1882,19 @@ pub(crate) fn generic_defaults_query(db: &dyn HirDatabase, def: GenericDefId) -> let resolver = def.resolver(db.upcast()); let parent_start_idx = generic_params.len_self(); - let ctx = TyLoweringContext::new(db, &resolver, def.into()) + let mut ctx = TyLoweringContext::new(db, &resolver, TypesMap::EMPTY, def.into()) .with_impl_trait_mode(ImplTraitLoweringMode::Disallowed) .with_type_param_mode(ParamLoweringMode::Variable); - GenericDefaults(Some(Arc::from_iter(generic_params.iter().enumerate().map( - |(idx, (id, p))| { + GenericDefaults(Some(Arc::from_iter(generic_params.iter_with_types_map().enumerate().map( + |(idx, ((id, p), types_map))| { + ctx.types_map = types_map; match p { GenericParamDataRef::TypeParamData(p) => { let ty = p.default.as_ref().map_or(TyKind::Error.intern(Interner), |ty| { // Each default can only refer to previous parameters. // Type variable default referring to parameter coming // after it is forbidden (FIXME: report diagnostic) - fallback_bound_vars(ctx.lower_ty(ty), idx, parent_start_idx) + fallback_bound_vars(ctx.lower_ty(*ty), idx, parent_start_idx) }); crate::make_binders(db, &generic_params, ty.cast(Interner)) } @@ -1834,7 +1906,7 @@ pub(crate) fn generic_defaults_query(db: &dyn HirDatabase, def: GenericDefId) -> let mut val = p.default.as_ref().map_or_else( || unknown_const_as_generic(db.const_param_ty(id)), |c| { - let c = ctx.lower_const(c, ctx.lower_ty(&p.ty)); + let c = ctx.lower_const(c, ctx.lower_ty(p.ty)); c.cast(Interner) }, ); @@ -1874,14 +1946,14 @@ pub(crate) fn generic_defaults_recover( fn fn_sig_for_fn(db: &dyn HirDatabase, def: FunctionId) -> PolyFnSig { let data = db.function_data(def); let resolver = def.resolver(db.upcast()); - let ctx_params = TyLoweringContext::new(db, &resolver, def.into()) + let ctx_params = TyLoweringContext::new(db, &resolver, &data.types_map, def.into()) .with_impl_trait_mode(ImplTraitLoweringMode::Variable) .with_type_param_mode(ParamLoweringMode::Variable); - let params = data.params.iter().map(|tr| ctx_params.lower_ty(tr)); - let ctx_ret = TyLoweringContext::new(db, &resolver, def.into()) + let params = data.params.iter().map(|&tr| ctx_params.lower_ty(tr)); + let ctx_ret = TyLoweringContext::new(db, &resolver, &data.types_map, def.into()) .with_impl_trait_mode(ImplTraitLoweringMode::Opaque) .with_type_param_mode(ParamLoweringMode::Variable); - let ret = ctx_ret.lower_ty(&data.ret_type); + let ret = ctx_ret.lower_ty(data.ret_type); let generics = generics(db.upcast(), def.into()); let sig = CallableSig::from_params_and_return( params, @@ -1910,28 +1982,33 @@ fn type_for_const(db: &dyn HirDatabase, def: ConstId) -> Binders<Ty> { let data = db.const_data(def); let generics = generics(db.upcast(), def.into()); let resolver = def.resolver(db.upcast()); - let ctx = TyLoweringContext::new(db, &resolver, def.into()) + let ctx = TyLoweringContext::new(db, &resolver, &data.types_map, def.into()) .with_type_param_mode(ParamLoweringMode::Variable); - make_binders(db, &generics, ctx.lower_ty(&data.type_ref)) + make_binders(db, &generics, ctx.lower_ty(data.type_ref)) } /// Build the declared type of a static. fn type_for_static(db: &dyn HirDatabase, def: StaticId) -> Binders<Ty> { let data = db.static_data(def); let resolver = def.resolver(db.upcast()); - let ctx = TyLoweringContext::new(db, &resolver, def.into()); + let ctx = TyLoweringContext::new(db, &resolver, &data.types_map, def.into()); - Binders::empty(Interner, ctx.lower_ty(&data.type_ref)) + Binders::empty(Interner, ctx.lower_ty(data.type_ref)) } fn fn_sig_for_struct_constructor(db: &dyn HirDatabase, def: StructId) -> PolyFnSig { let struct_data = db.struct_data(def); let fields = struct_data.variant_data.fields(); let resolver = def.resolver(db.upcast()); - let ctx = TyLoweringContext::new(db, &resolver, AdtId::from(def).into()) - .with_type_param_mode(ParamLoweringMode::Variable); - let params = fields.iter().map(|(_, field)| ctx.lower_ty(&field.type_ref)); + let ctx = TyLoweringContext::new( + db, + &resolver, + struct_data.variant_data.types_map(), + AdtId::from(def).into(), + ) + .with_type_param_mode(ParamLoweringMode::Variable); + let params = fields.iter().map(|(_, field)| ctx.lower_ty(field.type_ref)); let (ret, binders) = type_for_adt(db, def.into()).into_value_and_skipped_binders(); Binders::new( binders, @@ -1961,9 +2038,14 @@ fn fn_sig_for_enum_variant_constructor(db: &dyn HirDatabase, def: EnumVariantId) let var_data = db.enum_variant_data(def); let fields = var_data.variant_data.fields(); let resolver = def.resolver(db.upcast()); - let ctx = TyLoweringContext::new(db, &resolver, DefWithBodyId::VariantId(def).into()) - .with_type_param_mode(ParamLoweringMode::Variable); - let params = fields.iter().map(|(_, field)| ctx.lower_ty(&field.type_ref)); + let ctx = TyLoweringContext::new( + db, + &resolver, + var_data.variant_data.types_map(), + DefWithBodyId::VariantId(def).into(), + ) + .with_type_param_mode(ParamLoweringMode::Variable); + let params = fields.iter().map(|(_, field)| ctx.lower_ty(field.type_ref)); let (ret, binders) = type_for_adt(db, def.lookup(db.upcast()).parent.into()).into_value_and_skipped_binders(); Binders::new( @@ -2004,15 +2086,17 @@ fn type_for_adt(db: &dyn HirDatabase, adt: AdtId) -> Binders<Ty> { fn type_for_type_alias(db: &dyn HirDatabase, t: TypeAliasId) -> Binders<Ty> { let generics = generics(db.upcast(), t.into()); let resolver = t.resolver(db.upcast()); - let ctx = TyLoweringContext::new(db, &resolver, t.into()) + let type_alias_data = db.type_alias_data(t); + let ctx = TyLoweringContext::new(db, &resolver, &type_alias_data.types_map, t.into()) .with_impl_trait_mode(ImplTraitLoweringMode::Opaque) .with_type_param_mode(ParamLoweringMode::Variable); - let type_alias_data = db.type_alias_data(t); let inner = if type_alias_data.is_extern { TyKind::Foreign(crate::to_foreign_def_id(t)).intern(Interner) } else { - let type_ref = &type_alias_data.type_ref; - ctx.lower_ty(type_ref.as_deref().unwrap_or(&TypeRef::Error)) + type_alias_data + .type_ref + .map(|type_ref| ctx.lower_ty(type_ref)) + .unwrap_or_else(|| TyKind::Error.intern(Interner)) }; make_binders(db, &generics, inner) } @@ -2085,9 +2169,9 @@ pub(crate) fn impl_self_ty_query(db: &dyn HirDatabase, impl_id: ImplId) -> Binde let impl_data = db.impl_data(impl_id); let resolver = impl_id.resolver(db.upcast()); let generics = generics(db.upcast(), impl_id.into()); - let ctx = TyLoweringContext::new(db, &resolver, impl_id.into()) + let ctx = TyLoweringContext::new(db, &resolver, &impl_data.types_map, impl_id.into()) .with_type_param_mode(ParamLoweringMode::Variable); - make_binders(db, &generics, ctx.lower_ty(&impl_data.self_ty)) + make_binders(db, &generics, ctx.lower_ty(impl_data.self_ty)) } // returns None if def is a type arg @@ -2095,13 +2179,13 @@ pub(crate) fn const_param_ty_query(db: &dyn HirDatabase, def: ConstParamId) -> T let parent_data = db.generic_params(def.parent()); let data = &parent_data[def.local_id()]; let resolver = def.parent().resolver(db.upcast()); - let ctx = TyLoweringContext::new(db, &resolver, def.parent().into()); + let ctx = TyLoweringContext::new(db, &resolver, &parent_data.types_map, def.parent().into()); match data { TypeOrConstParamData::TypeParamData(_) => { never!(); Ty::new(Interner, TyKind::Error) } - TypeOrConstParamData::ConstParamData(d) => ctx.lower_ty(&d.ty), + TypeOrConstParamData::ConstParamData(d) => ctx.lower_ty(d.ty), } } @@ -2117,7 +2201,7 @@ pub(crate) fn impl_self_ty_recover( pub(crate) fn impl_trait_query(db: &dyn HirDatabase, impl_id: ImplId) -> Option<Binders<TraitRef>> { let impl_data = db.impl_data(impl_id); let resolver = impl_id.resolver(db.upcast()); - let ctx = TyLoweringContext::new(db, &resolver, impl_id.into()) + let ctx = TyLoweringContext::new(db, &resolver, &impl_data.types_map, impl_id.into()) .with_type_param_mode(ParamLoweringMode::Variable); let (self_ty, binders) = db.impl_self_ty(impl_id).into_value_and_skipped_binders(); let target_trait = impl_data.target_trait.as_ref()?; @@ -2131,10 +2215,10 @@ pub(crate) fn return_type_impl_traits( // FIXME unify with fn_sig_for_fn instead of doing lowering twice, maybe let data = db.function_data(def); let resolver = def.resolver(db.upcast()); - let ctx_ret = TyLoweringContext::new(db, &resolver, def.into()) + let ctx_ret = TyLoweringContext::new(db, &resolver, &data.types_map, def.into()) .with_impl_trait_mode(ImplTraitLoweringMode::Opaque) .with_type_param_mode(ParamLoweringMode::Variable); - let _ret = ctx_ret.lower_ty(&data.ret_type); + let _ret = ctx_ret.lower_ty(data.ret_type); let generics = generics(db.upcast(), def.into()); let return_type_impl_traits = ImplTraits { impl_traits: match ctx_ret.impl_trait_mode { @@ -2155,10 +2239,10 @@ pub(crate) fn type_alias_impl_traits( ) -> Option<Arc<Binders<ImplTraits>>> { let data = db.type_alias_data(def); let resolver = def.resolver(db.upcast()); - let ctx = TyLoweringContext::new(db, &resolver, def.into()) + let ctx = TyLoweringContext::new(db, &resolver, &data.types_map, def.into()) .with_impl_trait_mode(ImplTraitLoweringMode::Opaque) .with_type_param_mode(ParamLoweringMode::Variable); - if let Some(type_ref) = &data.type_ref { + if let Some(type_ref) = data.type_ref { let _ty = ctx.lower_ty(type_ref); } let type_alias_impl_traits = ImplTraits { @@ -2190,7 +2274,8 @@ pub(crate) fn generic_arg_to_chalk<'a, T>( kind_id: GenericParamId, arg: &'a GenericArg, this: &mut T, - for_type: impl FnOnce(&mut T, &TypeRef) -> Ty + 'a, + types_map: &TypesMap, + for_type: impl FnOnce(&mut T, TypeRefId) -> Ty + 'a, for_const: impl FnOnce(&mut T, &ConstRef, Ty) -> Const + 'a, for_lifetime: impl FnOnce(&mut T, &LifetimeRef) -> Lifetime + 'a, ) -> crate::GenericArg { @@ -2203,7 +2288,7 @@ pub(crate) fn generic_arg_to_chalk<'a, T>( GenericParamId::LifetimeParamId(_) => ParamKind::Lifetime, }; match (arg, kind) { - (GenericArg::Type(type_ref), ParamKind::Type) => for_type(this, type_ref).cast(Interner), + (GenericArg::Type(type_ref), ParamKind::Type) => for_type(this, *type_ref).cast(Interner), (GenericArg::Const(c), ParamKind::Const(c_ty)) => for_const(this, c, c_ty).cast(Interner), (GenericArg::Lifetime(lifetime_ref), ParamKind::Lifetime) => { for_lifetime(this, lifetime_ref).cast(Interner) @@ -2214,7 +2299,7 @@ pub(crate) fn generic_arg_to_chalk<'a, T>( // We want to recover simple idents, which parser detects them // as types. Maybe here is not the best place to do it, but // it works. - if let TypeRef::Path(p) = t { + if let TypeRef::Path(p) = &types_map[*t] { if let Some(p) = p.mod_path() { if p.kind == PathKind::Plain { if let [n] = p.segments() { diff --git a/src/tools/rust-analyzer/crates/hir-ty/src/mir.rs b/src/tools/rust-analyzer/crates/hir-ty/src/mir.rs index 8e815aabf20..59c583afb2a 100644 --- a/src/tools/rust-analyzer/crates/hir-ty/src/mir.rs +++ b/src/tools/rust-analyzer/crates/hir-ty/src/mir.rs @@ -879,7 +879,8 @@ pub enum Rvalue { /// /// **Needs clarification**: Are there weird additional semantics here related to the runtime /// nature of this operation? - //ThreadLocalRef(DefId), + // ThreadLocalRef(DefId), + ThreadLocalRef(std::convert::Infallible), /// Creates a pointer with the indicated mutability to the place. /// @@ -888,7 +889,8 @@ pub enum Rvalue { /// /// Like with references, the semantics of this operation are heavily dependent on the aliasing /// model. - //AddressOf(Mutability, Place), + // AddressOf(Mutability, Place), + AddressOf(std::convert::Infallible), /// Yields the length of the place, as a `usize`. /// @@ -906,19 +908,21 @@ pub enum Rvalue { Cast(CastKind, Operand, Ty), // FIXME link to `pointer::offset` when it hits stable. - // /// * `Offset` has the same semantics as `pointer::offset`, except that the second - // /// parameter may be a `usize` as well. - // /// * The comparison operations accept `bool`s, `char`s, signed or unsigned integers, floats, - // /// raw pointers, or function pointers and return a `bool`. The types of the operands must be - // /// matching, up to the usual caveat of the lifetimes in function pointers. - // /// * Left and right shift operations accept signed or unsigned integers not necessarily of the - // /// same type and return a value of the same type as their LHS. Like in Rust, the RHS is - // /// truncated as needed. - // /// * The `Bit*` operations accept signed integers, unsigned integers, or bools with matching - // /// types and return a value of that type. - // /// * The remaining operations accept signed integers, unsigned integers, or floats with - // /// matching types and return a value of that type. + /// * `Offset` has the same semantics as `pointer::offset`, except that the second + /// parameter may be a `usize` as well. + /// * The comparison operations accept `bool`s, `char`s, signed or unsigned integers, floats, + /// raw pointers, or function pointers and return a `bool`. The types of the operands must be + /// matching, up to the usual caveat of the lifetimes in function pointers. + /// * Left and right shift operations accept signed or unsigned integers not necessarily of the + /// same type and return a value of the same type as their LHS. Like in Rust, the RHS is + /// truncated as needed. + /// * The `Bit*` operations accept signed integers, unsigned integers, or bools with matching + /// types and return a value of that type. + /// * The remaining operations accept signed integers, unsigned integers, or floats with + /// matching types and return a value of that type. //BinaryOp(BinOp, Box<(Operand, Operand)>), + BinaryOp(std::convert::Infallible), + /// Same as `BinaryOp`, but yields `(T, bool)` with a `bool` indicating an error condition. /// /// When overflow checking is disabled and we are generating run-time code, the error condition @@ -937,6 +941,7 @@ pub enum Rvalue { /// Computes a value as described by the operation. //NullaryOp(NullOp, Ty), + NullaryOp(std::convert::Infallible), /// Exactly like `BinaryOp`, but less operands. /// @@ -1095,6 +1100,10 @@ impl MirBody { for_operand(op, &mut f, &mut self.projection_store); } } + Rvalue::ThreadLocalRef(n) + | Rvalue::AddressOf(n) + | Rvalue::BinaryOp(n) + | Rvalue::NullaryOp(n) => match *n {}, } } StatementKind::FakeRead(p) | StatementKind::Deinit(p) => { diff --git a/src/tools/rust-analyzer/crates/hir-ty/src/mir/borrowck.rs b/src/tools/rust-analyzer/crates/hir-ty/src/mir/borrowck.rs index 9830fa1ca7b..9c86d3b59f6 100644 --- a/src/tools/rust-analyzer/crates/hir-ty/src/mir/borrowck.rs +++ b/src/tools/rust-analyzer/crates/hir-ty/src/mir/borrowck.rs @@ -167,6 +167,10 @@ fn moved_out_of_ref(db: &dyn HirDatabase, body: &MirBody) -> Vec<MovedOutOfRef> for_operand(op, statement.span); } } + Rvalue::ThreadLocalRef(n) + | Rvalue::AddressOf(n) + | Rvalue::BinaryOp(n) + | Rvalue::NullaryOp(n) => match *n {}, }, StatementKind::FakeRead(_) | StatementKind::Deinit(_) @@ -253,6 +257,10 @@ fn partially_moved(db: &dyn HirDatabase, body: &MirBody) -> Vec<PartiallyMoved> for_operand(op, statement.span); } } + Rvalue::ThreadLocalRef(n) + | Rvalue::AddressOf(n) + | Rvalue::BinaryOp(n) + | Rvalue::NullaryOp(n) => match *n {}, }, StatementKind::FakeRead(_) | StatementKind::Deinit(_) @@ -548,6 +556,10 @@ fn mutability_of_locals( } } Rvalue::ShallowInitBox(_, _) | Rvalue::ShallowInitBoxWithAlloc(_) => (), + Rvalue::ThreadLocalRef(n) + | Rvalue::AddressOf(n) + | Rvalue::BinaryOp(n) + | Rvalue::NullaryOp(n) => match *n {}, } if let Rvalue::Ref( BorrowKind::Mut { diff --git a/src/tools/rust-analyzer/crates/hir-ty/src/mir/eval.rs b/src/tools/rust-analyzer/crates/hir-ty/src/mir/eval.rs index 0d42617d185..e73b9dc27d1 100644 --- a/src/tools/rust-analyzer/crates/hir-ty/src/mir/eval.rs +++ b/src/tools/rust-analyzer/crates/hir-ty/src/mir/eval.rs @@ -6,6 +6,7 @@ use base_db::CrateId; use chalk_ir::{cast::Cast, Mutability}; use either::Either; use hir_def::{ + body::HygieneId, builtin_type::BuiltinType, data::adt::{StructFlags, VariantData}, lang_item::LangItem, @@ -1628,6 +1629,10 @@ impl Evaluator<'_> { } CastKind::FnPtrToPtr => not_supported!("fn ptr to ptr cast"), }, + Rvalue::ThreadLocalRef(n) + | Rvalue::AddressOf(n) + | Rvalue::BinaryOp(n) + | Rvalue::NullaryOp(n) => match *n {}, }) } @@ -2703,17 +2708,15 @@ impl Evaluator<'_> { TyKind::Function(_) => { self.exec_fn_pointer(func_data, destination, &args[1..], locals, target_bb, span) } - TyKind::Closure(closure, subst) => { - return self.exec_closure( - *closure, - func_data, - &Substitution::from_iter(Interner, ClosureSubst(subst).parent_subst()), - destination, - &args[1..], - locals, - span, - ); - } + TyKind::Closure(closure, subst) => self.exec_closure( + *closure, + func_data, + &Substitution::from_iter(Interner, ClosureSubst(subst).parent_subst()), + destination, + &args[1..], + locals, + span, + ), _ => { // try to execute the manual impl of `FnTrait` for structs (nightly feature used in std) let arg0 = func; @@ -2846,7 +2849,8 @@ impl Evaluator<'_> { } let layout = self.layout_adt(id.0, subst.clone())?; match data.variant_data.as_ref() { - VariantData::Record(fields) | VariantData::Tuple(fields) => { + VariantData::Record { fields, .. } + | VariantData::Tuple { fields, .. } => { let field_types = self.db.field_types(s.into()); for (field, _) in fields.iter() { let offset = layout @@ -2951,6 +2955,7 @@ pub fn render_const_using_debug_impl( let Some(ValueNs::FunctionId(format_fn)) = resolver.resolve_path_in_value_ns_fully( db.upcast(), &hir_def::path::Path::from_known_path_with_no_generic(path![std::fmt::format]), + HygieneId::ROOT, ) else { not_supported!("std::fmt::format not found"); }; diff --git a/src/tools/rust-analyzer/crates/hir-ty/src/mir/lower.rs b/src/tools/rust-analyzer/crates/hir-ty/src/mir/lower.rs index 16994cdd0c6..c4e06400510 100644 --- a/src/tools/rust-analyzer/crates/hir-ty/src/mir/lower.rs +++ b/src/tools/rust-analyzer/crates/hir-ty/src/mir/lower.rs @@ -5,7 +5,7 @@ use std::{fmt::Write, iter, mem}; use base_db::ra_salsa::Cycle; use chalk_ir::{BoundVar, ConstData, DebruijnIndex, TyKind}; use hir_def::{ - body::Body, + body::{Body, HygieneId}, data::adt::{StructKind, VariantData}, hir::{ ArithOp, Array, BinaryOp, BindingAnnotation, BindingId, ExprId, LabelId, Literal, @@ -13,7 +13,8 @@ use hir_def::{ }, lang_item::{LangItem, LangItemTarget}, path::Path, - resolver::{resolver_for_expr, HasResolver, ResolveValueResult, ValueNs}, + resolver::{HasResolver, ResolveValueResult, Resolver, ValueNs}, + type_ref::TypesMap, AdtId, DefWithBodyId, EnumVariantId, GeneralConstId, HasModule, ItemContainerId, LocalFieldId, Lookup, TraitId, TupleId, TypeOrConstParamId, }; @@ -28,7 +29,7 @@ use triomphe::Arc; use crate::{ consteval::ConstEvalError, db::{HirDatabase, InternedClosure}, - display::HirDisplay, + display::{hir_display_with_types_map, HirDisplay}, error_lifetime, generics::generics, infer::{cast::CastTy, unify::InferenceTable, CaptureKind, CapturedItem, TypeMismatch}, @@ -76,6 +77,7 @@ struct MirLowerCtx<'a> { db: &'a dyn HirDatabase, body: &'a Body, infer: &'a InferenceResult, + resolver: Resolver, drop_scopes: Vec<DropScope>, } @@ -246,8 +248,15 @@ impl From<LayoutError> for MirLowerError { } impl MirLowerError { - fn unresolved_path(db: &dyn HirDatabase, p: &Path, edition: Edition) -> Self { - Self::UnresolvedName(p.display(db, edition).to_string()) + fn unresolved_path( + db: &dyn HirDatabase, + p: &Path, + edition: Edition, + types_map: &TypesMap, + ) -> Self { + Self::UnresolvedName( + hir_display_with_types_map(p, types_map).display(db, edition).to_string(), + ) } } @@ -278,6 +287,7 @@ impl<'ctx> MirLowerCtx<'ctx> { owner, closures: vec![], }; + let resolver = owner.resolver(db.upcast()); MirLowerCtx { result: mir, @@ -285,6 +295,7 @@ impl<'ctx> MirLowerCtx<'ctx> { infer, body, owner, + resolver, current_loop_blocks: None, labeled_loop_blocks: Default::default(), discr_temp: None, @@ -410,43 +421,54 @@ impl<'ctx> MirLowerCtx<'ctx> { Err(MirLowerError::IncompleteExpr) } Expr::Path(p) => { - let pr = - if let Some((assoc, subst)) = self.infer.assoc_resolutions_for_expr(expr_id) { - match assoc { - hir_def::AssocItemId::ConstId(c) => { - self.lower_const( - c.into(), - current, - place, - subst, - expr_id.into(), - self.expr_ty_without_adjust(expr_id), - )?; - return Ok(Some(current)); - } - hir_def::AssocItemId::FunctionId(_) => { - // FnDefs are zero sized, no action is needed. - return Ok(Some(current)); - } - hir_def::AssocItemId::TypeAliasId(_) => { - // FIXME: If it is unreachable, use proper error instead of `not_supported`. - not_supported!("associated functions and types") - } + let pr = if let Some((assoc, subst)) = + self.infer.assoc_resolutions_for_expr(expr_id) + { + match assoc { + hir_def::AssocItemId::ConstId(c) => { + self.lower_const( + c.into(), + current, + place, + subst, + expr_id.into(), + self.expr_ty_without_adjust(expr_id), + )?; + return Ok(Some(current)); } - } else if let Some(variant) = self.infer.variant_resolution_for_expr(expr_id) { - match variant { - VariantId::EnumVariantId(e) => ValueNs::EnumVariantId(e), - VariantId::StructId(s) => ValueNs::StructId(s), - VariantId::UnionId(_) => implementation_error!("Union variant as path"), + hir_def::AssocItemId::FunctionId(_) => { + // FnDefs are zero sized, no action is needed. + return Ok(Some(current)); } - } else { - let unresolved_name = - || MirLowerError::unresolved_path(self.db, p, self.edition()); - let resolver = resolver_for_expr(self.db.upcast(), self.owner, expr_id); - resolver - .resolve_path_in_value_ns_fully(self.db.upcast(), p) - .ok_or_else(unresolved_name)? - }; + hir_def::AssocItemId::TypeAliasId(_) => { + // FIXME: If it is unreachable, use proper error instead of `not_supported`. + not_supported!("associated functions and types") + } + } + } else if let Some(variant) = self.infer.variant_resolution_for_expr(expr_id) { + match variant { + VariantId::EnumVariantId(e) => ValueNs::EnumVariantId(e), + VariantId::StructId(s) => ValueNs::StructId(s), + VariantId::UnionId(_) => implementation_error!("Union variant as path"), + } + } else { + let resolver_guard = + self.resolver.update_to_inner_scope(self.db.upcast(), self.owner, expr_id); + let hygiene = self.body.expr_path_hygiene(expr_id); + let result = self + .resolver + .resolve_path_in_value_ns_fully(self.db.upcast(), p, hygiene) + .ok_or_else(|| { + MirLowerError::unresolved_path( + self.db, + p, + self.edition(), + &self.body.types, + ) + })?; + self.resolver.reset_to_guard(resolver_guard); + result + }; match pr { ValueNs::LocalBinding(_) | ValueNs::StaticId(_) => { let Some((temp, current)) = @@ -553,8 +575,11 @@ impl<'ctx> MirLowerCtx<'ctx> { return Ok(None); }; self.push_fake_read(current, cond_place, expr_id.into()); + let resolver_guard = + self.resolver.update_to_inner_scope(self.db.upcast(), self.owner, expr_id); let (then_target, else_target) = self.pattern_match(current, None, cond_place, *pat)?; + self.resolver.reset_to_guard(resolver_guard); self.write_bytes_to_place( then_target, place, @@ -688,6 +713,8 @@ impl<'ctx> MirLowerCtx<'ctx> { }; self.push_fake_read(current, cond_place, expr_id.into()); let mut end = None; + let resolver_guard = + self.resolver.update_to_inner_scope(self.db.upcast(), self.owner, expr_id); for MatchArm { pat, guard, expr } in arms.iter() { let (then, mut otherwise) = self.pattern_match(current, None, cond_place, *pat)?; @@ -721,6 +748,7 @@ impl<'ctx> MirLowerCtx<'ctx> { } } } + self.resolver.reset_to_guard(resolver_guard); if self.is_unterminated(current) { self.set_terminator(current, TerminatorKind::Unreachable, expr_id.into()); } @@ -795,7 +823,7 @@ impl<'ctx> MirLowerCtx<'ctx> { } Expr::Become { .. } => not_supported!("tail-calls"), Expr::Yield { .. } => not_supported!("yield"), - Expr::RecordLit { fields, path, spread, ellipsis: _, is_assignee_expr: _ } => { + Expr::RecordLit { fields, path, spread } => { let spread_place = match spread { &Some(it) => { let Some((p, c)) = self.lower_expr_as_place(current, it, true)? else { @@ -809,7 +837,9 @@ impl<'ctx> MirLowerCtx<'ctx> { let variant_id = self.infer.variant_resolution_for_expr(expr_id).ok_or_else(|| match path { Some(p) => MirLowerError::UnresolvedName( - p.display(self.db, self.edition()).to_string(), + hir_display_with_types_map(&**p, &self.body.types) + .display(self.db, self.edition()) + .to_string(), ), None => MirLowerError::RecordLiteralWithoutPath, })?; @@ -1010,35 +1040,28 @@ impl<'ctx> MirLowerCtx<'ctx> { ); } } - if let hir_def::hir::BinaryOp::Assignment { op } = op { - if let Some(op) = op { - // last adjustment is `&mut` which we don't want it. - let adjusts = self - .infer - .expr_adjustments - .get(lhs) - .and_then(|it| it.split_last()) - .map(|it| it.1) - .ok_or(MirLowerError::TypeError( - "adjustment of binary op was missing", - ))?; - let Some((lhs_place, current)) = - self.lower_expr_as_place_with_adjust(current, *lhs, false, adjusts)? - else { - return Ok(None); - }; - let Some((rhs_op, current)) = - self.lower_expr_to_some_operand(*rhs, current)? - else { - return Ok(None); - }; - let r_value = - Rvalue::CheckedBinaryOp(op.into(), Operand::Copy(lhs_place), rhs_op); - self.push_assignment(current, lhs_place, r_value, expr_id.into()); - return Ok(Some(current)); - } else { - return self.lower_assignment(current, *lhs, *rhs, expr_id.into()); - } + if let hir_def::hir::BinaryOp::Assignment { op: Some(op) } = op { + // last adjustment is `&mut` which we don't want it. + let adjusts = self + .infer + .expr_adjustments + .get(lhs) + .and_then(|it| it.split_last()) + .map(|it| it.1) + .ok_or(MirLowerError::TypeError("adjustment of binary op was missing"))?; + let Some((lhs_place, current)) = + self.lower_expr_as_place_with_adjust(current, *lhs, false, adjusts)? + else { + return Ok(None); + }; + let Some((rhs_op, current)) = self.lower_expr_to_some_operand(*rhs, current)? + else { + return Ok(None); + }; + let r_value = + Rvalue::CheckedBinaryOp(op.into(), Operand::Copy(lhs_place), rhs_op); + self.push_assignment(current, lhs_place, r_value, expr_id.into()); + return Ok(Some(current)); } let Some((lhs_op, current)) = self.lower_expr_to_some_operand(*lhs, current)? else { @@ -1097,6 +1120,18 @@ impl<'ctx> MirLowerCtx<'ctx> { ); Ok(Some(current)) } + &Expr::Assignment { target, value } => { + let Some((value, mut current)) = self.lower_expr_as_place(current, value, true)? + else { + return Ok(None); + }; + self.push_fake_read(current, value, expr_id.into()); + let resolver_guard = + self.resolver.update_to_inner_scope(self.db.upcast(), self.owner, expr_id); + current = self.pattern_match_assignment(current, value, target)?; + self.resolver.reset_to_guard(resolver_guard); + Ok(Some(current)) + } &Expr::Range { lhs, rhs, range_type: _ } => { let ty = self.expr_ty_without_adjust(expr_id); let Some((adt, subst)) = ty.as_adt() else { @@ -1213,7 +1248,7 @@ impl<'ctx> MirLowerCtx<'ctx> { ); Ok(Some(current)) } - Expr::Tuple { exprs, is_assignee_expr: _ } => { + Expr::Tuple { exprs } => { let Some(values) = exprs .iter() .map(|it| { @@ -1291,73 +1326,6 @@ impl<'ctx> MirLowerCtx<'ctx> { } } - fn lower_destructing_assignment( - &mut self, - mut current: BasicBlockId, - lhs: ExprId, - rhs: Place, - span: MirSpan, - ) -> Result<Option<BasicBlockId>> { - match &self.body.exprs[lhs] { - Expr::Tuple { exprs, is_assignee_expr: _ } => { - for (i, expr) in exprs.iter().enumerate() { - let rhs = rhs.project( - ProjectionElem::Field(Either::Right(TupleFieldId { - tuple: TupleId(!0), // Dummy this as its unused - index: i as u32, - })), - &mut self.result.projection_store, - ); - let Some(c) = self.lower_destructing_assignment(current, *expr, rhs, span)? - else { - return Ok(None); - }; - current = c; - } - Ok(Some(current)) - } - Expr::Underscore => Ok(Some(current)), - _ => { - let Some((lhs_place, current)) = self.lower_expr_as_place(current, lhs, false)? - else { - return Ok(None); - }; - self.push_assignment(current, lhs_place, Operand::Copy(rhs).into(), span); - Ok(Some(current)) - } - } - } - - fn lower_assignment( - &mut self, - current: BasicBlockId, - lhs: ExprId, - rhs: ExprId, - span: MirSpan, - ) -> Result<Option<BasicBlockId>> { - let Some((rhs_op, current)) = self.lower_expr_to_some_operand(rhs, current)? else { - return Ok(None); - }; - if matches!(&self.body.exprs[lhs], Expr::Underscore) { - self.push_fake_read_for_operand(current, rhs_op, span); - return Ok(Some(current)); - } - if matches!( - &self.body.exprs[lhs], - Expr::Tuple { .. } | Expr::RecordLit { .. } | Expr::Call { .. } - ) { - let temp = self.temp(self.expr_ty_after_adjustments(rhs), current, rhs.into())?; - let temp = Place::from(temp); - self.push_assignment(current, temp, rhs_op.into(), span); - return self.lower_destructing_assignment(current, lhs, temp, span); - } - let Some((lhs_place, current)) = self.lower_expr_as_place(current, lhs, false)? else { - return Ok(None); - }; - self.push_assignment(current, lhs_place, rhs_op.into(), span); - Ok(Some(current)) - } - fn placeholder_subst(&mut self) -> Substitution { match self.owner.as_generic_def_id(self.db.upcast()) { Some(it) => TyBuilder::placeholder_subst(self.db, it), @@ -1406,10 +1374,10 @@ impl<'ctx> MirLowerCtx<'ctx> { }; let edition = self.edition(); let unresolved_name = - || MirLowerError::unresolved_path(self.db, c.as_ref(), edition); - let resolver = self.owner.resolver(self.db.upcast()); - let pr = resolver - .resolve_path_in_value_ns(self.db.upcast(), c.as_ref()) + || MirLowerError::unresolved_path(self.db, c, edition, &self.body.types); + let pr = self + .resolver + .resolve_path_in_value_ns(self.db.upcast(), c, HygieneId::ROOT) .ok_or_else(unresolved_name)?; match pr { ResolveValueResult::ValueNs(v, _) => { @@ -1632,12 +1600,6 @@ impl<'ctx> MirLowerCtx<'ctx> { self.push_statement(block, StatementKind::FakeRead(p).with_span(span)); } - fn push_fake_read_for_operand(&mut self, block: BasicBlockId, operand: Operand, span: MirSpan) { - if let Operand::Move(p) | Operand::Copy(p) = operand { - self.push_fake_read(block, p, span); - } - } - fn push_assignment( &mut self, block: BasicBlockId, @@ -1791,8 +1753,16 @@ impl<'ctx> MirLowerCtx<'ctx> { }; current = c; self.push_fake_read(current, init_place, span); + // Using the initializer for the resolver scope is good enough for us, as it cannot create new declarations + // and has all declarations of the `let`. + let resolver_guard = self.resolver.update_to_inner_scope( + self.db.upcast(), + self.owner, + *expr_id, + ); (current, else_block) = self.pattern_match(current, None, init_place, *pat)?; + self.resolver.reset_to_guard(resolver_guard); match (else_block, else_branch) { (None, _) => (), (Some(else_block), None) => { @@ -1828,7 +1798,7 @@ impl<'ctx> MirLowerCtx<'ctx> { self.push_fake_read(c, p, expr.into()); current = scope2.pop_and_drop(self, c, expr.into()); } - hir_def::hir::Statement::Item => (), + hir_def::hir::Statement::Item(_) => (), } } if let Some(tail) = tail { @@ -2066,11 +2036,13 @@ pub fn mir_body_for_closure_query( let Some(sig) = ClosureSubst(substs).sig_ty().callable_sig(db) else { implementation_error!("closure has not callable sig"); }; + let resolver_guard = ctx.resolver.update_to_inner_scope(db.upcast(), owner, expr); let current = ctx.lower_params_and_bindings( args.iter().zip(sig.params().iter()).map(|(it, y)| (*it, y.clone())), None, |_| true, )?; + ctx.resolver.reset_to_guard(resolver_guard); if let Some(current) = ctx.lower_expr_to_place(*root, return_slot().into(), current)? { let current = ctx.pop_drop_scope_assert_finished(current, root.into())?; ctx.set_terminator(current, TerminatorKind::Return, (*root).into()); diff --git a/src/tools/rust-analyzer/crates/hir-ty/src/mir/lower/as_place.rs b/src/tools/rust-analyzer/crates/hir-ty/src/mir/lower/as_place.rs index 424ee1160c8..420f2aaff46 100644 --- a/src/tools/rust-analyzer/crates/hir-ty/src/mir/lower/as_place.rs +++ b/src/tools/rust-analyzer/crates/hir-ty/src/mir/lower/as_place.rs @@ -135,8 +135,13 @@ impl MirLowerCtx<'_> { }; match &self.body.exprs[expr_id] { Expr::Path(p) => { - let resolver = resolver_for_expr(self.db.upcast(), self.owner, expr_id); - let Some(pr) = resolver.resolve_path_in_value_ns_fully(self.db.upcast(), p) else { + let resolver_guard = + self.resolver.update_to_inner_scope(self.db.upcast(), self.owner, expr_id); + let hygiene = self.body.expr_path_hygiene(expr_id); + let resolved = + self.resolver.resolve_path_in_value_ns_fully(self.db.upcast(), p, hygiene); + self.resolver.reset_to_guard(resolver_guard); + let Some(pr) = resolved else { return try_rvalue(self); }; match pr { @@ -216,7 +221,7 @@ impl MirLowerCtx<'_> { self.push_field_projection(&mut r, expr_id)?; Ok(Some((r, current))) } - Expr::Index { base, index, is_assignee_expr: _ } => { + Expr::Index { base, index } => { let base_ty = self.expr_ty_after_adjustments(*base); let index_ty = self.expr_ty_after_adjustments(*index); if index_ty != TyBuilder::usize() diff --git a/src/tools/rust-analyzer/crates/hir-ty/src/mir/lower/pattern_matching.rs b/src/tools/rust-analyzer/crates/hir-ty/src/mir/lower/pattern_matching.rs index b1c0d1f2b39..2ffea34c85a 100644 --- a/src/tools/rust-analyzer/crates/hir-ty/src/mir/lower/pattern_matching.rs +++ b/src/tools/rust-analyzer/crates/hir-ty/src/mir/lower/pattern_matching.rs @@ -1,6 +1,6 @@ //! MIR lowering for patterns -use hir_def::{hir::LiteralOrConst, resolver::HasResolver, AssocItemId}; +use hir_def::{hir::LiteralOrConst, AssocItemId}; use crate::{ mir::{ @@ -46,6 +46,8 @@ enum MatchingMode { Check, /// Assume that this pattern matches, fill bindings Bind, + /// Assume that this pattern matches, assign to existing variables. + Assign, } impl MirLowerCtx<'_> { @@ -82,6 +84,17 @@ impl MirLowerCtx<'_> { Ok((current, current_else)) } + pub(super) fn pattern_match_assignment( + &mut self, + current: BasicBlockId, + value: Place, + pattern: PatId, + ) -> Result<BasicBlockId> { + let (current, _) = + self.pattern_match_inner(current, None, value, pattern, MatchingMode::Assign)?; + Ok(current) + } + pub(super) fn match_self_param( &mut self, id: BindingId, @@ -155,14 +168,8 @@ impl MirLowerCtx<'_> { *pat, MatchingMode::Check, )?; - if mode == MatchingMode::Bind { - (next, _) = self.pattern_match_inner( - next, - None, - cond_place, - *pat, - MatchingMode::Bind, - )?; + if mode != MatchingMode::Check { + (next, _) = self.pattern_match_inner(next, None, cond_place, *pat, mode)?; } self.set_goto(next, then_target, pattern.into()); match next_else { @@ -176,11 +183,11 @@ impl MirLowerCtx<'_> { } } if !finished { - if mode == MatchingMode::Bind { - self.set_terminator(current, TerminatorKind::Unreachable, pattern.into()); - } else { + if mode == MatchingMode::Check { let ce = *current_else.get_or_insert_with(|| self.new_basic_block()); self.set_goto(current, ce, pattern.into()); + } else { + self.set_terminator(current, TerminatorKind::Unreachable, pattern.into()); } } (then_target, current_else) @@ -300,7 +307,7 @@ impl MirLowerCtx<'_> { self.pattern_match_inner(current, current_else, next_place, pat, mode)?; } if let &Some(slice) = slice { - if mode == MatchingMode::Bind { + if mode != MatchingMode::Check { if let Pat::Bind { id, subpat: _ } = self.body[slice] { let next_place = cond_place.project( ProjectionElem::Subslice { @@ -342,17 +349,36 @@ impl MirLowerCtx<'_> { mode, )?, None => { - // The path is not a variant, so it is a const + let unresolved_name = || { + MirLowerError::unresolved_path(self.db, p, self.edition(), &self.body.types) + }; + let hygiene = self.body.pat_path_hygiene(pattern); + let pr = self + .resolver + .resolve_path_in_value_ns(self.db.upcast(), p, hygiene) + .ok_or_else(unresolved_name)?; + + if let ( + MatchingMode::Assign, + ResolveValueResult::ValueNs(ValueNs::LocalBinding(binding), _), + ) = (mode, &pr) + { + let local = self.binding_local(*binding)?; + self.push_match_assignment( + current, + local, + BindingMode::Move, + cond_place, + pattern.into(), + ); + return Ok((current, current_else)); + } + + // The path is not a variant or a local, so it is a const if mode != MatchingMode::Check { // A const don't bind anything. Only needs check. return Ok((current, current_else)); } - let unresolved_name = - || MirLowerError::unresolved_path(self.db, p, self.edition()); - let resolver = self.owner.resolver(self.db.upcast()); - let pr = resolver - .resolve_path_in_value_ns(self.db.upcast(), p) - .ok_or_else(unresolved_name)?; let (c, subst) = 'b: { if let Some(x) = self.infer.assoc_resolutions_for_pat(pattern) { if let AssocItemId::ConstId(c) = x.0 { @@ -415,7 +441,7 @@ impl MirLowerCtx<'_> { (current, current_else) = self.pattern_match_inner(current, current_else, cond_place, *subpat, mode)? } - if mode == MatchingMode::Bind { + if mode != MatchingMode::Check { let mode = self.infer.binding_modes[pattern]; self.pattern_match_binding( *id, @@ -448,6 +474,23 @@ impl MirLowerCtx<'_> { cond_place.project(ProjectionElem::Deref, &mut self.result.projection_store); self.pattern_match_inner(current, current_else, cond_place, *pat, mode)? } + &Pat::Expr(expr) => { + stdx::always!( + mode == MatchingMode::Assign, + "Pat::Expr can only come in destructuring assignments" + ); + let Some((lhs_place, current)) = self.lower_expr_as_place(current, expr, false)? + else { + return Ok((current, current_else)); + }; + self.push_assignment( + current, + lhs_place, + Operand::Copy(cond_place).into(), + expr.into(), + ); + (current, current_else) + } Pat::Box { .. } => not_supported!("box pattern"), Pat::ConstBlock(_) => not_supported!("const block pattern"), }) @@ -464,6 +507,18 @@ impl MirLowerCtx<'_> { ) -> Result<(BasicBlockId, Option<BasicBlockId>)> { let target_place = self.binding_local(id)?; self.push_storage_live(id, current)?; + self.push_match_assignment(current, target_place, mode, cond_place, span); + Ok((current, current_else)) + } + + fn push_match_assignment( + &mut self, + current: BasicBlockId, + target_place: LocalId, + mode: BindingMode, + cond_place: Place, + span: MirSpan, + ) { self.push_assignment( current, target_place.into(), @@ -476,7 +531,6 @@ impl MirLowerCtx<'_> { }, span, ); - Ok((current, current_else)) } fn pattern_match_const( diff --git a/src/tools/rust-analyzer/crates/hir-ty/src/mir/monomorphization.rs b/src/tools/rust-analyzer/crates/hir-ty/src/mir/monomorphization.rs index 4c6bc376e2b..92132fa0473 100644 --- a/src/tools/rust-analyzer/crates/hir-ty/src/mir/monomorphization.rs +++ b/src/tools/rust-analyzer/crates/hir-ty/src/mir/monomorphization.rs @@ -258,6 +258,10 @@ impl Filler<'_> { | Rvalue::UnaryOp(_, _) | Rvalue::Discriminant(_) | Rvalue::CopyForDeref(_) => (), + Rvalue::ThreadLocalRef(n) + | Rvalue::AddressOf(n) + | Rvalue::BinaryOp(n) + | Rvalue::NullaryOp(n) => match *n {}, }, StatementKind::Deinit(_) | StatementKind::FakeRead(_) diff --git a/src/tools/rust-analyzer/crates/hir-ty/src/mir/pretty.rs b/src/tools/rust-analyzer/crates/hir-ty/src/mir/pretty.rs index df56071aa9a..06765a104cb 100644 --- a/src/tools/rust-analyzer/crates/hir-ty/src/mir/pretty.rs +++ b/src/tools/rust-analyzer/crates/hir-ty/src/mir/pretty.rs @@ -459,6 +459,10 @@ impl<'a> MirPrettyCtx<'a> { self.place(p); w!(self, ")"); } + Rvalue::ThreadLocalRef(n) + | Rvalue::AddressOf(n) + | Rvalue::BinaryOp(n) + | Rvalue::NullaryOp(n) => match *n {}, } } diff --git a/src/tools/rust-analyzer/crates/hir-ty/src/tests/simple.rs b/src/tools/rust-analyzer/crates/hir-ty/src/tests/simple.rs index a8170b60606..5f0f341f393 100644 --- a/src/tools/rust-analyzer/crates/hir-ty/src/tests/simple.rs +++ b/src/tools/rust-analyzer/crates/hir-ty/src/tests/simple.rs @@ -3418,11 +3418,11 @@ struct TS(usize); fn main() { let x; [x,] = &[1,]; - //^^^^expected &'? [i32; 1], got [{unknown}; _] + //^^^^expected &'? [i32; 1], got [{unknown}] let x; [(x,),] = &[(1,),]; - //^^^^^^^expected &'? [(i32,); 1], got [{unknown}; _] + //^^^^^^^expected &'? [(i32,); 1], got [{unknown}] let x; ((x,),) = &((1,),); @@ -3720,3 +3720,85 @@ fn test() -> bool { "#]], ); } + +#[test] +fn macro_semitransparent_hygiene() { + check_types( + r#" +macro_rules! m { + () => { let bar: i32; }; +} +fn foo() { + let bar: bool; + m!(); + bar; + // ^^^ bool +} + "#, + ); +} + +#[test] +fn macro_expansion_can_refer_variables_defined_before_macro_definition() { + check_types( + r#" +fn foo() { + let v: i32 = 0; + macro_rules! m { + () => { v }; + } + let v: bool = true; + m!(); + // ^^^^ i32 +} + "#, + ); +} + +#[test] +fn macro_rules_shadowing_works_with_hygiene() { + check_types( + r#" +fn foo() { + let v: bool; + macro_rules! m { () => { v } } + m!(); + // ^^^^ bool + + let v: char; + macro_rules! m { () => { v } } + m!(); + // ^^^^ char + + { + let v: u8; + macro_rules! m { () => { v } } + m!(); + // ^^^^ u8 + + let v: i8; + macro_rules! m { () => { v } } + m!(); + // ^^^^ i8 + + let v: i16; + macro_rules! m { () => { v } } + m!(); + // ^^^^ i16 + + { + let v: u32; + macro_rules! m { () => { v } } + m!(); + // ^^^^ u32 + + let v: u64; + macro_rules! m { () => { v } } + m!(); + // ^^^^ u64 + } + } +} + "#, + ); +} diff --git a/src/tools/rust-analyzer/crates/hir-ty/src/utils.rs b/src/tools/rust-analyzer/crates/hir-ty/src/utils.rs index 620bba2d75c..0a436ff2b41 100644 --- a/src/tools/rust-analyzer/crates/hir-ty/src/utils.rs +++ b/src/tools/rust-analyzer/crates/hir-ty/src/utils.rs @@ -123,7 +123,7 @@ pub(super) struct ClauseElaborator<'a> { seen: FxHashSet<WhereClause>, } -impl<'a> ClauseElaborator<'a> { +impl ClauseElaborator<'_> { fn extend_deduped(&mut self, clauses: impl IntoIterator<Item = WhereClause>) { self.stack.extend(clauses.into_iter().filter(|c| self.seen.insert(c.clone()))) } @@ -163,10 +163,12 @@ fn direct_super_traits(db: &dyn DefDatabase, trait_: TraitId, cb: impl FnMut(Tra WherePredicate::ForLifetime { target, bound, .. } | WherePredicate::TypeBound { target, bound } => { let is_trait = match target { - WherePredicateTypeTarget::TypeRef(type_ref) => match &**type_ref { - TypeRef::Path(p) => p.is_self_type(), - _ => false, - }, + WherePredicateTypeTarget::TypeRef(type_ref) => { + match &generic_params.types_map[*type_ref] { + TypeRef::Path(p) => p.is_self_type(), + _ => false, + } + } WherePredicateTypeTarget::TypeOrConstParam(local_id) => { Some(*local_id) == trait_self } diff --git a/src/tools/rust-analyzer/crates/hir/src/db.rs b/src/tools/rust-analyzer/crates/hir/src/db.rs index cb5f5b06aef..22760c41aae 100644 --- a/src/tools/rust-analyzer/crates/hir/src/db.rs +++ b/src/tools/rust-analyzer/crates/hir/src/db.rs @@ -4,35 +4,43 @@ //! //! But we need this for at least LRU caching at the query level. pub use hir_def::db::{ - AttrsQuery, BlockDefMapQuery, BlockItemTreeQuery, BodyQuery, BodyWithSourceMapQuery, - ConstDataQuery, ConstVisibilityQuery, CrateDefMapQuery, CrateLangItemsQuery, - CrateNotableTraitsQuery, CrateSupportsNoStdQuery, DefDatabase, DefDatabaseStorage, - EnumDataQuery, EnumVariantDataWithDiagnosticsQuery, ExprScopesQuery, ExternCrateDeclDataQuery, - FieldVisibilitiesQuery, FieldsAttrsQuery, FieldsAttrsSourceMapQuery, FileItemTreeQuery, - FunctionDataQuery, FunctionVisibilityQuery, GenericParamsQuery, ImplDataWithDiagnosticsQuery, - ImportMapQuery, InternAnonymousConstQuery, InternBlockQuery, InternConstQuery, InternDatabase, - InternDatabaseStorage, InternEnumQuery, InternExternBlockQuery, InternExternCrateQuery, - InternFunctionQuery, InternImplQuery, InternInTypeConstQuery, InternMacro2Query, - InternMacroRulesQuery, InternProcMacroQuery, InternStaticQuery, InternStructQuery, - InternTraitAliasQuery, InternTraitQuery, InternTypeAliasQuery, InternUnionQuery, - InternUseQuery, LangItemQuery, Macro2DataQuery, MacroRulesDataQuery, ProcMacroDataQuery, - StaticDataQuery, StructDataWithDiagnosticsQuery, TraitAliasDataQuery, - TraitDataWithDiagnosticsQuery, TypeAliasDataQuery, UnionDataWithDiagnosticsQuery, + AttrsQuery, BlockDefMapQuery, BlockItemTreeQuery, BlockItemTreeWithSourceMapQuery, BodyQuery, + BodyWithSourceMapQuery, ConstDataQuery, ConstVisibilityQuery, CrateDefMapQuery, + CrateLangItemsQuery, CrateNotableTraitsQuery, CrateSupportsNoStdQuery, DefDatabase, + DefDatabaseStorage, EnumDataQuery, EnumVariantDataWithDiagnosticsQuery, + ExpandProcAttrMacrosQuery, ExprScopesQuery, ExternCrateDeclDataQuery, FieldVisibilitiesQuery, + FieldsAttrsQuery, FieldsAttrsSourceMapQuery, FileItemTreeQuery, FileItemTreeWithSourceMapQuery, + FunctionDataQuery, FunctionVisibilityQuery, GenericParamsQuery, + GenericParamsWithSourceMapQuery, ImplDataWithDiagnosticsQuery, ImportMapQuery, + IncludeMacroInvocQuery, InternAnonymousConstQuery, InternBlockQuery, InternConstQuery, + InternDatabase, InternDatabaseStorage, InternEnumQuery, InternExternBlockQuery, + InternExternCrateQuery, InternFunctionQuery, InternImplQuery, InternInTypeConstQuery, + InternMacro2Query, InternMacroRulesQuery, InternProcMacroQuery, InternStaticQuery, + InternStructQuery, InternTraitAliasQuery, InternTraitQuery, InternTypeAliasQuery, + InternUnionQuery, InternUseQuery, LangItemQuery, Macro2DataQuery, MacroDefQuery, + MacroRulesDataQuery, NotableTraitsInDepsQuery, ProcMacroDataQuery, StaticDataQuery, + StructDataWithDiagnosticsQuery, TraitAliasDataQuery, TraitDataWithDiagnosticsQuery, + TypeAliasDataQuery, UnionDataWithDiagnosticsQuery, }; pub use hir_expand::db::{ AstIdMapQuery, DeclMacroExpanderQuery, ExpandDatabase, ExpandDatabaseStorage, ExpandProcMacroQuery, InternMacroCallQuery, InternSyntaxContextQuery, MacroArgQuery, - ParseMacroExpansionErrorQuery, ParseMacroExpansionQuery, ProcMacrosQuery, RealSpanMapQuery, + ParseMacroExpansionErrorQuery, ParseMacroExpansionQuery, ProcMacroSpanQuery, ProcMacrosQuery, + RealSpanMapQuery, }; pub use hir_ty::db::{ AdtDatumQuery, AdtVarianceQuery, AssociatedTyDataQuery, AssociatedTyValueQuery, BorrowckQuery, CallableItemSignatureQuery, ConstEvalDiscriminantQuery, ConstEvalQuery, ConstEvalStaticQuery, - ConstParamTyQuery, FieldTypesQuery, FnDefDatumQuery, FnDefVarianceQuery, GenericDefaultsQuery, - GenericPredicatesForParamQuery, GenericPredicatesQuery, HirDatabase, HirDatabaseStorage, - ImplDatumQuery, ImplSelfTyQuery, ImplTraitQuery, IncoherentInherentImplCratesQuery, + ConstParamTyQuery, DynCompatibilityOfTraitQuery, FieldTypesQuery, FnDefDatumQuery, + FnDefVarianceQuery, GenericDefaultsQuery, GenericPredicatesForParamQuery, + GenericPredicatesQuery, GenericPredicatesWithoutParentQuery, HirDatabase, HirDatabaseStorage, + ImplDatumQuery, ImplSelfTyQuery, ImplTraitQuery, IncoherentInherentImplCratesQuery, InferQuery, InherentImplsInBlockQuery, InherentImplsInCrateQuery, InternCallableDefQuery, InternClosureQuery, InternCoroutineQuery, InternImplTraitIdQuery, InternLifetimeParamIdQuery, - InternTypeOrConstParamIdQuery, LayoutOfAdtQuery, MirBodyQuery, ProgramClausesForChalkEnvQuery, - ReturnTypeImplTraitsQuery, TargetDataLayoutQuery, TraitDatumQuery, TraitEnvironmentQuery, - TraitImplsInBlockQuery, TraitImplsInCrateQuery, TraitImplsInDepsQuery, TyQuery, ValueTyQuery, + InternTypeOrConstParamIdQuery, LayoutOfAdtQuery, LayoutOfTyQuery, LookupImplMethodQuery, + MirBodyForClosureQuery, MirBodyQuery, MonomorphizedMirBodyForClosureQuery, + MonomorphizedMirBodyQuery, ProgramClausesForChalkEnvQuery, ReturnTypeImplTraitsQuery, + TargetDataLayoutQuery, TraitDatumQuery, TraitEnvironmentQuery, TraitImplsInBlockQuery, + TraitImplsInCrateQuery, TraitImplsInDepsQuery, TraitSolveQuery, TyQuery, + TypeAliasImplTraitsQuery, ValueTyQuery, }; diff --git a/src/tools/rust-analyzer/crates/hir/src/diagnostics.rs b/src/tools/rust-analyzer/crates/hir/src/diagnostics.rs index 0b3cdb2f379..8297acde857 100644 --- a/src/tools/rust-analyzer/crates/hir/src/diagnostics.rs +++ b/src/tools/rust-analyzer/crates/hir/src/diagnostics.rs @@ -165,6 +165,7 @@ pub struct MacroError { pub precise_location: Option<TextRange>, pub message: String, pub error: bool, + pub kind: &'static str, } #[derive(Debug, Clone, Eq, PartialEq)] @@ -246,7 +247,7 @@ pub struct UnresolvedAssocItem { #[derive(Debug)] pub struct UnresolvedIdent { - pub expr: InFile<AstPtr<ast::Expr>>, + pub expr_or_pat: InFile<AstPtr<Either<ast::Expr, ast::Pat>>>, } #[derive(Debug)] @@ -257,7 +258,7 @@ pub struct PrivateField { #[derive(Debug)] pub struct MissingUnsafe { - pub expr: InFile<AstPtr<ast::Expr>>, + pub expr: InFile<AstPtr<Either<ast::Expr, ast::Pat>>>, /// If true, the diagnostics is an `unsafe_op_in_unsafe_fn` lint instead of a hard error. pub only_lint: bool, } @@ -398,56 +399,46 @@ impl AnyDiagnostic { .map(|idx| variant_data.fields()[idx].name.clone()) .collect(); - match record { - Either::Left(record_expr) => match source_map.expr_syntax(record_expr) { - Ok(source_ptr) => { - let root = source_ptr.file_syntax(db.upcast()); - if let ast::Expr::RecordExpr(record_expr) = - source_ptr.value.to_node(&root) - { - if record_expr.record_expr_field_list().is_some() { - let field_list_parent_path = - record_expr.path().map(|path| AstPtr::new(&path)); - return Some( - MissingFields { - file: source_ptr.file_id, - field_list_parent: AstPtr::new(&Either::Left( - record_expr, - )), - field_list_parent_path, - missed_fields, - } - .into(), - ); + let record = match record { + Either::Left(record_expr) => { + source_map.expr_syntax(record_expr).ok()?.map(AstPtr::wrap_left) + } + Either::Right(record_pat) => source_map.pat_syntax(record_pat).ok()?, + }; + let file = record.file_id; + let root = record.file_syntax(db.upcast()); + match record.value.to_node(&root) { + Either::Left(ast::Expr::RecordExpr(record_expr)) => { + if record_expr.record_expr_field_list().is_some() { + let field_list_parent_path = + record_expr.path().map(|path| AstPtr::new(&path)); + return Some( + MissingFields { + file, + field_list_parent: AstPtr::new(&Either::Left(record_expr)), + field_list_parent_path, + missed_fields, } - } + .into(), + ); } - Err(SyntheticSyntax) => (), - }, - Either::Right(record_pat) => match source_map.pat_syntax(record_pat) { - Ok(source_ptr) => { - if let Some(ptr) = source_ptr.value.cast::<ast::RecordPat>() { - let root = source_ptr.file_syntax(db.upcast()); - let record_pat = ptr.to_node(&root); - if record_pat.record_pat_field_list().is_some() { - let field_list_parent_path = - record_pat.path().map(|path| AstPtr::new(&path)); - return Some( - MissingFields { - file: source_ptr.file_id, - field_list_parent: AstPtr::new(&Either::Right( - record_pat, - )), - field_list_parent_path, - missed_fields, - } - .into(), - ); + } + Either::Right(ast::Pat::RecordPat(record_pat)) => { + if record_pat.record_pat_field_list().is_some() { + let field_list_parent_path = + record_pat.path().map(|path| AstPtr::new(&path)); + return Some( + MissingFields { + file, + field_list_parent: AstPtr::new(&Either::Right(record_pat)), + field_list_parent_path, + missed_fields, } - } + .into(), + ); } - Err(SyntheticSyntax) => (), - }, + } + _ => {} } } BodyValidationDiagnostic::ReplaceFilterMapNextWithFindMap { method_call_expr } => { @@ -541,15 +532,17 @@ impl AnyDiagnostic { let pat_syntax = |pat| { source_map.pat_syntax(pat).inspect_err(|_| tracing::error!("synthetic syntax")).ok() }; + let expr_or_pat_syntax = |id| match id { + ExprOrPatId::ExprId(expr) => expr_syntax(expr).map(|it| it.map(AstPtr::wrap_left)), + ExprOrPatId::PatId(pat) => pat_syntax(pat), + }; Some(match d { &InferenceDiagnostic::NoSuchField { field: expr, private, variant } => { let expr_or_pat = match expr { ExprOrPatId::ExprId(expr) => { source_map.field_syntax(expr).map(AstPtr::wrap_left) } - ExprOrPatId::PatId(pat) => { - source_map.pat_field_syntax(pat).map(AstPtr::wrap_right) - } + ExprOrPatId::PatId(pat) => source_map.pat_field_syntax(pat), }; NoSuchField { field: expr_or_pat, private, variant }.into() } @@ -562,10 +555,7 @@ impl AnyDiagnostic { PrivateField { expr, field }.into() } &InferenceDiagnostic::PrivateAssocItem { id, item } => { - let expr_or_pat = match id { - ExprOrPatId::ExprId(expr) => expr_syntax(expr)?.map(AstPtr::wrap_left), - ExprOrPatId::PatId(pat) => pat_syntax(pat)?.map(AstPtr::wrap_right), - }; + let expr_or_pat = expr_or_pat_syntax(id)?; let item = item.into(); PrivateAssocItem { expr_or_pat, item }.into() } @@ -609,15 +599,12 @@ impl AnyDiagnostic { .into() } &InferenceDiagnostic::UnresolvedAssocItem { id } => { - let expr_or_pat = match id { - ExprOrPatId::ExprId(expr) => expr_syntax(expr)?.map(AstPtr::wrap_left), - ExprOrPatId::PatId(pat) => pat_syntax(pat)?.map(AstPtr::wrap_right), - }; + let expr_or_pat = expr_or_pat_syntax(id)?; UnresolvedAssocItem { expr_or_pat }.into() } - &InferenceDiagnostic::UnresolvedIdent { expr } => { - let expr = expr_syntax(expr)?; - UnresolvedIdent { expr }.into() + &InferenceDiagnostic::UnresolvedIdent { id } => { + let expr_or_pat = expr_or_pat_syntax(id)?; + UnresolvedIdent { expr_or_pat }.into() } &InferenceDiagnostic::BreakOutsideOfLoop { expr, is_break, bad_value_break } => { let expr = expr_syntax(expr)?; diff --git a/src/tools/rust-analyzer/crates/hir/src/display.rs b/src/tools/rust-analyzer/crates/hir/src/display.rs index c2b2fbef751..9275f45d881 100644 --- a/src/tools/rust-analyzer/crates/hir/src/display.rs +++ b/src/tools/rust-analyzer/crates/hir/src/display.rs @@ -12,12 +12,11 @@ use hir_def::{ }; use hir_ty::{ display::{ - write_bounds_like_dyn_trait_with_prefix, write_visibility, HirDisplay, HirDisplayError, - HirFormatter, SizedByDefault, + hir_display_with_types_map, write_bounds_like_dyn_trait_with_prefix, write_visibility, + HirDisplay, HirDisplayError, HirDisplayWithTypesMap, HirFormatter, SizedByDefault, }, AliasEq, AliasTy, Interner, ProjectionTyExt, TraitRefExt, TyKind, WhereClause, }; -use intern::Interned; use itertools::Itertools; use crate::{ @@ -113,7 +112,7 @@ impl HirDisplay for Function { f.write_str(&pat_str)?; f.write_str(": ")?; - type_ref.hir_fmt(f)?; + type_ref.hir_fmt(f, &data.types_map)?; } if data.is_varargs() { @@ -129,28 +128,30 @@ impl HirDisplay for Function { // Use ugly pattern match to strip the Future trait. // Better way? let ret_type = if !data.is_async() { - &data.ret_type + Some(data.ret_type) } else { - match &*data.ret_type { - TypeRef::ImplTrait(bounds) => match bounds[0].as_ref() { - TypeBound::Path(path, _) => { - path.segments().iter().last().unwrap().args_and_bindings.unwrap().bindings + match &data.types_map[data.ret_type] { + TypeRef::ImplTrait(bounds) => match &bounds[0] { + TypeBound::Path(path, _) => Some( + *path.segments().iter().last().unwrap().args_and_bindings.unwrap().bindings [0] .type_ref .as_ref() - .unwrap() - } - _ => &TypeRef::Error, + .unwrap(), + ), + _ => None, }, - _ => &TypeRef::Error, + _ => None, } }; - match ret_type { - TypeRef::Tuple(tup) if tup.is_empty() => {} - ty => { - f.write_str(" -> ")?; - ty.hir_fmt(f)?; + if let Some(ret_type) = ret_type { + match &data.types_map[ret_type] { + TypeRef::Tuple(tup) if tup.is_empty() => {} + _ => { + f.write_str(" -> ")?; + ret_type.hir_fmt(f, &data.types_map)?; + } } } @@ -192,23 +193,23 @@ fn write_impl_header(impl_: &Impl, f: &mut HirFormatter<'_>) -> Result<(), HirDi impl HirDisplay for SelfParam { fn hir_fmt(&self, f: &mut HirFormatter<'_>) -> Result<(), HirDisplayError> { let data = f.db.function_data(self.func); - let param = data.params.first().unwrap(); - match &**param { + let param = *data.params.first().unwrap(); + match &data.types_map[param] { TypeRef::Path(p) if p.is_self_type() => f.write_str("self"), - TypeRef::Reference(inner, lifetime, mut_) if matches!(&**inner, TypeRef::Path(p) if p.is_self_type()) => + TypeRef::Reference(ref_) if matches!(&data.types_map[ref_.ty], TypeRef::Path(p) if p.is_self_type()) => { f.write_char('&')?; - if let Some(lifetime) = lifetime { + if let Some(lifetime) = &ref_.lifetime { write!(f, "{} ", lifetime.name.display(f.db.upcast(), f.edition()))?; } - if let hir_def::type_ref::Mutability::Mut = mut_ { + if let hir_def::type_ref::Mutability::Mut = ref_.mutability { f.write_str("mut ")?; } f.write_str("self") } - ty => { + _ => { f.write_str("self: ")?; - ty.hir_fmt(f) + param.hir_fmt(f, &data.types_map) } } } @@ -393,7 +394,7 @@ impl HirDisplay for Variant { let data = self.variant_data(f.db); match &*data { VariantData::Unit => {} - VariantData::Tuple(fields) => { + VariantData::Tuple { fields, types_map } => { f.write_char('(')?; let mut first = true; for (_, field) in fields.iter() { @@ -403,11 +404,11 @@ impl HirDisplay for Variant { f.write_str(", ")?; } // Enum variant fields must be pub. - field.type_ref.hir_fmt(f)?; + field.type_ref.hir_fmt(f, types_map)?; } f.write_char(')')?; } - VariantData::Record(_) => { + VariantData::Record { .. } => { if let Some(limit) = f.entity_limit { write_fields(&self.fields(f.db), false, limit, true, f)?; } @@ -579,13 +580,13 @@ fn write_generic_params( write!(f, "{}", name.display(f.db.upcast(), f.edition()))?; if let Some(default) = &ty.default { f.write_str(" = ")?; - default.hir_fmt(f)?; + default.hir_fmt(f, ¶ms.types_map)?; } } TypeOrConstParamData::ConstParamData(c) => { delim(f)?; write!(f, "const {}: ", name.display(f.db.upcast(), f.edition()))?; - c.ty.hir_fmt(f)?; + c.ty.hir_fmt(f, ¶ms.types_map)?; if let Some(default) = &c.default { f.write_str(" = ")?; @@ -615,7 +616,7 @@ fn write_where_clause( Ok(true) } -fn has_disaplayable_predicates(params: &Interned<GenericParams>) -> bool { +fn has_disaplayable_predicates(params: &GenericParams) -> bool { params.where_predicates().any(|pred| { !matches!( pred, @@ -626,21 +627,20 @@ fn has_disaplayable_predicates(params: &Interned<GenericParams>) -> bool { } fn write_where_predicates( - params: &Interned<GenericParams>, + params: &GenericParams, f: &mut HirFormatter<'_>, ) -> Result<(), HirDisplayError> { use WherePredicate::*; // unnamed type targets are displayed inline with the argument itself, e.g. `f: impl Y`. - let is_unnamed_type_target = - |params: &Interned<GenericParams>, target: &WherePredicateTypeTarget| { - matches!(target, - WherePredicateTypeTarget::TypeOrConstParam(id) if params[*id].name().is_none() - ) - }; + let is_unnamed_type_target = |params: &GenericParams, target: &WherePredicateTypeTarget| { + matches!(target, + WherePredicateTypeTarget::TypeOrConstParam(id) if params[*id].name().is_none() + ) + }; let write_target = |target: &WherePredicateTypeTarget, f: &mut HirFormatter<'_>| match target { - WherePredicateTypeTarget::TypeRef(ty) => ty.hir_fmt(f), + WherePredicateTypeTarget::TypeRef(ty) => ty.hir_fmt(f, ¶ms.types_map), WherePredicateTypeTarget::TypeOrConstParam(id) => match params[*id].name() { Some(name) => write!(f, "{}", name.display(f.db.upcast(), f.edition())), None => f.write_str("{unnamed}"), @@ -668,7 +668,7 @@ fn write_where_predicates( TypeBound { target, bound } => { write_target(target, f)?; f.write_str(": ")?; - bound.hir_fmt(f)?; + bound.hir_fmt(f, ¶ms.types_map)?; } Lifetime { target, bound } => { let target = target.name.display(f.db.upcast(), f.edition()); @@ -681,14 +681,16 @@ fn write_where_predicates( write!(f, "for<{lifetimes}> ")?; write_target(target, f)?; f.write_str(": ")?; - bound.hir_fmt(f)?; + bound.hir_fmt(f, ¶ms.types_map)?; } } while let Some(nxt) = iter.next_if(|nxt| check_same_target(pred, nxt)) { f.write_str(" + ")?; match nxt { - TypeBound { bound, .. } | ForLifetime { bound, .. } => bound.hir_fmt(f)?, + TypeBound { bound, .. } | ForLifetime { bound, .. } => { + bound.hir_fmt(f, ¶ms.types_map)? + } Lifetime { bound, .. } => { write!(f, "{}", bound.name.display(f.db.upcast(), f.edition()))? } @@ -716,7 +718,7 @@ impl HirDisplay for Const { Some(name) => write!(f, "{}: ", name.display(f.db.upcast(), f.edition()))?, None => f.write_str("_: ")?, } - data.type_ref.hir_fmt(f)?; + data.type_ref.hir_fmt(f, &data.types_map)?; Ok(()) } } @@ -730,7 +732,7 @@ impl HirDisplay for Static { f.write_str("mut ")?; } write!(f, "{}: ", data.name.display(f.db.upcast(), f.edition()))?; - data.type_ref.hir_fmt(f)?; + data.type_ref.hir_fmt(f, &data.types_map)?; Ok(()) } } @@ -813,11 +815,14 @@ impl HirDisplay for TypeAlias { write_generic_params(def_id, f)?; if !data.bounds.is_empty() { f.write_str(": ")?; - f.write_joined(data.bounds.iter(), " + ")?; + f.write_joined( + data.bounds.iter().map(|bound| hir_display_with_types_map(bound, &data.types_map)), + " + ", + )?; } - if let Some(ty) = &data.type_ref { + if let Some(ty) = data.type_ref { f.write_str(" = ")?; - ty.hir_fmt(f)?; + ty.hir_fmt(f, &data.types_map)?; } write_where_clause(def_id, f)?; Ok(()) diff --git a/src/tools/rust-analyzer/crates/hir/src/lib.rs b/src/tools/rust-analyzer/crates/hir/src/lib.rs index 30e023e1a47..88eb3b127e0 100644 --- a/src/tools/rust-analyzer/crates/hir/src/lib.rs +++ b/src/tools/rust-analyzer/crates/hir/src/lib.rs @@ -58,7 +58,8 @@ use hir_def::{ TypeOrConstParamId, TypeParamId, UnionId, }; use hir_expand::{ - attrs::collect_attrs, proc_macro::ProcMacroKind, AstId, MacroCallKind, ValueResult, + attrs::collect_attrs, proc_macro::ProcMacroKind, AstId, MacroCallKind, RenderedExpandError, + ValueResult, }; use hir_ty::{ all_super_traits, autoderef, check_orphan_rules, @@ -838,7 +839,7 @@ fn macro_call_diagnostics( let file_id = loc.kind.file_id(); let node = InFile::new(file_id, db.ast_id_map(file_id).get_erased(loc.kind.erased_ast_id())); - let (message, error) = err.render_to_string(db.upcast()); + let RenderedExpandError { message, error, kind } = err.render_to_string(db.upcast()); let precise_location = if err.span().anchor.file_id == file_id { Some( err.span().range @@ -850,7 +851,7 @@ fn macro_call_diagnostics( } else { None }; - acc.push(MacroError { node, precise_location, message, error }.into()); + acc.push(MacroError { node, precise_location, message, error, kind }.into()); } if !parse_errors.is_empty() { @@ -916,13 +917,14 @@ fn emit_def_diagnostic_( DefDiagnosticKind::MacroError { ast, path, err } => { let item = ast.to_ptr(db.upcast()); - let (message, error) = err.render_to_string(db.upcast()); + let RenderedExpandError { message, error, kind } = err.render_to_string(db.upcast()); acc.push( MacroError { node: InFile::new(ast.file_id, item.syntax_node_ptr()), precise_location: None, message: format!("{}: {message}", path.display(db.upcast(), edition)), error, + kind, } .into(), ) @@ -1811,7 +1813,8 @@ impl DefWithBody { InactiveCode { node: *node, cfg: cfg.clone(), opts: opts.clone() }.into() } BodyDiagnostic::MacroError { node, err } => { - let (message, error) = err.render_to_string(db.upcast()); + let RenderedExpandError { message, error, kind } = + err.render_to_string(db.upcast()); let precise_location = if err.span().anchor.file_id == node.file_id { Some( @@ -1829,6 +1832,7 @@ impl DefWithBody { precise_location, message, error, + kind, } .into() } @@ -1885,7 +1889,7 @@ impl DefWithBody { let (unafe_exprs, only_lint) = hir_ty::diagnostics::missing_unsafe(db, self.into()); for expr in unafe_exprs { - match source_map.expr_syntax(expr) { + match source_map.expr_or_pat_syntax(expr) { Ok(expr) => acc.push(MissingUnsafe { expr, only_lint }.into()), Err(SyntheticSyntax) => { // FIXME: Here and elsewhere in this file, the `expr` was @@ -2420,8 +2424,8 @@ impl SelfParam { func_data .params .first() - .map(|param| match &**param { - TypeRef::Reference(.., mutability) => match mutability { + .map(|¶m| match &func_data.types_map[param] { + TypeRef::Reference(ref_) => match ref_.mutability { hir_def::type_ref::Mutability::Shared => Access::Shared, hir_def::type_ref::Mutability::Mut => Access::Exclusive, }, @@ -2747,10 +2751,6 @@ impl TypeAlias { Module { id: self.id.module(db.upcast()) } } - pub fn type_ref(self, db: &dyn HirDatabase) -> Option<TypeRef> { - db.type_alias_data(self.id).type_ref.as_deref().cloned() - } - pub fn ty(self, db: &dyn HirDatabase) -> Type { Type::from_def(db, self.id) } @@ -3481,7 +3481,7 @@ impl Local { LocalSource { local: self, source: src.map(|ast| match ast.to_node(&root) { - ast::Pat::IdentPat(it) => Either::Left(it), + Either::Right(ast::Pat::IdentPat(it)) => Either::Left(it), _ => unreachable!("local with non ident-pattern"), }), } @@ -3510,7 +3510,7 @@ impl Local { LocalSource { local: self, source: src.map(|ast| match ast.to_node(&root) { - ast::Pat::IdentPat(it) => Either::Left(it), + Either::Right(ast::Pat::IdentPat(it)) => Either::Left(it), _ => unreachable!("local with non ident-pattern"), }), } @@ -4235,10 +4235,7 @@ impl CaptureUsages { } mir::MirSpan::PatId(pat) => { if let Ok(pat) = source_map.pat_syntax(pat) { - result.push(CaptureUsageSource { - is_ref, - source: pat.map(AstPtr::wrap_right), - }); + result.push(CaptureUsageSource { is_ref, source: pat }); } } mir::MirSpan::BindingId(binding) => result.extend( @@ -4246,10 +4243,7 @@ impl CaptureUsages { .patterns_for_binding(binding) .iter() .filter_map(|&pat| source_map.pat_syntax(pat).ok()) - .map(|pat| CaptureUsageSource { - is_ref, - source: pat.map(AstPtr::wrap_right), - }), + .map(|pat| CaptureUsageSource { is_ref, source: pat }), ), mir::MirSpan::SelfParam | mir::MirSpan::Unknown => { unreachable!("invalid capture usage span") diff --git a/src/tools/rust-analyzer/crates/hir/src/semantics.rs b/src/tools/rust-analyzer/crates/hir/src/semantics.rs index 3eac33ce990..feb9a344d8a 100644 --- a/src/tools/rust-analyzer/crates/hir/src/semantics.rs +++ b/src/tools/rust-analyzer/crates/hir/src/semantics.rs @@ -11,13 +11,13 @@ use std::{ use either::Either; use hir_def::{ - hir::Expr, + hir::{Expr, ExprOrPatId}, lower::LowerCtx, nameres::{MacroSubNs, ModuleOrigin}, path::ModPath, resolver::{self, HasResolver, Resolver, TypeNs}, - type_ref::Mutability, - AsMacroCall, DefWithBodyId, FunctionId, MacroId, TraitId, VariantId, + type_ref::{Mutability, TypesMap, TypesSourceMap}, + AsMacroCall, DefWithBodyId, FunctionId, MacroId, StructId, TraitId, VariantId, }; use hir_expand::{ attrs::collect_attrs, @@ -45,7 +45,7 @@ use syntax::{ use crate::{ db::HirDatabase, semantics::source_to_def::{ChildContainer, SourceToDefCache, SourceToDefCtx}, - source_analyzer::{resolve_hir_path, SourceAnalyzer}, + source_analyzer::{name_hygiene, resolve_hir_path, SourceAnalyzer}, Access, Adjust, Adjustment, Adt, AutoBorrow, BindingMode, BuiltinAttr, Callable, Const, ConstParam, Crate, DeriveHelper, Enum, Field, Function, HasSource, HirFileId, Impl, InFile, InlineAsmOperand, ItemInNs, Label, LifetimeParam, Local, Macro, Module, ModuleDef, Name, @@ -154,7 +154,7 @@ impl<'db, DB> ops::Deref for Semantics<'db, DB> { } } -impl<'db, DB: HirDatabase> Semantics<'db, DB> { +impl<DB: HirDatabase> Semantics<'_, DB> { pub fn new(db: &DB) -> Semantics<'_, DB> { let impl_ = SemanticsImpl::new(db); Semantics { db, imp: impl_ } @@ -203,6 +203,14 @@ impl<'db, DB: HirDatabase> Semantics<'db, DB> { self.imp.descend_node_at_offset(node, offset).filter_map(|mut it| it.find_map(N::cast)) } + pub fn resolve_range_pat(&self, range_pat: &ast::RangePat) -> Option<Struct> { + self.imp.resolve_range_pat(range_pat).map(Struct::from) + } + + pub fn resolve_range_expr(&self, range_expr: &ast::RangeExpr) -> Option<Struct> { + self.imp.resolve_range_expr(range_expr).map(Struct::from) + } + pub fn resolve_await_to_poll(&self, await_expr: &ast::AwaitExpr) -> Option<Function> { self.imp.resolve_await_to_poll(await_expr).map(Function::from) } @@ -928,16 +936,7 @@ impl<'db> SemanticsImpl<'db> { } } - let (file_id, tokens) = stack.first()?; - // make sure we pick the token in the expanded include if we encountered an include, - // otherwise we'll get the wrong semantics - let sa = - tokens.first()?.0.parent().and_then(|parent| { - self.analyze_impl(InFile::new(*file_id, &parent), None, false) - })?; - let mut m_cache = self.macro_call_cache.borrow_mut(); - let def_map = sa.resolver.def_map(); // Filters out all tokens that contain the given range (usually the macro call), any such // token is redundant as the corresponding macro call has already been processed @@ -946,6 +945,10 @@ impl<'db> SemanticsImpl<'db> { }; while let Some((expansion, ref mut tokens)) = stack.pop() { + // Reverse the tokens so we prefer first tokens (to accommodate for popping from the + // back) + // alternatively we could pop from the front but that would shift the content on every pop + tokens.reverse(); while let Some((token, ctx)) = tokens.pop() { let was_not_remapped = (|| { // First expand into attribute invocations @@ -1016,8 +1019,16 @@ impl<'db> SemanticsImpl<'db> { ) { call.as_macro_file() } else { - // FIXME: This is wrong, the SourceAnalyzer might be invalid here - sa.expand(self.db, mcall.as_ref())? + token + .parent() + .and_then(|parent| { + self.analyze_impl( + InFile::new(expansion, &parent), + None, + false, + ) + })? + .expand(self.db, mcall.as_ref())? }; m_cache.insert(mcall, it); it @@ -1087,9 +1098,16 @@ impl<'db> SemanticsImpl<'db> { attr.path().and_then(|it| it.as_single_name_ref())?.as_name(); // Not an attribute, nor a derive, so it's either an intert attribute or a derive helper // Try to resolve to a derive helper and downmap + let resolver = &token + .parent() + .and_then(|parent| { + self.analyze_impl(InFile::new(expansion, &parent), None, false) + })? + .resolver; let id = self.db.ast_id_map(expansion).ast_id(&adt); - let helpers = - def_map.derive_helpers_in_scope(InFile::new(expansion, id))?; + let helpers = resolver + .def_map() + .derive_helpers_in_scope(InFile::new(expansion, id))?; if !helpers.is_empty() { let text_range = attr.syntax().text_range(); @@ -1251,19 +1269,28 @@ impl<'db> SemanticsImpl<'db> { pub fn resolve_type(&self, ty: &ast::Type) -> Option<Type> { let analyze = self.analyze(ty.syntax())?; - let ctx = LowerCtx::new(self.db.upcast(), analyze.file_id); + let (mut types_map, mut types_source_map) = + (TypesMap::default(), TypesSourceMap::default()); + let ctx = + LowerCtx::new(self.db.upcast(), analyze.file_id, &mut types_map, &mut types_source_map); + let type_ref = crate::TypeRef::from_ast(&ctx, ty.clone()); let ty = hir_ty::TyLoweringContext::new_maybe_unowned( self.db, &analyze.resolver, + &types_map, + None, analyze.resolver.type_owner(), ) - .lower_ty(&crate::TypeRef::from_ast(&ctx, ty.clone())); + .lower_ty(type_ref); Some(Type::new_with_resolver(self.db, &analyze.resolver, ty)) } pub fn resolve_trait(&self, path: &ast::Path) -> Option<Trait> { let analyze = self.analyze(path.syntax())?; - let ctx = LowerCtx::new(self.db.upcast(), analyze.file_id); + let (mut types_map, mut types_source_map) = + (TypesMap::default(), TypesSourceMap::default()); + let ctx = + LowerCtx::new(self.db.upcast(), analyze.file_id, &mut types_map, &mut types_source_map); let hir_path = Path::from_src(&ctx, path.clone())?; match analyze.resolver.resolve_path_in_type_ns_fully(self.db.upcast(), &hir_path)? { TypeNs::TraitId(id) => Some(Trait { id }), @@ -1363,6 +1390,14 @@ impl<'db> SemanticsImpl<'db> { self.analyze(call.syntax())?.resolve_method_call_fallback(self.db, call) } + fn resolve_range_pat(&self, range_pat: &ast::RangePat) -> Option<StructId> { + self.analyze(range_pat.syntax())?.resolve_range_pat(self.db, range_pat) + } + + fn resolve_range_expr(&self, range_expr: &ast::RangeExpr) -> Option<StructId> { + self.analyze(range_expr.syntax())?.resolve_range_expr(self.db, range_expr) + } + fn resolve_await_to_poll(&self, await_expr: &ast::AwaitExpr) -> Option<FunctionId> { self.analyze(await_expr.syntax())?.resolve_await_to_poll(self.db, await_expr) } @@ -1761,7 +1796,9 @@ impl<'db> SemanticsImpl<'db> { } if let Some(parent) = ast::Expr::cast(parent.clone()) { - if let Some(expr_id) = source_map.node_expr(InFile { file_id, value: &parent }) { + if let Some(ExprOrPatId::ExprId(expr_id)) = + source_map.node_expr(InFile { file_id, value: &parent }) + { if let Expr::Unsafe { .. } = body[expr_id] { break true; } @@ -1934,10 +1971,19 @@ impl SemanticsScope<'_> { /// Resolve a path as-if it was written at the given scope. This is /// necessary a heuristic, as it doesn't take hygiene into account. - pub fn speculative_resolve(&self, path: &ast::Path) -> Option<PathResolution> { - let ctx = LowerCtx::new(self.db.upcast(), self.file_id); - let path = Path::from_src(&ctx, path.clone())?; - resolve_hir_path(self.db, &self.resolver, &path) + pub fn speculative_resolve(&self, ast_path: &ast::Path) -> Option<PathResolution> { + let (mut types_map, mut types_source_map) = + (TypesMap::default(), TypesSourceMap::default()); + let ctx = + LowerCtx::new(self.db.upcast(), self.file_id, &mut types_map, &mut types_source_map); + let path = Path::from_src(&ctx, ast_path.clone())?; + resolve_hir_path( + self.db, + &self.resolver, + &path, + name_hygiene(self.db, InFile::new(self.file_id, ast_path.syntax())), + &types_map, + ) } /// Iterates over associated types that may be specified after the given path (using diff --git a/src/tools/rust-analyzer/crates/hir/src/semantics/source_to_def.rs b/src/tools/rust-analyzer/crates/hir/src/semantics/source_to_def.rs index 389778b44ed..5357e824d09 100644 --- a/src/tools/rust-analyzer/crates/hir/src/semantics/source_to_def.rs +++ b/src/tools/rust-analyzer/crates/hir/src/semantics/source_to_def.rs @@ -328,7 +328,7 @@ impl SourceToDefCtx<'_, '_> { .position(|it| it == *src.value)?; let container = self.find_pat_or_label_container(src.syntax_ref())?; let (_, source_map) = self.db.body_with_source_map(container); - let expr = source_map.node_expr(src.with_value(&ast::Expr::AsmExpr(asm)))?; + let expr = source_map.node_expr(src.with_value(&ast::Expr::AsmExpr(asm)))?.as_expr()?; Some(InlineAsmOperand { owner: container, expr, index }) } @@ -372,7 +372,8 @@ impl SourceToDefCtx<'_, '_> { let break_or_continue = ast::Expr::cast(src.value.syntax().parent()?)?; let container = self.find_pat_or_label_container(src.syntax_ref())?; let (body, source_map) = self.db.body_with_source_map(container); - let break_or_continue = source_map.node_expr(src.with_value(&break_or_continue))?; + let break_or_continue = + source_map.node_expr(src.with_value(&break_or_continue))?.as_expr()?; let (Expr::Break { label, .. } | Expr::Continue { label }) = body[break_or_continue] else { return None; }; diff --git a/src/tools/rust-analyzer/crates/hir/src/source_analyzer.rs b/src/tools/rust-analyzer/crates/hir/src/source_analyzer.rs index 3da67ae23f8..8d6e228e14c 100644 --- a/src/tools/rust-analyzer/crates/hir/src/source_analyzer.rs +++ b/src/tools/rust-analyzer/crates/hir/src/source_analyzer.rs @@ -7,21 +7,26 @@ //! purely for "IDE needs". use std::iter::{self, once}; +use crate::{ + db::HirDatabase, semantics::PathResolution, Adt, AssocItem, BindingMode, BuiltinAttr, + BuiltinType, Callable, Const, DeriveHelper, Field, Function, Local, Macro, ModuleDef, Static, + Struct, ToolModule, Trait, TraitAlias, TupleField, Type, TypeAlias, Variant, +}; use either::Either; use hir_def::{ body::{ scope::{ExprScopes, ScopeId}, - Body, BodySourceMap, + Body, BodySourceMap, HygieneId, }, - hir::{BindingId, ExprId, Pat, PatId}, + hir::{BindingId, ExprId, ExprOrPatId, Pat, PatId}, lang_item::LangItem, lower::LowerCtx, nameres::MacroSubNs, path::{ModPath, Path, PathKind}, resolver::{resolver_for_scope, Resolver, TypeNs, ValueNs}, - type_ref::Mutability, + type_ref::{Mutability, TypesMap, TypesSourceMap}, AsMacroCall, AssocItemId, ConstId, DefWithBodyId, FieldId, FunctionId, ItemContainerId, - LocalFieldId, Lookup, ModuleDefId, TraitId, VariantId, + LocalFieldId, Lookup, ModuleDefId, StructId, TraitId, VariantId, }; use hir_expand::{ mod_path::path, @@ -40,18 +45,13 @@ use hir_ty::{ use intern::sym; use itertools::Itertools; use smallvec::SmallVec; +use syntax::ast::{RangeItem, RangeOp}; use syntax::{ ast::{self, AstNode}, SyntaxKind, SyntaxNode, TextRange, TextSize, }; use triomphe::Arc; -use crate::{ - db::HirDatabase, semantics::PathResolution, Adt, AssocItem, BindingMode, BuiltinAttr, - BuiltinType, Callable, Const, DeriveHelper, Field, Function, Local, Macro, ModuleDef, Static, - Struct, ToolModule, Trait, TraitAlias, TupleField, Type, TypeAlias, Variant, -}; - /// `SourceAnalyzer` is a convenience wrapper which exposes HIR API in terms of /// original source files. It should not be used inside the HIR itself. #[derive(Debug)] @@ -120,7 +120,7 @@ impl SourceAnalyzer { self.def.as_ref().map(|(_, body, _)| &**body) } - fn expr_id(&self, db: &dyn HirDatabase, expr: &ast::Expr) -> Option<ExprId> { + fn expr_id(&self, db: &dyn HirDatabase, expr: &ast::Expr) -> Option<ExprOrPatId> { let src = match expr { ast::Expr::MacroExpr(expr) => { self.expand_expr(db, InFile::new(self.file_id, expr.macro_call()?))?.into() @@ -174,7 +174,9 @@ impl SourceAnalyzer { db: &dyn HirDatabase, expr: &ast::Expr, ) -> Option<&[Adjustment]> { - let expr_id = self.expr_id(db, expr)?; + // It is safe to omit destructuring assignments here because they have no adjustments (neither + // expressions nor patterns). + let expr_id = self.expr_id(db, expr)?.as_expr()?; let infer = self.infer.as_ref()?; infer.expr_adjustments.get(&expr_id).map(|v| &**v) } @@ -186,9 +188,9 @@ impl SourceAnalyzer { ) -> Option<(Type, Option<Type>)> { let expr_id = self.expr_id(db, expr)?; let infer = self.infer.as_ref()?; - let coerced = infer - .expr_adjustments - .get(&expr_id) + let coerced = expr_id + .as_expr() + .and_then(|expr_id| infer.expr_adjustments.get(&expr_id)) .and_then(|adjusts| adjusts.last().map(|adjust| adjust.target.clone())); let ty = infer[expr_id].clone(); let mk_ty = |ty| Type::new_with_resolver(db, &self.resolver, ty); @@ -268,7 +270,7 @@ impl SourceAnalyzer { db: &dyn HirDatabase, call: &ast::MethodCallExpr, ) -> Option<Callable> { - let expr_id = self.expr_id(db, &call.clone().into())?; + let expr_id = self.expr_id(db, &call.clone().into())?.as_expr()?; let (func, substs) = self.infer.as_ref()?.method_resolution(expr_id)?; let ty = db.value_ty(func.into())?.substitute(Interner, &substs); let ty = Type::new_with_resolver(db, &self.resolver, ty); @@ -282,7 +284,7 @@ impl SourceAnalyzer { db: &dyn HirDatabase, call: &ast::MethodCallExpr, ) -> Option<Function> { - let expr_id = self.expr_id(db, &call.clone().into())?; + let expr_id = self.expr_id(db, &call.clone().into())?.as_expr()?; let (f_in_trait, substs) = self.infer.as_ref()?.method_resolution(expr_id)?; Some(self.resolve_impl_method_or_trait_def(db, f_in_trait, substs).into()) @@ -293,7 +295,7 @@ impl SourceAnalyzer { db: &dyn HirDatabase, call: &ast::MethodCallExpr, ) -> Option<Either<Function, Field>> { - let expr_id = self.expr_id(db, &call.clone().into())?; + let expr_id = self.expr_id(db, &call.clone().into())?.as_expr()?; let inference_result = self.infer.as_ref()?; match inference_result.method_resolution(expr_id) { Some((f_in_trait, substs)) => Some(Either::Left( @@ -322,7 +324,7 @@ impl SourceAnalyzer { field: &ast::FieldExpr, ) -> Option<Either<Field, TupleField>> { let &(def, ..) = self.def.as_ref()?; - let expr_id = self.expr_id(db, &field.clone().into())?; + let expr_id = self.expr_id(db, &field.clone().into())?.as_expr()?; self.infer.as_ref()?.field_resolution(expr_id).map(|it| { it.map_either(Into::into, |f| TupleField { owner: def, tuple: f.tuple, index: f.index }) }) @@ -334,7 +336,7 @@ impl SourceAnalyzer { field: &ast::FieldExpr, ) -> Option<Either<Either<Field, TupleField>, Function>> { let &(def, ..) = self.def.as_ref()?; - let expr_id = self.expr_id(db, &field.clone().into())?; + let expr_id = self.expr_id(db, &field.clone().into())?.as_expr()?; let inference_result = self.infer.as_ref()?; match inference_result.field_resolution(expr_id) { Some(field) => Some(Either::Left(field.map_either(Into::into, |f| TupleField { @@ -348,6 +350,45 @@ impl SourceAnalyzer { } } + pub(crate) fn resolve_range_pat( + &self, + db: &dyn HirDatabase, + range_pat: &ast::RangePat, + ) -> Option<StructId> { + let path: ModPath = match (range_pat.op_kind()?, range_pat.start(), range_pat.end()) { + (RangeOp::Exclusive, None, Some(_)) => path![core::ops::RangeTo], + (RangeOp::Exclusive, Some(_), None) => path![core::ops::RangeFrom], + (RangeOp::Exclusive, Some(_), Some(_)) => path![core::ops::Range], + (RangeOp::Inclusive, None, Some(_)) => path![core::ops::RangeToInclusive], + (RangeOp::Inclusive, Some(_), Some(_)) => path![core::ops::RangeInclusive], + + (RangeOp::Exclusive, None, None) => return None, + (RangeOp::Inclusive, None, None) => return None, + (RangeOp::Inclusive, Some(_), None) => return None, + }; + self.resolver.resolve_known_struct(db.upcast(), &path) + } + + pub(crate) fn resolve_range_expr( + &self, + db: &dyn HirDatabase, + range_expr: &ast::RangeExpr, + ) -> Option<StructId> { + let path: ModPath = match (range_expr.op_kind()?, range_expr.start(), range_expr.end()) { + (RangeOp::Exclusive, None, None) => path![core::ops::RangeFull], + (RangeOp::Exclusive, None, Some(_)) => path![core::ops::RangeTo], + (RangeOp::Exclusive, Some(_), None) => path![core::ops::RangeFrom], + (RangeOp::Exclusive, Some(_), Some(_)) => path![core::ops::Range], + (RangeOp::Inclusive, None, Some(_)) => path![core::ops::RangeToInclusive], + (RangeOp::Inclusive, Some(_), Some(_)) => path![core::ops::RangeInclusive], + + // [E0586] inclusive ranges must be bounded at the end + (RangeOp::Inclusive, None, None) => return None, + (RangeOp::Inclusive, Some(_), None) => return None, + }; + self.resolver.resolve_known_struct(db.upcast(), &path) + } + pub(crate) fn resolve_await_to_poll( &self, db: &dyn HirDatabase, @@ -403,7 +444,7 @@ impl SourceAnalyzer { self.infer .as_ref() .and_then(|infer| { - let expr = self.expr_id(db, &prefix_expr.clone().into())?; + let expr = self.expr_id(db, &prefix_expr.clone().into())?.as_expr()?; let (func, _) = infer.method_resolution(expr)?; let (deref_mut_trait, deref_mut) = self.lang_trait_fn( db, @@ -449,7 +490,7 @@ impl SourceAnalyzer { .infer .as_ref() .and_then(|infer| { - let expr = self.expr_id(db, &index_expr.clone().into())?; + let expr = self.expr_id(db, &index_expr.clone().into())?.as_expr()?; let (func, _) = infer.method_resolution(expr)?; let (index_mut_trait, index_mut_fn) = self.lang_trait_fn( db, @@ -521,7 +562,8 @@ impl SourceAnalyzer { let expr = ast::Expr::from(record_expr); let expr_id = self.body_source_map()?.node_expr(InFile::new(self.file_id, &expr))?; - let local_name = field.field_name()?.as_name(); + let ast_name = field.field_name()?; + let local_name = ast_name.as_name(); let local = if field.name_ref().is_some() { None } else { @@ -530,15 +572,19 @@ impl SourceAnalyzer { PathKind::Plain, once(local_name.clone()), )); - match self.resolver.resolve_path_in_value_ns_fully(db.upcast(), &path) { + match self.resolver.resolve_path_in_value_ns_fully( + db.upcast(), + &path, + name_hygiene(db, InFile::new(self.file_id, ast_name.syntax())), + ) { Some(ValueNs::LocalBinding(binding_id)) => { Some(Local { binding_id, parent: self.resolver.body_owner()? }) } _ => None, } }; - let (_, subst) = self.infer.as_ref()?.type_of_expr.get(expr_id)?.as_adt()?; - let variant = self.infer.as_ref()?.variant_resolution_for_expr(expr_id)?; + let (_, subst) = self.infer.as_ref()?.type_of_expr_or_pat(expr_id)?.as_adt()?; + let variant = self.infer.as_ref()?.variant_resolution_for_expr_or_pat(expr_id)?; let variant_data = variant.variant_data(db.upcast()); let field = FieldId { parent: variant, local_id: variant_data.field(&local_name)? }; let field_ty = @@ -568,7 +614,10 @@ impl SourceAnalyzer { db: &dyn HirDatabase, macro_call: InFile<&ast::MacroCall>, ) -> Option<Macro> { - let ctx = LowerCtx::new(db.upcast(), macro_call.file_id); + let (mut types_map, mut types_source_map) = + (TypesMap::default(), TypesSourceMap::default()); + let ctx = + LowerCtx::new(db.upcast(), macro_call.file_id, &mut types_map, &mut types_source_map); let path = macro_call.value.path().and_then(|ast| Path::from_src(&ctx, ast))?; self.resolver .resolve_path_as_macro(db.upcast(), path.mod_path()?, Some(MacroSubNs::Bang)) @@ -586,7 +635,7 @@ impl SourceAnalyzer { Pat::Path(path) => path, _ => return None, }; - let res = resolve_hir_path(db, &self.resolver, path)?; + let res = resolve_hir_path(db, &self.resolver, path, HygieneId::ROOT, TypesMap::EMPTY)?; match res { PathResolution::Def(def) => Some(def), _ => None, @@ -606,10 +655,10 @@ impl SourceAnalyzer { let infer = self.infer.as_deref()?; if let Some(path_expr) = parent().and_then(ast::PathExpr::cast) { let expr_id = self.expr_id(db, &path_expr.into())?; - if let Some((assoc, subs)) = infer.assoc_resolutions_for_expr(expr_id) { + if let Some((assoc, subs)) = infer.assoc_resolutions_for_expr_or_pat(expr_id) { let assoc = match assoc { AssocItemId::FunctionId(f_in_trait) => { - match infer.type_of_expr.get(expr_id) { + match infer.type_of_expr_or_pat(expr_id) { None => assoc, Some(func_ty) => { if let TyKind::FnDef(_fn_def, subs) = func_ty.kind(Interner) { @@ -634,7 +683,7 @@ impl SourceAnalyzer { return Some(PathResolution::Def(AssocItem::from(assoc).into())); } if let Some(VariantId::EnumVariantId(variant)) = - infer.variant_resolution_for_expr(expr_id) + infer.variant_resolution_for_expr_or_pat(expr_id) { return Some(PathResolution::Def(ModuleDef::Variant(variant.into()))); } @@ -658,7 +707,7 @@ impl SourceAnalyzer { } else if let Some(rec_lit) = parent().and_then(ast::RecordExpr::cast) { let expr_id = self.expr_id(db, &rec_lit.into())?; if let Some(VariantId::EnumVariantId(variant)) = - infer.variant_resolution_for_expr(expr_id) + infer.variant_resolution_for_expr_or_pat(expr_id) { return Some(PathResolution::Def(ModuleDef::Variant(variant.into()))); } @@ -680,14 +729,16 @@ impl SourceAnalyzer { return resolved; } - let ctx = LowerCtx::new(db.upcast(), self.file_id); + let (mut types_map, mut types_source_map) = + (TypesMap::default(), TypesSourceMap::default()); + let ctx = LowerCtx::new(db.upcast(), self.file_id, &mut types_map, &mut types_source_map); let hir_path = Path::from_src(&ctx, path.clone())?; // Case where path is a qualifier of a use tree, e.g. foo::bar::{Baz, Qux} where we are // trying to resolve foo::bar. if let Some(use_tree) = parent().and_then(ast::UseTree::cast) { if use_tree.coloncolon_token().is_some() { - return resolve_hir_path_qualifier(db, &self.resolver, &hir_path); + return resolve_hir_path_qualifier(db, &self.resolver, &hir_path, &types_map); } } @@ -704,7 +755,7 @@ impl SourceAnalyzer { // Case where path is a qualifier of another path, e.g. foo::bar::Baz where we are // trying to resolve foo::bar. if path.parent_path().is_some() { - return match resolve_hir_path_qualifier(db, &self.resolver, &hir_path) { + return match resolve_hir_path_qualifier(db, &self.resolver, &hir_path, &types_map) { None if meta_path.is_some() => { path.first_segment().and_then(|it| it.name_ref()).and_then(|name_ref| { ToolModule::by_name(db, self.resolver.krate().into(), &name_ref.text()) @@ -775,9 +826,16 @@ impl SourceAnalyzer { }; } if parent().map_or(false, |it| ast::Visibility::can_cast(it.kind())) { - resolve_hir_path_qualifier(db, &self.resolver, &hir_path) + resolve_hir_path_qualifier(db, &self.resolver, &hir_path, &types_map) } else { - resolve_hir_path_(db, &self.resolver, &hir_path, prefer_value_ns) + resolve_hir_path_( + db, + &self.resolver, + &hir_path, + prefer_value_ns, + name_hygiene(db, InFile::new(self.file_id, path.syntax())), + &types_map, + ) } } @@ -790,10 +848,16 @@ impl SourceAnalyzer { let infer = self.infer.as_ref()?; let expr_id = self.expr_id(db, &literal.clone().into())?; - let substs = infer.type_of_expr[expr_id].as_adt()?.1; + let substs = infer[expr_id].as_adt()?.1; - let (variant, missing_fields, _exhaustive) = - record_literal_missing_fields(db, infer, expr_id, &body[expr_id])?; + let (variant, missing_fields, _exhaustive) = match expr_id { + ExprOrPatId::ExprId(expr_id) => { + record_literal_missing_fields(db, infer, expr_id, &body[expr_id])? + } + ExprOrPatId::PatId(pat_id) => { + record_pattern_missing_fields(db, infer, pat_id, &body[pat_id])? + } + }; let res = self.missing_fields(db, substs, variant, missing_fields); Some(res) } @@ -856,7 +920,7 @@ impl SourceAnalyzer { ) -> Option<VariantId> { let infer = self.infer.as_ref()?; let expr_id = self.expr_id(db, &record_lit.into())?; - infer.variant_resolution_for_expr(expr_id) + infer.variant_resolution_for_expr_or_pat(expr_id) } pub(crate) fn is_unsafe_macro_call_expr( @@ -867,14 +931,24 @@ impl SourceAnalyzer { if let (Some((def, body, sm)), Some(infer)) = (&self.def, &self.infer) { if let Some(expanded_expr) = sm.macro_expansion_expr(macro_expr) { let mut is_unsafe = false; - unsafe_expressions( - db, - infer, - *def, - body, - expanded_expr, - &mut |UnsafeExpr { inside_unsafe_block, .. }| is_unsafe |= !inside_unsafe_block, - ); + let mut walk_expr = |expr_id| { + unsafe_expressions( + db, + infer, + *def, + body, + expr_id, + &mut |UnsafeExpr { inside_unsafe_block, .. }| { + is_unsafe |= !inside_unsafe_block + }, + ) + }; + match expanded_expr { + ExprOrPatId::ExprId(expanded_expr) => walk_expr(expanded_expr), + ExprOrPatId::PatId(expanded_pat) => { + body.walk_exprs_in_pat(expanded_pat, &mut walk_expr) + } + } return is_unsafe; } } @@ -887,7 +961,7 @@ impl SourceAnalyzer { format_args: InFile<&ast::FormatArgsExpr>, offset: TextSize, ) -> Option<(TextRange, Option<PathResolution>)> { - let implicits = self.body_source_map()?.implicit_format_args(format_args)?; + let (hygiene, implicits) = self.body_source_map()?.implicit_format_args(format_args)?; implicits.iter().find(|(range, _)| range.contains_inclusive(offset)).map(|(range, name)| { ( *range, @@ -899,6 +973,7 @@ impl SourceAnalyzer { PathKind::Plain, Some(name.clone()), )), + hygiene, ), ) }) @@ -925,22 +1000,22 @@ impl SourceAnalyzer { db: &'a dyn HirDatabase, format_args: InFile<&ast::FormatArgsExpr>, ) -> Option<impl Iterator<Item = (TextRange, Option<PathResolution>)> + 'a> { - Some(self.body_source_map()?.implicit_format_args(format_args)?.iter().map( - move |(range, name)| { - ( - *range, - resolve_hir_value_path( - db, - &self.resolver, - self.resolver.body_owner(), - &Path::from_known_path_with_no_generic(ModPath::from_segments( - PathKind::Plain, - Some(name.clone()), - )), - ), - ) - }, - )) + let (hygiene, names) = self.body_source_map()?.implicit_format_args(format_args)?; + Some(names.iter().map(move |(range, name)| { + ( + *range, + resolve_hir_value_path( + db, + &self.resolver, + self.resolver.body_owner(), + &Path::from_known_path_with_no_generic(ModPath::from_segments( + PathKind::Plain, + Some(name.clone()), + )), + hygiene, + ), + ) + })) } pub(crate) fn as_asm_parts( @@ -991,7 +1066,7 @@ impl SourceAnalyzer { } fn ty_of_expr(&self, db: &dyn HirDatabase, expr: &ast::Expr) -> Option<&Ty> { - self.infer.as_ref()?.type_of_expr.get(self.expr_id(db, expr)?) + self.infer.as_ref()?.type_of_expr_or_pat(self.expr_id(db, expr)?) } } @@ -1004,7 +1079,7 @@ fn scope_for( node.ancestors_with_macros(db.upcast()) .take_while(|it| !ast::Item::can_cast(it.kind()) || ast::MacroCall::can_cast(it.kind())) .filter_map(|it| it.map(ast::Expr::cast).transpose()) - .filter_map(|it| source_map.node_expr(it.as_ref())) + .filter_map(|it| source_map.node_expr(it.as_ref())?.as_expr()) .find_map(|it| scopes.scope_for(it)) } @@ -1086,8 +1161,10 @@ pub(crate) fn resolve_hir_path( db: &dyn HirDatabase, resolver: &Resolver, path: &Path, + hygiene: HygieneId, + types_map: &TypesMap, ) -> Option<PathResolution> { - resolve_hir_path_(db, resolver, path, false) + resolve_hir_path_(db, resolver, path, false, hygiene, types_map) } #[inline] @@ -1107,13 +1184,20 @@ fn resolve_hir_path_( resolver: &Resolver, path: &Path, prefer_value_ns: bool, + hygiene: HygieneId, + types_map: &TypesMap, ) -> Option<PathResolution> { let types = || { let (ty, unresolved) = match path.type_anchor() { Some(type_ref) => { - let (_, res) = - TyLoweringContext::new_maybe_unowned(db, resolver, resolver.type_owner()) - .lower_ty_ext(type_ref); + let (_, res) = TyLoweringContext::new_maybe_unowned( + db, + resolver, + types_map, + None, + resolver.type_owner(), + ) + .lower_ty_ext(type_ref); res.map(|ty_ns| (ty_ns, path.segments().first())) } None => { @@ -1172,7 +1256,7 @@ fn resolve_hir_path_( }; let body_owner = resolver.body_owner(); - let values = || resolve_hir_value_path(db, resolver, body_owner, path); + let values = || resolve_hir_value_path(db, resolver, body_owner, path, hygiene); let items = || { resolver @@ -1197,8 +1281,9 @@ fn resolve_hir_value_path( resolver: &Resolver, body_owner: Option<DefWithBodyId>, path: &Path, + hygiene: HygieneId, ) -> Option<PathResolution> { - resolver.resolve_path_in_value_ns_fully(db.upcast(), path).and_then(|val| { + resolver.resolve_path_in_value_ns_fully(db.upcast(), path, hygiene).and_then(|val| { let res = match val { ValueNs::LocalBinding(binding_id) => { let var = Local { parent: body_owner?, binding_id }; @@ -1233,13 +1318,19 @@ fn resolve_hir_path_qualifier( db: &dyn HirDatabase, resolver: &Resolver, path: &Path, + types_map: &TypesMap, ) -> Option<PathResolution> { (|| { let (ty, unresolved) = match path.type_anchor() { Some(type_ref) => { - let (_, res) = - TyLoweringContext::new_maybe_unowned(db, resolver, resolver.type_owner()) - .lower_ty_ext(type_ref); + let (_, res) = TyLoweringContext::new_maybe_unowned( + db, + resolver, + types_map, + None, + resolver.type_owner(), + ) + .lower_ty_ext(type_ref); res.map(|ty_ns| (ty_ns, path.segments().first())) } None => { @@ -1303,3 +1394,13 @@ fn resolve_hir_path_qualifier( .map(|it| PathResolution::Def(it.into())) }) } + +pub(crate) fn name_hygiene(db: &dyn HirDatabase, name: InFile<&SyntaxNode>) -> HygieneId { + let Some(macro_file) = name.file_id.macro_file() else { + return HygieneId::ROOT; + }; + let span_map = db.expansion_span_map(macro_file); + let ctx = span_map.span_at(name.value.text_range().start()).ctx; + let ctx = db.lookup_intern_syntax_context(ctx); + HygieneId::new(ctx.opaque_and_semitransparent) +} diff --git a/src/tools/rust-analyzer/crates/hir/src/symbols.rs b/src/tools/rust-analyzer/crates/hir/src/symbols.rs index cabb7e3db3d..f8416f86bf9 100644 --- a/src/tools/rust-analyzer/crates/hir/src/symbols.rs +++ b/src/tools/rust-analyzer/crates/hir/src/symbols.rs @@ -8,7 +8,10 @@ use hir_def::{ TraitId, }; use hir_expand::HirFileId; -use hir_ty::{db::HirDatabase, display::HirDisplay}; +use hir_ty::{ + db::HirDatabase, + display::{hir_display_with_types_map, HirDisplay}, +}; use span::Edition; use syntax::{ast::HasName, AstNode, AstPtr, SmolStr, SyntaxNode, SyntaxNodePtr, ToSmolStr}; @@ -214,8 +217,11 @@ impl<'a> SymbolCollector<'a> { fn collect_from_impl(&mut self, impl_id: ImplId) { let impl_data = self.db.impl_data(impl_id); - let impl_name = - Some(SmolStr::new(impl_data.self_ty.display(self.db, self.edition).to_string())); + let impl_name = Some( + hir_display_with_types_map(impl_data.self_ty, &impl_data.types_map) + .display(self.db, self.edition) + .to_smolstr(), + ); self.with_container_name(impl_name, |s| { for &assoc_item_id in impl_data.items.iter() { s.push_assoc_item(assoc_item_id) diff --git a/src/tools/rust-analyzer/crates/ide-assists/Cargo.toml b/src/tools/rust-analyzer/crates/ide-assists/Cargo.toml index 2a14fbe1e0a..ba215868710 100644 --- a/src/tools/rust-analyzer/crates/ide-assists/Cargo.toml +++ b/src/tools/rust-analyzer/crates/ide-assists/Cargo.toml @@ -23,7 +23,6 @@ tracing.workspace = true # local deps stdx.workspace = true syntax.workspace = true -text-edit.workspace = true ide-db.workspace = true hir.workspace = true diff --git a/src/tools/rust-analyzer/crates/ide-assists/src/handlers/bool_to_enum.rs b/src/tools/rust-analyzer/crates/ide-assists/src/handlers/bool_to_enum.rs index c035c59ffca..605fd140523 100644 --- a/src/tools/rust-analyzer/crates/ide-assists/src/handlers/bool_to_enum.rs +++ b/src/tools/rust-analyzer/crates/ide-assists/src/handlers/bool_to_enum.rs @@ -1,5 +1,6 @@ use either::Either; use hir::ModuleDef; +use ide_db::text_edit::TextRange; use ide_db::{ assists::{AssistId, AssistKind}, defs::Definition, @@ -19,7 +20,6 @@ use syntax::{ }, AstNode, NodeOrToken, SyntaxKind, SyntaxNode, T, }; -use text_edit::TextRange; use crate::{ assist_context::{AssistContext, Assists}, diff --git a/src/tools/rust-analyzer/crates/ide-assists/src/handlers/destructure_struct_binding.rs b/src/tools/rust-analyzer/crates/ide-assists/src/handlers/destructure_struct_binding.rs index b229b750e88..22a1efdbea7 100644 --- a/src/tools/rust-analyzer/crates/ide-assists/src/handlers/destructure_struct_binding.rs +++ b/src/tools/rust-analyzer/crates/ide-assists/src/handlers/destructure_struct_binding.rs @@ -1,4 +1,5 @@ use hir::{sym, HasVisibility}; +use ide_db::text_edit::TextRange; use ide_db::{ assists::{AssistId, AssistKind}, defs::Definition, @@ -8,7 +9,6 @@ use ide_db::{ }; use itertools::Itertools; use syntax::{ast, ted, AstNode, Edition, SmolStr, SyntaxNode, ToSmolStr}; -use text_edit::TextRange; use crate::{ assist_context::{AssistContext, Assists, SourceChangeBuilder}, diff --git a/src/tools/rust-analyzer/crates/ide-assists/src/handlers/destructure_tuple_binding.rs b/src/tools/rust-analyzer/crates/ide-assists/src/handlers/destructure_tuple_binding.rs index 9ecfb83ed53..3f0d5cf152c 100644 --- a/src/tools/rust-analyzer/crates/ide-assists/src/handlers/destructure_tuple_binding.rs +++ b/src/tools/rust-analyzer/crates/ide-assists/src/handlers/destructure_tuple_binding.rs @@ -1,3 +1,4 @@ +use ide_db::text_edit::TextRange; use ide_db::{ assists::{AssistId, AssistKind}, defs::Definition, @@ -8,7 +9,6 @@ use syntax::{ ast::{self, make, AstNode, FieldExpr, HasName, IdentPat}, ted, }; -use text_edit::TextRange; use crate::{ assist_context::{AssistContext, Assists, SourceChangeBuilder}, diff --git a/src/tools/rust-analyzer/crates/ide-assists/src/handlers/remove_dbg.rs b/src/tools/rust-analyzer/crates/ide-assists/src/handlers/remove_dbg.rs index 0e9c463e024..94274f6d17c 100644 --- a/src/tools/rust-analyzer/crates/ide-assists/src/handlers/remove_dbg.rs +++ b/src/tools/rust-analyzer/crates/ide-assists/src/handlers/remove_dbg.rs @@ -41,7 +41,7 @@ pub(crate) fn remove_dbg(acc: &mut Assists, ctx: &AssistContext<'_>) -> Option<( macro_calls.into_iter().filter_map(compute_dbg_replacement).collect::<Vec<_>>(); acc.add( - AssistId("remove_dbg", AssistKind::Refactor), + AssistId("remove_dbg", AssistKind::QuickFix), "Remove dbg!()", replacements.iter().map(|&(range, _)| range).reduce(|acc, range| acc.cover(range))?, |builder| { diff --git a/src/tools/rust-analyzer/crates/ide-assists/src/handlers/remove_unused_imports.rs b/src/tools/rust-analyzer/crates/ide-assists/src/handlers/remove_unused_imports.rs index c6f99d68748..0570b447782 100644 --- a/src/tools/rust-analyzer/crates/ide-assists/src/handlers/remove_unused_imports.rs +++ b/src/tools/rust-analyzer/crates/ide-assists/src/handlers/remove_unused_imports.rs @@ -1,6 +1,7 @@ use std::collections::hash_map::Entry; use hir::{FileRange, HirFileIdExt, InFile, InRealFile, Module, ModuleSource}; +use ide_db::text_edit::TextRange; use ide_db::{ defs::Definition, search::{FileReference, ReferenceCategory, SearchScope}, @@ -10,7 +11,6 @@ use syntax::{ ast::{self, Rename}, AstNode, }; -use text_edit::TextRange; use crate::{AssistContext, AssistId, AssistKind, Assists}; diff --git a/src/tools/rust-analyzer/crates/ide-assists/src/handlers/replace_named_generic_with_impl.rs b/src/tools/rust-analyzer/crates/ide-assists/src/handlers/replace_named_generic_with_impl.rs index 8a6c2937d90..26fd887cc99 100644 --- a/src/tools/rust-analyzer/crates/ide-assists/src/handlers/replace_named_generic_with_impl.rs +++ b/src/tools/rust-analyzer/crates/ide-assists/src/handlers/replace_named_generic_with_impl.rs @@ -1,4 +1,5 @@ use hir::{FileRange, Semantics}; +use ide_db::text_edit::TextRange; use ide_db::{ defs::Definition, search::{SearchScope, UsageSearchResult}, @@ -11,7 +12,6 @@ use syntax::{ }, match_ast, ted, AstNode, }; -use text_edit::TextRange; use crate::{AssistContext, AssistId, AssistKind, Assists}; diff --git a/src/tools/rust-analyzer/crates/ide-assists/src/handlers/unmerge_match_arm.rs b/src/tools/rust-analyzer/crates/ide-assists/src/handlers/unmerge_match_arm.rs index db789cfa334..648bf358b4b 100644 --- a/src/tools/rust-analyzer/crates/ide-assists/src/handlers/unmerge_match_arm.rs +++ b/src/tools/rust-analyzer/crates/ide-assists/src/handlers/unmerge_match_arm.rs @@ -34,6 +34,9 @@ use crate::{AssistContext, AssistId, AssistKind, Assists}; pub(crate) fn unmerge_match_arm(acc: &mut Assists, ctx: &AssistContext<'_>) -> Option<()> { let pipe_token = ctx.find_token_syntax_at_offset(T![|])?; let or_pat = ast::OrPat::cast(pipe_token.parent()?)?.clone_for_update(); + if or_pat.leading_pipe().is_some_and(|it| it == pipe_token) { + return None; + } let match_arm = ast::MatchArm::cast(or_pat.syntax().parent()?)?; let match_arm_body = match_arm.expr()?; diff --git a/src/tools/rust-analyzer/crates/ide-assists/src/lib.rs b/src/tools/rust-analyzer/crates/ide-assists/src/lib.rs index 22620816d50..8aaf5d6fff2 100644 --- a/src/tools/rust-analyzer/crates/ide-assists/src/lib.rs +++ b/src/tools/rust-analyzer/crates/ide-assists/src/lib.rs @@ -301,6 +301,7 @@ mod handlers { inline_call::inline_into_callers, inline_const_as_literal::inline_const_as_literal, inline_local_variable::inline_local_variable, + inline_macro::inline_macro, inline_type_alias::inline_type_alias, inline_type_alias::inline_type_alias_uses, into_to_qualified_from::into_to_qualified_from, @@ -326,6 +327,7 @@ mod handlers { raw_string::add_hash, raw_string::make_usual_string, raw_string::remove_hash, + remove_dbg::remove_dbg, remove_mut::remove_mut, remove_unused_imports::remove_unused_imports, remove_unused_param::remove_unused_param, @@ -381,9 +383,6 @@ mod handlers { generate_getter_or_setter::generate_setter, generate_delegate_methods::generate_delegate_methods, generate_deref::generate_deref, - // - remove_dbg::remove_dbg, - inline_macro::inline_macro, // Are you sure you want to add new assist here, and not to the // sorted list above? ] diff --git a/src/tools/rust-analyzer/crates/ide-completion/Cargo.toml b/src/tools/rust-analyzer/crates/ide-completion/Cargo.toml index 614465b4d06..1bef82af5ac 100644 --- a/src/tools/rust-analyzer/crates/ide-completion/Cargo.toml +++ b/src/tools/rust-analyzer/crates/ide-completion/Cargo.toml @@ -25,7 +25,6 @@ base-db.workspace = true ide-db.workspace = true stdx.workspace = true syntax.workspace = true -text-edit.workspace = true # completions crate should depend only on the top-level `hir` package. if you need # something from some `hir-xxx` subpackage, reexport the API via `hir`. hir.workspace = true diff --git a/src/tools/rust-analyzer/crates/ide-completion/src/completions/item_list/trait_impl.rs b/src/tools/rust-analyzer/crates/ide-completion/src/completions/item_list/trait_impl.rs index 672e1796d1e..c38a8ef29bb 100644 --- a/src/tools/rust-analyzer/crates/ide-completion/src/completions/item_list/trait_impl.rs +++ b/src/tools/rust-analyzer/crates/ide-completion/src/completions/item_list/trait_impl.rs @@ -32,6 +32,7 @@ //! ``` use hir::{db::ExpandDatabase, HasAttrs, MacroFileId, Name}; +use ide_db::text_edit::TextEdit; use ide_db::{ documentation::HasDocs, path_transform::PathTransform, syntax_helpers::prettify_macro_expansion, traits::get_missing_assoc_items, SymbolKind, @@ -40,7 +41,6 @@ use syntax::{ ast::{self, edit_in_place::AttrsOwnerEdit, make, HasGenericArgs, HasTypeBounds}, format_smolstr, ted, AstNode, SmolStr, SyntaxElement, SyntaxKind, TextRange, ToSmolStr, T, }; -use text_edit::TextEdit; use crate::{ context::PathCompletionCtx, CompletionContext, CompletionItem, CompletionItemKind, diff --git a/src/tools/rust-analyzer/crates/ide-completion/src/completions/mod_.rs b/src/tools/rust-analyzer/crates/ide-completion/src/completions/mod_.rs index 05e2892fdc8..f12f011a6bd 100644 --- a/src/tools/rust-analyzer/crates/ide-completion/src/completions/mod_.rs +++ b/src/tools/rust-analyzer/crates/ide-completion/src/completions/mod_.rs @@ -7,7 +7,6 @@ use ide_db::{ base_db::{SourceRootDatabase, VfsPath}, FxHashSet, RootDatabase, SymbolKind, }; -use stdx::IsNoneOr; use syntax::{ast, AstNode, SyntaxKind, ToSmolStr}; use crate::{context::CompletionContext, CompletionItem, Completions}; @@ -66,7 +65,7 @@ pub(crate) fn complete_mod( .iter() .filter(|&submodule_candidate_file| submodule_candidate_file != module_definition_file) .filter(|&submodule_candidate_file| { - IsNoneOr::is_none_or(module_declaration_file, |it| it != submodule_candidate_file) + module_declaration_file.is_none_or(|it| it != submodule_candidate_file) }) .filter_map(|submodule_file| { let submodule_path = source_root.path_for_file(&submodule_file)?; diff --git a/src/tools/rust-analyzer/crates/ide-completion/src/completions/postfix.rs b/src/tools/rust-analyzer/crates/ide-completion/src/completions/postfix.rs index d3579fd8cc6..495f82da866 100644 --- a/src/tools/rust-analyzer/crates/ide-completion/src/completions/postfix.rs +++ b/src/tools/rust-analyzer/crates/ide-completion/src/completions/postfix.rs @@ -3,6 +3,7 @@ mod format_like; use hir::ItemInNs; +use ide_db::text_edit::TextEdit; use ide_db::{ documentation::{Documentation, HasDocs}, imports::insert_use::ImportScope, @@ -15,7 +16,6 @@ use syntax::{ SyntaxKind::{BLOCK_EXPR, EXPR_STMT, FOR_EXPR, IF_EXPR, LOOP_EXPR, STMT_LIST, WHILE_EXPR}, TextRange, TextSize, }; -use text_edit::TextEdit; use crate::{ completions::postfix::format_like::add_format_like_completions, diff --git a/src/tools/rust-analyzer/crates/ide-completion/src/context.rs b/src/tools/rust-analyzer/crates/ide-completion/src/context.rs index 0e1302ff2ef..efbee39a2d4 100644 --- a/src/tools/rust-analyzer/crates/ide-completion/src/context.rs +++ b/src/tools/rust-analyzer/crates/ide-completion/src/context.rs @@ -20,7 +20,6 @@ use syntax::{ SyntaxKind::{self, *}, SyntaxToken, TextRange, TextSize, T, }; -use text_edit::Indel; use crate::{ context::analysis::{expand_and_analyze, AnalysisResult}, @@ -684,8 +683,7 @@ impl<'a> CompletionContext<'a> { // actual completion. let file_with_fake_ident = { let parse = db.parse(file_id); - let edit = Indel::insert(offset, COMPLETION_MARKER.to_owned()); - parse.reparse(&edit, file_id.edition()).tree() + parse.reparse(TextRange::empty(offset), COMPLETION_MARKER, file_id.edition()).tree() }; // always pick the token to the immediate left of the cursor, as that is what we are actually diff --git a/src/tools/rust-analyzer/crates/ide-completion/src/item.rs b/src/tools/rust-analyzer/crates/ide-completion/src/item.rs index 8c97ebd5500..52f6bedaaa9 100644 --- a/src/tools/rust-analyzer/crates/ide-completion/src/item.rs +++ b/src/tools/rust-analyzer/crates/ide-completion/src/item.rs @@ -3,6 +3,7 @@ use std::{fmt, mem}; use hir::Mutability; +use ide_db::text_edit::TextEdit; use ide_db::{ documentation::Documentation, imports::import_assets::LocatedImport, RootDatabase, SnippetCap, SymbolKind, @@ -11,7 +12,6 @@ use itertools::Itertools; use smallvec::SmallVec; use stdx::{impl_from, never}; use syntax::{format_smolstr, Edition, SmolStr, TextRange, TextSize}; -use text_edit::TextEdit; use crate::{ context::{CompletionContext, PathCompletionCtx}, @@ -426,7 +426,7 @@ impl CompletionItem { self.lookup.as_str() } - pub fn ref_match(&self) -> Option<(String, text_edit::Indel, CompletionRelevance)> { + pub fn ref_match(&self) -> Option<(String, ide_db::text_edit::Indel, CompletionRelevance)> { // Relevance of the ref match should be the same as the original // match, but with exact type match set because self.ref_match // is only set if there is an exact type match. @@ -436,7 +436,10 @@ impl CompletionItem { self.ref_match.map(|(mutability, offset)| { ( format!("&{}{}", mutability.as_keyword_for_ref(), self.label), - text_edit::Indel::insert(offset, format!("&{}", mutability.as_keyword_for_ref())), + ide_db::text_edit::Indel::insert( + offset, + format!("&{}", mutability.as_keyword_for_ref()), + ), relevance, ) }) diff --git a/src/tools/rust-analyzer/crates/ide-completion/src/lib.rs b/src/tools/rust-analyzer/crates/ide-completion/src/lib.rs index a78976d3fd8..dfee01b187e 100644 --- a/src/tools/rust-analyzer/crates/ide-completion/src/lib.rs +++ b/src/tools/rust-analyzer/crates/ide-completion/src/lib.rs @@ -10,16 +10,17 @@ mod snippet; #[cfg(test)] mod tests; +use ide_db::text_edit::TextEdit; use ide_db::{ helpers::mod_path_to_ast, imports::{ import_assets::NameToImport, insert_use::{self, ImportScope}, }, - items_locator, FilePosition, RootDatabase, + items_locator, + syntax_helpers::tree_diff::diff, + FilePosition, RootDatabase, }; -use syntax::algo; -use text_edit::TextEdit; use crate::{ completions::Completions, @@ -297,6 +298,6 @@ pub fn resolve_completion_edits( } }); - algo::diff(scope.as_syntax_node(), new_ast.as_syntax_node()).into_text_edit(&mut import_insert); + diff(scope.as_syntax_node(), new_ast.as_syntax_node()).into_text_edit(&mut import_insert); Some(vec![import_insert.finish()]) } diff --git a/src/tools/rust-analyzer/crates/ide-completion/src/render.rs b/src/tools/rust-analyzer/crates/ide-completion/src/render.rs index 4dd171142f9..ec3c2fe3556 100644 --- a/src/tools/rust-analyzer/crates/ide-completion/src/render.rs +++ b/src/tools/rust-analyzer/crates/ide-completion/src/render.rs @@ -11,6 +11,7 @@ pub(crate) mod union_literal; pub(crate) mod variant; use hir::{sym, AsAssocItem, HasAttrs, HirDisplay, ModuleDef, ScopeDef, Type}; +use ide_db::text_edit::TextEdit; use ide_db::{ documentation::{Documentation, HasDocs}, helpers::item_name, @@ -18,7 +19,6 @@ use ide_db::{ RootDatabase, SnippetCap, SymbolKind, }; use syntax::{ast, format_smolstr, AstNode, Edition, SmolStr, SyntaxKind, TextRange, ToSmolStr}; -use text_edit::TextEdit; use crate::{ context::{DotAccess, DotAccessKind, PathCompletionCtx, PathKind, PatternContext}, diff --git a/src/tools/rust-analyzer/crates/ide-completion/src/tests/attribute.rs b/src/tools/rust-analyzer/crates/ide-completion/src/tests/attribute.rs index 1bbe097cc6c..45679355b42 100644 --- a/src/tools/rust-analyzer/crates/ide-completion/src/tests/attribute.rs +++ b/src/tools/rust-analyzer/crates/ide-completion/src/tests/attribute.rs @@ -663,6 +663,7 @@ mod cfg { ba dbg ba opt_level ba test + ba true "#]], ); check( @@ -674,6 +675,7 @@ mod cfg { ba dbg ba opt_level ba test + ba true "#]], ); } diff --git a/src/tools/rust-analyzer/crates/ide-db/Cargo.toml b/src/tools/rust-analyzer/crates/ide-db/Cargo.toml index c078188d6d3..17f0e69bde4 100644 --- a/src/tools/rust-analyzer/crates/ide-db/Cargo.toml +++ b/src/tools/rust-analyzer/crates/ide-db/Cargo.toml @@ -35,7 +35,6 @@ parser.workspace = true profile.workspace = true stdx.workspace = true syntax.workspace = true -text-edit.workspace = true span.workspace = true # ide should depend only on the top-level `hir` package. if you need # something from some `hir-xxx` subpackage, reexport the API via `hir`. diff --git a/src/tools/rust-analyzer/crates/ide-db/src/apply_change.rs b/src/tools/rust-analyzer/crates/ide-db/src/apply_change.rs index 7474d7bc54d..35e3a8d9bf7 100644 --- a/src/tools/rust-analyzer/crates/ide-db/src/apply_change.rs +++ b/src/tools/rust-analyzer/crates/ide-db/src/apply_change.rs @@ -100,16 +100,19 @@ impl RootDatabase { hir::db::ConstEvalQuery hir::db::ConstEvalStaticQuery hir::db::ConstParamTyQuery + hir::db::DynCompatibilityOfTraitQuery hir::db::FieldTypesQuery hir::db::FnDefDatumQuery hir::db::FnDefVarianceQuery hir::db::GenericDefaultsQuery hir::db::GenericPredicatesForParamQuery hir::db::GenericPredicatesQuery + hir::db::GenericPredicatesWithoutParentQuery hir::db::ImplDatumQuery hir::db::ImplSelfTyQuery hir::db::ImplTraitQuery hir::db::IncoherentInherentImplCratesQuery + hir::db::InferQuery hir::db::InherentImplsInBlockQuery hir::db::InherentImplsInCrateQuery hir::db::InternCallableDefQuery @@ -119,7 +122,12 @@ impl RootDatabase { hir::db::InternLifetimeParamIdQuery hir::db::InternTypeOrConstParamIdQuery hir::db::LayoutOfAdtQuery + hir::db::LayoutOfTyQuery + hir::db::LookupImplMethodQuery + hir::db::MirBodyForClosureQuery hir::db::MirBodyQuery + hir::db::MonomorphizedMirBodyForClosureQuery + hir::db::MonomorphizedMirBodyQuery hir::db::ProgramClausesForChalkEnvQuery hir::db::ReturnTypeImplTraitsQuery hir::db::TargetDataLayoutQuery @@ -128,13 +136,16 @@ impl RootDatabase { hir::db::TraitImplsInBlockQuery hir::db::TraitImplsInCrateQuery hir::db::TraitImplsInDepsQuery + hir::db::TraitSolveQuery hir::db::TyQuery + hir::db::TypeAliasImplTraitsQuery hir::db::ValueTyQuery // DefDatabase hir::db::AttrsQuery hir::db::BlockDefMapQuery hir::db::BlockItemTreeQuery + hir::db::BlockItemTreeWithSourceMapQuery hir::db::BodyQuery hir::db::BodyWithSourceMapQuery hir::db::ConstDataQuery @@ -145,17 +156,21 @@ impl RootDatabase { hir::db::CrateSupportsNoStdQuery hir::db::EnumDataQuery hir::db::EnumVariantDataWithDiagnosticsQuery + hir::db::ExpandProcAttrMacrosQuery hir::db::ExprScopesQuery hir::db::ExternCrateDeclDataQuery hir::db::FieldVisibilitiesQuery hir::db::FieldsAttrsQuery hir::db::FieldsAttrsSourceMapQuery hir::db::FileItemTreeQuery + hir::db::FileItemTreeWithSourceMapQuery hir::db::FunctionDataQuery hir::db::FunctionVisibilityQuery hir::db::GenericParamsQuery + hir::db::GenericParamsWithSourceMapQuery hir::db::ImplDataWithDiagnosticsQuery hir::db::ImportMapQuery + hir::db::IncludeMacroInvocQuery hir::db::InternAnonymousConstQuery hir::db::InternBlockQuery hir::db::InternConstQuery @@ -177,7 +192,9 @@ impl RootDatabase { hir::db::InternUseQuery hir::db::LangItemQuery hir::db::Macro2DataQuery + hir::db::MacroDefQuery hir::db::MacroRulesDataQuery + hir::db::NotableTraitsInDepsQuery hir::db::ProcMacroDataQuery hir::db::StaticDataQuery hir::db::StructDataWithDiagnosticsQuery @@ -212,6 +229,7 @@ impl RootDatabase { hir::db::MacroArgQuery hir::db::ParseMacroExpansionErrorQuery hir::db::ParseMacroExpansionQuery + hir::db::ProcMacroSpanQuery hir::db::ProcMacrosQuery hir::db::RealSpanMapQuery @@ -220,7 +238,9 @@ impl RootDatabase { // SourceDatabase base_db::ParseQuery + base_db::ParseErrorsQuery base_db::CrateGraphQuery + base_db::CrateWorkspaceDataQuery // SourceDatabaseExt base_db::FileTextQuery diff --git a/src/tools/rust-analyzer/crates/ide-db/src/defs.rs b/src/tools/rust-analyzer/crates/ide-db/src/defs.rs index 099f26eba78..fdac4dd2efb 100644 --- a/src/tools/rust-analyzer/crates/ide-db/src/defs.rs +++ b/src/tools/rust-analyzer/crates/ide-db/src/defs.rs @@ -5,14 +5,17 @@ // FIXME: this badly needs rename/rewrite (matklad, 2020-02-06). +use crate::documentation::{Documentation, HasDocs}; +use crate::famous_defs::FamousDefs; +use crate::RootDatabase; use arrayvec::ArrayVec; use either::Either; use hir::{ Adt, AsAssocItem, AsExternAssocItem, AssocItem, AttributeTemplate, BuiltinAttr, BuiltinType, Const, Crate, DefWithBody, DeriveHelper, DocLinkDef, ExternAssocItem, ExternCrateDecl, Field, Function, GenericParam, HasVisibility, HirDisplay, Impl, InlineAsmOperand, Label, Local, Macro, - Module, ModuleDef, Name, PathResolution, Semantics, Static, StaticLifetime, ToolModule, Trait, - TraitAlias, TupleField, TypeAlias, Variant, VariantDef, Visibility, + Module, ModuleDef, Name, PathResolution, Semantics, Static, StaticLifetime, Struct, ToolModule, + Trait, TraitAlias, TupleField, TypeAlias, Variant, VariantDef, Visibility, }; use span::Edition; use stdx::{format_to, impl_from}; @@ -21,10 +24,6 @@ use syntax::{ match_ast, SyntaxKind, SyntaxNode, SyntaxToken, }; -use crate::documentation::{Documentation, HasDocs}; -use crate::famous_defs::FamousDefs; -use crate::RootDatabase; - // FIXME: a more precise name would probably be `Symbol`? #[derive(Debug, PartialEq, Eq, Copy, Clone, Hash)] pub enum Definition { @@ -179,7 +178,19 @@ impl Definition { Definition::Static(it) => it.docs(db), Definition::Trait(it) => it.docs(db), Definition::TraitAlias(it) => it.docs(db), - Definition::TypeAlias(it) => it.docs(db), + Definition::TypeAlias(it) => { + it.docs(db).or_else(|| { + // docs are missing, try to fall back to the docs of the aliased item. + let adt = it.ty(db).as_adt()?; + let docs = adt.docs(db)?; + let docs = format!( + "*This is the documentation for* `{}`\n\n{}", + adt.display(db, edition), + docs.as_str() + ); + Some(Documentation::new(docs)) + }) + } Definition::BuiltinType(it) => { famous_defs.and_then(|fd| { // std exposes prim_{} modules with docstrings on the root to document the builtins @@ -319,6 +330,8 @@ impl IdentClass { .map(IdentClass::NameClass) .or_else(|| NameRefClass::classify_lifetime(sema, &lifetime).map(IdentClass::NameRefClass)) }, + ast::RangePat(range_pat) => OperatorClass::classify_range_pat(sema, &range_pat).map(IdentClass::Operator), + ast::RangeExpr(range_expr) => OperatorClass::classify_range_expr(sema, &range_expr).map(IdentClass::Operator), ast::AwaitExpr(await_expr) => OperatorClass::classify_await(sema, &await_expr).map(IdentClass::Operator), ast::BinExpr(bin_expr) => OperatorClass::classify_bin(sema, &bin_expr).map(IdentClass::Operator), ast::IndexExpr(index_expr) => OperatorClass::classify_index(sema, &index_expr).map(IdentClass::Operator), @@ -372,6 +385,9 @@ impl IdentClass { | OperatorClass::Index(func) | OperatorClass::Try(func), ) => res.push(Definition::Function(func)), + IdentClass::Operator(OperatorClass::Range(struct0)) => { + res.push(Definition::Adt(Adt::Struct(struct0))) + } } res } @@ -546,6 +562,7 @@ impl NameClass { #[derive(Debug)] pub enum OperatorClass { + Range(Struct), Await(Function), Prefix(Function), Index(Function), @@ -554,6 +571,20 @@ pub enum OperatorClass { } impl OperatorClass { + pub fn classify_range_pat( + sema: &Semantics<'_, RootDatabase>, + range_pat: &ast::RangePat, + ) -> Option<OperatorClass> { + sema.resolve_range_pat(range_pat).map(OperatorClass::Range) + } + + pub fn classify_range_expr( + sema: &Semantics<'_, RootDatabase>, + range_expr: &ast::RangeExpr, + ) -> Option<OperatorClass> { + sema.resolve_range_expr(range_expr).map(OperatorClass::Range) + } + pub fn classify_await( sema: &Semantics<'_, RootDatabase>, await_expr: &ast::AwaitExpr, diff --git a/src/tools/rust-analyzer/crates/ide-db/src/documentation.rs b/src/tools/rust-analyzer/crates/ide-db/src/documentation.rs index 5e443badf9e..b52a325790b 100644 --- a/src/tools/rust-analyzer/crates/ide-db/src/documentation.rs +++ b/src/tools/rust-analyzer/crates/ide-db/src/documentation.rs @@ -5,11 +5,11 @@ use hir::{ resolve_doc_path_on, sym, AttrId, AttrSourceMap, AttrsWithOwner, HasAttrs, InFile, }; use itertools::Itertools; +use span::{TextRange, TextSize}; use syntax::{ ast::{self, IsString}, AstToken, }; -use text_edit::{TextRange, TextSize}; /// Holds documentation #[derive(Debug, Clone, PartialEq, Eq, Hash)] diff --git a/src/tools/rust-analyzer/crates/ide-db/src/lib.rs b/src/tools/rust-analyzer/crates/ide-db/src/lib.rs index aed093f0ebf..81260c3e080 100644 --- a/src/tools/rust-analyzer/crates/ide-db/src/lib.rs +++ b/src/tools/rust-analyzer/crates/ide-db/src/lib.rs @@ -19,6 +19,7 @@ pub mod rust_doc; pub mod search; pub mod source_change; pub mod symbol_index; +pub mod text_edit; pub mod traits; pub mod ty_filter; pub mod use_trivial_constructor; @@ -36,6 +37,7 @@ pub mod generated { pub mod syntax_helpers { pub mod format_string; pub mod format_string_exprs; + pub mod tree_diff; pub use hir::prettify_macro_expansion; pub mod node_ext; pub mod suggest_name; @@ -293,3 +295,35 @@ impl SnippetCap { } } } + +pub struct Ranker<'a> { + pub kind: parser::SyntaxKind, + pub text: &'a str, + pub ident_kind: bool, +} + +impl<'a> Ranker<'a> { + pub const MAX_RANK: usize = 0b1110; + + pub fn from_token(token: &'a syntax::SyntaxToken) -> Self { + let kind = token.kind(); + Ranker { kind, text: token.text(), ident_kind: kind.is_any_identifier() } + } + + /// A utility function that ranks a token again a given kind and text, returning a number that + /// represents how close the token is to the given kind and text. + pub fn rank_token(&self, tok: &syntax::SyntaxToken) -> usize { + let tok_kind = tok.kind(); + + let exact_same_kind = tok_kind == self.kind; + let both_idents = exact_same_kind || (tok_kind.is_any_identifier() && self.ident_kind); + let same_text = tok.text() == self.text; + // anything that mapped into a token tree has likely no semantic information + let no_tt_parent = + tok.parent().map_or(false, |it| it.kind() != parser::SyntaxKind::TOKEN_TREE); + (both_idents as usize) + | ((exact_same_kind as usize) << 1) + | ((same_text as usize) << 2) + | ((no_tt_parent as usize) << 3) + } +} diff --git a/src/tools/rust-analyzer/crates/ide-db/src/rename.rs b/src/tools/rust-analyzer/crates/ide-db/src/rename.rs index f1404ed9f22..1d1679c3ff8 100644 --- a/src/tools/rust-analyzer/crates/ide-db/src/rename.rs +++ b/src/tools/rust-analyzer/crates/ide-db/src/rename.rs @@ -22,6 +22,7 @@ //! Our current behavior is ¯\_(ツ)_/¯. use std::fmt; +use crate::text_edit::{TextEdit, TextEditBuilder}; use base_db::AnchoredPathBuf; use either::Either; use hir::{FieldSource, FileRange, HirFileIdExt, InFile, ModuleSource, Semantics}; @@ -32,7 +33,6 @@ use syntax::{ utils::is_raw_identifier, AstNode, SyntaxKind, TextRange, T, }; -use text_edit::{TextEdit, TextEditBuilder}; use crate::{ defs::Definition, diff --git a/src/tools/rust-analyzer/crates/ide-db/src/source_change.rs b/src/tools/rust-analyzer/crates/ide-db/src/source_change.rs index 73073e92f78..27ff91dc19d 100644 --- a/src/tools/rust-analyzer/crates/ide-db/src/source_change.rs +++ b/src/tools/rust-analyzer/crates/ide-db/src/source_change.rs @@ -5,7 +5,8 @@ use std::{collections::hash_map::Entry, iter, mem}; -use crate::{assists::Command, SnippetCap}; +use crate::text_edit::{TextEdit, TextEditBuilder}; +use crate::{assists::Command, syntax_helpers::tree_diff::diff, SnippetCap}; use base_db::AnchoredPathBuf; use itertools::Itertools; use nohash_hasher::IntMap; @@ -13,11 +14,9 @@ use rustc_hash::FxHashMap; use span::FileId; use stdx::never; use syntax::{ - algo, syntax_editor::{SyntaxAnnotation, SyntaxEditor}, AstNode, SyntaxElement, SyntaxNode, SyntaxNodePtr, SyntaxToken, TextRange, TextSize, }; -use text_edit::{TextEdit, TextEditBuilder}; #[derive(Default, Debug, Clone)] pub struct SourceChange { @@ -315,7 +314,7 @@ impl SourceChangeBuilder { } let mut edit = TextEdit::builder(); - algo::diff(edit_result.old_root(), edit_result.new_root()).into_text_edit(&mut edit); + diff(edit_result.old_root(), edit_result.new_root()).into_text_edit(&mut edit); let edit = edit.finish(); let snippet_edit = @@ -334,7 +333,7 @@ impl SourceChangeBuilder { }); if let Some(tm) = self.mutated_tree.take() { - algo::diff(&tm.immutable, &tm.mutable_clone).into_text_edit(&mut self.edit); + diff(&tm.immutable, &tm.mutable_clone).into_text_edit(&mut self.edit); } let edit = mem::take(&mut self.edit).finish(); @@ -373,7 +372,7 @@ impl SourceChangeBuilder { self.edit.replace(range, replace_with.into()) } pub fn replace_ast<N: AstNode>(&mut self, old: N, new: N) { - algo::diff(old.syntax(), new.syntax()).into_text_edit(&mut self.edit) + diff(old.syntax(), new.syntax()).into_text_edit(&mut self.edit) } pub fn create_file(&mut self, dst: AnchoredPathBuf, content: impl Into<String>) { let file_system_edit = FileSystemEdit::CreateFile { dst, initial_contents: content.into() }; diff --git a/src/tools/rust-analyzer/crates/ide-db/src/syntax_helpers/tree_diff.rs b/src/tools/rust-analyzer/crates/ide-db/src/syntax_helpers/tree_diff.rs new file mode 100644 index 00000000000..02e24c47761 --- /dev/null +++ b/src/tools/rust-analyzer/crates/ide-db/src/syntax_helpers/tree_diff.rs @@ -0,0 +1,559 @@ +//! Basic tree diffing functionality. +use rustc_hash::FxHashMap; +use syntax::{NodeOrToken, SyntaxElement, SyntaxNode}; + +use crate::{text_edit::TextEditBuilder, FxIndexMap}; + +#[derive(Debug, Hash, PartialEq, Eq)] +enum TreeDiffInsertPos { + After(SyntaxElement), + AsFirstChild(SyntaxElement), +} + +#[derive(Debug)] +pub struct TreeDiff { + replacements: FxHashMap<SyntaxElement, SyntaxElement>, + deletions: Vec<SyntaxElement>, + // the vec as well as the indexmap are both here to preserve order + insertions: FxIndexMap<TreeDiffInsertPos, Vec<SyntaxElement>>, +} + +impl TreeDiff { + pub fn into_text_edit(&self, builder: &mut TextEditBuilder) { + let _p = tracing::info_span!("into_text_edit").entered(); + + for (anchor, to) in &self.insertions { + let offset = match anchor { + TreeDiffInsertPos::After(it) => it.text_range().end(), + TreeDiffInsertPos::AsFirstChild(it) => it.text_range().start(), + }; + to.iter().for_each(|to| builder.insert(offset, to.to_string())); + } + for (from, to) in &self.replacements { + builder.replace(from.text_range(), to.to_string()); + } + for text_range in self.deletions.iter().map(SyntaxElement::text_range) { + builder.delete(text_range); + } + } + + pub fn is_empty(&self) -> bool { + self.replacements.is_empty() && self.deletions.is_empty() && self.insertions.is_empty() + } +} + +/// Finds a (potentially minimal) diff, which, applied to `from`, will result in `to`. +/// +/// Specifically, returns a structure that consists of a replacements, insertions and deletions +/// such that applying this map on `from` will result in `to`. +/// +/// This function tries to find a fine-grained diff. +pub fn diff(from: &SyntaxNode, to: &SyntaxNode) -> TreeDiff { + let _p = tracing::info_span!("diff").entered(); + + let mut diff = TreeDiff { + replacements: FxHashMap::default(), + insertions: FxIndexMap::default(), + deletions: Vec::new(), + }; + let (from, to) = (from.clone().into(), to.clone().into()); + + if !syntax_element_eq(&from, &to) { + go(&mut diff, from, to); + } + return diff; + + fn syntax_element_eq(lhs: &SyntaxElement, rhs: &SyntaxElement) -> bool { + lhs.kind() == rhs.kind() + && lhs.text_range().len() == rhs.text_range().len() + && match (&lhs, &rhs) { + (NodeOrToken::Node(lhs), NodeOrToken::Node(rhs)) => { + lhs == rhs || lhs.text() == rhs.text() + } + (NodeOrToken::Token(lhs), NodeOrToken::Token(rhs)) => lhs.text() == rhs.text(), + _ => false, + } + } + + // FIXME: this is horribly inefficient. I bet there's a cool algorithm to diff trees properly. + fn go(diff: &mut TreeDiff, lhs: SyntaxElement, rhs: SyntaxElement) { + let (lhs, rhs) = match lhs.as_node().zip(rhs.as_node()) { + Some((lhs, rhs)) => (lhs, rhs), + _ => { + cov_mark::hit!(diff_node_token_replace); + diff.replacements.insert(lhs, rhs); + return; + } + }; + + let mut look_ahead_scratch = Vec::default(); + + let mut rhs_children = rhs.children_with_tokens(); + let mut lhs_children = lhs.children_with_tokens(); + let mut last_lhs = None; + loop { + let lhs_child = lhs_children.next(); + match (lhs_child.clone(), rhs_children.next()) { + (None, None) => break, + (None, Some(element)) => { + let insert_pos = match last_lhs.clone() { + Some(prev) => { + cov_mark::hit!(diff_insert); + TreeDiffInsertPos::After(prev) + } + // first iteration, insert into out parent as the first child + None => { + cov_mark::hit!(diff_insert_as_first_child); + TreeDiffInsertPos::AsFirstChild(lhs.clone().into()) + } + }; + diff.insertions.entry(insert_pos).or_default().push(element); + } + (Some(element), None) => { + cov_mark::hit!(diff_delete); + diff.deletions.push(element); + } + (Some(ref lhs_ele), Some(ref rhs_ele)) if syntax_element_eq(lhs_ele, rhs_ele) => {} + (Some(lhs_ele), Some(rhs_ele)) => { + // nodes differ, look for lhs_ele in rhs, if its found we can mark everything up + // until that element as insertions. This is important to keep the diff minimal + // in regards to insertions that have been actually done, this is important for + // use insertions as we do not want to replace the entire module node. + look_ahead_scratch.push(rhs_ele.clone()); + let mut rhs_children_clone = rhs_children.clone(); + let mut insert = false; + for rhs_child in &mut rhs_children_clone { + if syntax_element_eq(&lhs_ele, &rhs_child) { + cov_mark::hit!(diff_insertions); + insert = true; + break; + } + look_ahead_scratch.push(rhs_child); + } + let drain = look_ahead_scratch.drain(..); + if insert { + let insert_pos = if let Some(prev) = last_lhs.clone().filter(|_| insert) { + TreeDiffInsertPos::After(prev) + } else { + cov_mark::hit!(insert_first_child); + TreeDiffInsertPos::AsFirstChild(lhs.clone().into()) + }; + + diff.insertions.entry(insert_pos).or_default().extend(drain); + rhs_children = rhs_children_clone; + } else { + go(diff, lhs_ele, rhs_ele); + } + } + } + last_lhs = lhs_child.or(last_lhs); + } + } +} + +#[cfg(test)] +mod tests { + use expect_test::{expect, Expect}; + use itertools::Itertools; + use parser::{Edition, SyntaxKind}; + use syntax::{AstNode, SourceFile, SyntaxElement}; + + use crate::text_edit::TextEdit; + + #[test] + fn replace_node_token() { + cov_mark::check!(diff_node_token_replace); + check_diff( + r#"use node;"#, + r#"ident"#, + expect![[r#" + insertions: + + + + replacements: + + Line 0: Token(USE_KW@0..3 "use") -> ident + + deletions: + + Line 1: " " + Line 1: node + Line 1: ; + "#]], + ); + } + + #[test] + fn replace_parent() { + cov_mark::check!(diff_insert_as_first_child); + check_diff( + r#""#, + r#"use foo::bar;"#, + expect![[r#" + insertions: + + Line 0: AsFirstChild(Node(SOURCE_FILE@0..0)) + -> use foo::bar; + + replacements: + + + + deletions: + + + "#]], + ); + } + + #[test] + fn insert_last() { + cov_mark::check!(diff_insert); + check_diff( + r#" +use foo; +use bar;"#, + r#" +use foo; +use bar; +use baz;"#, + expect![[r#" + insertions: + + Line 2: After(Node(USE@10..18)) + -> "\n" + -> use baz; + + replacements: + + + + deletions: + + + "#]], + ); + } + + #[test] + fn insert_middle() { + check_diff( + r#" +use foo; +use baz;"#, + r#" +use foo; +use bar; +use baz;"#, + expect![[r#" + insertions: + + Line 2: After(Token(WHITESPACE@9..10 "\n")) + -> use bar; + -> "\n" + + replacements: + + + + deletions: + + + "#]], + ) + } + + #[test] + fn insert_first() { + check_diff( + r#" +use bar; +use baz;"#, + r#" +use foo; +use bar; +use baz;"#, + expect![[r#" + insertions: + + Line 0: After(Token(WHITESPACE@0..1 "\n")) + -> use foo; + -> "\n" + + replacements: + + + + deletions: + + + "#]], + ) + } + + #[test] + fn first_child_insertion() { + cov_mark::check!(insert_first_child); + check_diff( + r#"fn main() { + stdi + }"#, + r#"use foo::bar; + + fn main() { + stdi + }"#, + expect![[r#" + insertions: + + Line 0: AsFirstChild(Node(SOURCE_FILE@0..30)) + -> use foo::bar; + -> "\n\n " + + replacements: + + + + deletions: + + + "#]], + ); + } + + #[test] + fn delete_last() { + cov_mark::check!(diff_delete); + check_diff( + r#"use foo; + use bar;"#, + r#"use foo;"#, + expect![[r#" + insertions: + + + + replacements: + + + + deletions: + + Line 1: "\n " + Line 2: use bar; + "#]], + ); + } + + #[test] + fn delete_middle() { + cov_mark::check!(diff_insertions); + check_diff( + r#" +use expect_test::{expect, Expect}; +use text_edit::TextEdit; + +use crate::AstNode; +"#, + r#" +use expect_test::{expect, Expect}; + +use crate::AstNode; +"#, + expect![[r#" + insertions: + + Line 1: After(Node(USE@1..35)) + -> "\n\n" + -> use crate::AstNode; + + replacements: + + + + deletions: + + Line 2: use text_edit::TextEdit; + Line 3: "\n\n" + Line 4: use crate::AstNode; + Line 5: "\n" + "#]], + ) + } + + #[test] + fn delete_first() { + check_diff( + r#" +use text_edit::TextEdit; + +use crate::AstNode; +"#, + r#" +use crate::AstNode; +"#, + expect![[r#" + insertions: + + + + replacements: + + Line 2: Token(IDENT@5..14 "text_edit") -> crate + Line 2: Token(IDENT@16..24 "TextEdit") -> AstNode + Line 2: Token(WHITESPACE@25..27 "\n\n") -> "\n" + + deletions: + + Line 3: use crate::AstNode; + Line 4: "\n" + "#]], + ) + } + + #[test] + fn merge_use() { + check_diff( + r#" +use std::{ + fmt, + hash::BuildHasherDefault, + ops::{self, RangeInclusive}, +}; +"#, + r#" +use std::fmt; +use std::hash::BuildHasherDefault; +use std::ops::{self, RangeInclusive}; +"#, + expect![[r#" + insertions: + + Line 2: After(Node(PATH_SEGMENT@5..8)) + -> :: + -> fmt + Line 6: After(Token(WHITESPACE@86..87 "\n")) + -> use std::hash::BuildHasherDefault; + -> "\n" + -> use std::ops::{self, RangeInclusive}; + -> "\n" + + replacements: + + Line 2: Token(IDENT@5..8 "std") -> std + + deletions: + + Line 2: :: + Line 2: { + fmt, + hash::BuildHasherDefault, + ops::{self, RangeInclusive}, + } + "#]], + ) + } + + #[test] + fn early_return_assist() { + check_diff( + r#" +fn main() { + if let Ok(x) = Err(92) { + foo(x); + } +} + "#, + r#" +fn main() { + let x = match Err(92) { + Ok(it) => it, + _ => return, + }; + foo(x); +} + "#, + expect![[r#" + insertions: + + Line 3: After(Node(BLOCK_EXPR@40..63)) + -> " " + -> match Err(92) { + Ok(it) => it, + _ => return, + } + -> ; + Line 3: After(Node(IF_EXPR@17..63)) + -> "\n " + -> foo(x); + + replacements: + + Line 3: Token(IF_KW@17..19 "if") -> let + Line 3: Token(LET_KW@20..23 "let") -> x + Line 3: Node(BLOCK_EXPR@40..63) -> = + + deletions: + + Line 3: " " + Line 3: Ok(x) + Line 3: " " + Line 3: = + Line 3: " " + Line 3: Err(92) + "#]], + ) + } + + fn check_diff(from: &str, to: &str, expected_diff: Expect) { + let from_node = SourceFile::parse(from, Edition::CURRENT).tree().syntax().clone(); + let to_node = SourceFile::parse(to, Edition::CURRENT).tree().syntax().clone(); + let diff = super::diff(&from_node, &to_node); + + let line_number = + |syn: &SyntaxElement| from[..syn.text_range().start().into()].lines().count(); + + let fmt_syntax = |syn: &SyntaxElement| match syn.kind() { + SyntaxKind::WHITESPACE => format!("{:?}", syn.to_string()), + _ => format!("{syn}"), + }; + + let insertions = + diff.insertions.iter().format_with("\n", |(k, v), f| -> Result<(), std::fmt::Error> { + f(&format!( + "Line {}: {:?}\n-> {}", + line_number(match k { + super::TreeDiffInsertPos::After(syn) => syn, + super::TreeDiffInsertPos::AsFirstChild(syn) => syn, + }), + k, + v.iter().format_with("\n-> ", |v, f| f(&fmt_syntax(v))) + )) + }); + + let replacements = diff + .replacements + .iter() + .sorted_by_key(|(syntax, _)| syntax.text_range().start()) + .format_with("\n", |(k, v), f| { + f(&format!("Line {}: {k:?} -> {}", line_number(k), fmt_syntax(v))) + }); + + let deletions = diff + .deletions + .iter() + .format_with("\n", |v, f| f(&format!("Line {}: {}", line_number(v), fmt_syntax(v)))); + + let actual = format!( + "insertions:\n\n{insertions}\n\nreplacements:\n\n{replacements}\n\ndeletions:\n\n{deletions}\n" + ); + expected_diff.assert_eq(&actual); + + let mut from = from.to_owned(); + let mut text_edit = TextEdit::builder(); + diff.into_text_edit(&mut text_edit); + text_edit.finish().apply(&mut from); + assert_eq!(&*from, to, "diff did not turn `from` to `to`"); + } +} diff --git a/src/tools/rust-analyzer/crates/text-edit/src/lib.rs b/src/tools/rust-analyzer/crates/ide-db/src/text_edit.rs index 3efe0850d88..0c675f0619f 100644 --- a/src/tools/rust-analyzer/crates/text-edit/src/lib.rs +++ b/src/tools/rust-analyzer/crates/ide-db/src/text_edit.rs @@ -5,8 +5,8 @@ //! rust-analyzer. use itertools::Itertools; +pub use span::{TextRange, TextSize}; use std::cmp::max; -pub use text_size::{TextRange, TextSize}; /// `InsertDelete` -- a single "atomic" change to text /// diff --git a/src/tools/rust-analyzer/crates/ide-diagnostics/Cargo.toml b/src/tools/rust-analyzer/crates/ide-diagnostics/Cargo.toml index bf54f4ab322..281a08e5429 100644 --- a/src/tools/rust-analyzer/crates/ide-diagnostics/Cargo.toml +++ b/src/tools/rust-analyzer/crates/ide-diagnostics/Cargo.toml @@ -22,7 +22,6 @@ tracing.workspace = true # local deps stdx.workspace = true syntax.workspace = true -text-edit.workspace = true cfg.workspace = true hir.workspace = true ide-db.workspace = true diff --git a/src/tools/rust-analyzer/crates/ide-diagnostics/src/handlers/field_shorthand.rs b/src/tools/rust-analyzer/crates/ide-diagnostics/src/handlers/field_shorthand.rs index c7071d1ce47..876c2ccd49d 100644 --- a/src/tools/rust-analyzer/crates/ide-diagnostics/src/handlers/field_shorthand.rs +++ b/src/tools/rust-analyzer/crates/ide-diagnostics/src/handlers/field_shorthand.rs @@ -1,9 +1,9 @@ //! Suggests shortening `Foo { field: field }` to `Foo { field }` in both //! expressions and patterns. +use ide_db::text_edit::TextEdit; use ide_db::{source_change::SourceChange, EditionedFileId, FileRange}; use syntax::{ast, match_ast, AstNode, SyntaxNode}; -use text_edit::TextEdit; use crate::{fix, Diagnostic, DiagnosticCode}; diff --git a/src/tools/rust-analyzer/crates/ide-diagnostics/src/handlers/inactive_code.rs b/src/tools/rust-analyzer/crates/ide-diagnostics/src/handlers/inactive_code.rs index 1f8f805a1e2..4c0c685e550 100644 --- a/src/tools/rust-analyzer/crates/ide-diagnostics/src/handlers/inactive_code.rs +++ b/src/tools/rust-analyzer/crates/ide-diagnostics/src/handlers/inactive_code.rs @@ -195,4 +195,20 @@ union FooBar { "#, ); } + + #[test] + fn cfg_true_false() { + check( + r#" + #[cfg(false)] fn inactive() {} +//^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ weak: code is inactive due to #[cfg] directives: false is disabled + + #[cfg(true)] fn active() {} + + #[cfg(any(not(true)), false)] fn inactive2() {} +//^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ weak: code is inactive due to #[cfg] directives: true is enabled + +"#, + ); + } } diff --git a/src/tools/rust-analyzer/crates/ide-diagnostics/src/handlers/json_is_not_rust.rs b/src/tools/rust-analyzer/crates/ide-diagnostics/src/handlers/json_is_not_rust.rs index ccb33fed100..dca889d1a8e 100644 --- a/src/tools/rust-analyzer/crates/ide-diagnostics/src/handlers/json_is_not_rust.rs +++ b/src/tools/rust-analyzer/crates/ide-diagnostics/src/handlers/json_is_not_rust.rs @@ -2,6 +2,7 @@ //! example. use hir::{ImportPathConfig, PathResolution, Semantics}; +use ide_db::text_edit::TextEdit; use ide_db::{ helpers::mod_path_to_ast, imports::insert_use::{insert_use, ImportScope}, @@ -14,7 +15,6 @@ use syntax::{ ast::{self, make}, Edition, SyntaxKind, SyntaxNode, }; -use text_edit::TextEdit; use crate::{fix, Diagnostic, DiagnosticCode, DiagnosticsConfig, Severity}; diff --git a/src/tools/rust-analyzer/crates/ide-diagnostics/src/handlers/macro_error.rs b/src/tools/rust-analyzer/crates/ide-diagnostics/src/handlers/macro_error.rs index 6a976697c80..e177b72e4d4 100644 --- a/src/tools/rust-analyzer/crates/ide-diagnostics/src/handlers/macro_error.rs +++ b/src/tools/rust-analyzer/crates/ide-diagnostics/src/handlers/macro_error.rs @@ -3,14 +3,19 @@ use crate::{Diagnostic, DiagnosticCode, DiagnosticsContext, Severity}; // Diagnostic: macro-error // // This diagnostic is shown for macro expansion errors. + +// Diagnostic: proc-macros-disabled +// +// This diagnostic is shown for proc macros where proc macros have been disabled. + +// Diagnostic: proc-macro-disabled +// +// This diagnostic is shown for proc macros that has been specifically disabled via `rust-analyzer.procMacro.ignored`. pub(crate) fn macro_error(ctx: &DiagnosticsContext<'_>, d: &hir::MacroError) -> Diagnostic { // Use more accurate position if available. let display_range = ctx.resolve_precise_location(&d.node, d.precise_location); Diagnostic::new( - DiagnosticCode::Ra( - "macro-error", - if d.error { Severity::Error } else { Severity::WeakWarning }, - ), + DiagnosticCode::Ra(d.kind, if d.error { Severity::Error } else { Severity::WeakWarning }), d.message.clone(), display_range, ) diff --git a/src/tools/rust-analyzer/crates/ide-diagnostics/src/handlers/missing_fields.rs b/src/tools/rust-analyzer/crates/ide-diagnostics/src/handlers/missing_fields.rs index 86c237f7b5e..fd1044e51bc 100644 --- a/src/tools/rust-analyzer/crates/ide-diagnostics/src/handlers/missing_fields.rs +++ b/src/tools/rust-analyzer/crates/ide-diagnostics/src/handlers/missing_fields.rs @@ -5,15 +5,14 @@ use hir::{ }; use ide_db::{ assists::Assist, famous_defs::FamousDefs, imports::import_assets::item_for_path_search, - source_change::SourceChange, use_trivial_constructor::use_trivial_constructor, FxHashMap, + source_change::SourceChange, syntax_helpers::tree_diff::diff, text_edit::TextEdit, + use_trivial_constructor::use_trivial_constructor, FxHashMap, }; use stdx::format_to; use syntax::{ - algo, ast::{self, make}, AstNode, Edition, SyntaxNode, SyntaxNodePtr, ToSmolStr, }; -use text_edit::TextEdit; use crate::{fix, Diagnostic, DiagnosticCode, DiagnosticsContext}; @@ -77,7 +76,7 @@ fn fixes(ctx: &DiagnosticsContext<'_>, d: &hir::MissingFields) -> Option<Vec<Ass // FIXME: this also currently discards a lot of whitespace in the input... we really need a formatter here builder.replace(old_range.range, new_syntax.to_string()); } else { - algo::diff(old_syntax, new_syntax).into_text_edit(&mut builder); + diff(old_syntax, new_syntax).into_text_edit(&mut builder); } builder.finish() }; @@ -308,22 +307,27 @@ struct T(S); fn regular(a: S) { let s; S { s, .. } = a; + _ = s; } fn nested(a: S2) { let s; S2 { s: S { s, .. }, .. } = a; + _ = s; } fn in_tuple(a: (S,)) { let s; (S { s, .. },) = a; + _ = s; } fn in_array(a: [S;1]) { let s; [S { s, .. },] = a; + _ = s; } fn in_tuple_struct(a: T) { let s; T(S { s, .. }) = a; + _ = s; } ", ); diff --git a/src/tools/rust-analyzer/crates/ide-diagnostics/src/handlers/missing_unsafe.rs b/src/tools/rust-analyzer/crates/ide-diagnostics/src/handlers/missing_unsafe.rs index 44be53b87ca..a630d3c7c36 100644 --- a/src/tools/rust-analyzer/crates/ide-diagnostics/src/handlers/missing_unsafe.rs +++ b/src/tools/rust-analyzer/crates/ide-diagnostics/src/handlers/missing_unsafe.rs @@ -1,9 +1,9 @@ use hir::db::ExpandDatabase; use hir::HirFileIdExt; +use ide_db::text_edit::TextEdit; use ide_db::{assists::Assist, source_change::SourceChange}; use syntax::{ast, SyntaxNode}; use syntax::{match_ast, AstNode}; -use text_edit::TextEdit; use crate::{fix, Diagnostic, DiagnosticCode, DiagnosticsContext}; @@ -32,7 +32,8 @@ fn fixes(ctx: &DiagnosticsContext<'_>, d: &hir::MissingUnsafe) -> Option<Vec<Ass } let root = ctx.sema.db.parse_or_expand(d.expr.file_id); - let expr = d.expr.value.to_node(&root); + let node = d.expr.value.to_node(&root); + let expr = node.syntax().ancestors().find_map(ast::Expr::cast)?; let node_to_add_unsafe_block = pick_best_node_to_add_unsafe_block(&expr)?; diff --git a/src/tools/rust-analyzer/crates/ide-diagnostics/src/handlers/mutability_errors.rs b/src/tools/rust-analyzer/crates/ide-diagnostics/src/handlers/mutability_errors.rs index 6fa0e7a5a89..13979791444 100644 --- a/src/tools/rust-analyzer/crates/ide-diagnostics/src/handlers/mutability_errors.rs +++ b/src/tools/rust-analyzer/crates/ide-diagnostics/src/handlers/mutability_errors.rs @@ -1,6 +1,7 @@ +use hir::db::ExpandDatabase; use ide_db::source_change::SourceChange; -use syntax::{AstNode, SyntaxKind, SyntaxNode, SyntaxToken, T}; -use text_edit::TextEdit; +use ide_db::text_edit::TextEdit; +use syntax::{ast, AstNode, SyntaxKind, SyntaxNode, SyntaxNodePtr, SyntaxToken, T}; use crate::{fix, Diagnostic, DiagnosticCode, DiagnosticsContext}; @@ -8,18 +9,27 @@ use crate::{fix, Diagnostic, DiagnosticCode, DiagnosticsContext}; // // This diagnostic is triggered on mutating an immutable variable. pub(crate) fn need_mut(ctx: &DiagnosticsContext<'_>, d: &hir::NeedMut) -> Option<Diagnostic> { - if d.span.file_id.macro_file().is_some() { - // FIXME: Our infra can't handle allow from within macro expansions rn - return None; - } + let root = ctx.sema.db.parse_or_expand(d.span.file_id); + let node = d.span.value.to_node(&root); + let mut span = d.span; + if let Some(parent) = node.parent() { + if ast::BinExpr::can_cast(parent.kind()) { + // In case of an assignment, the diagnostic is provided on the variable name. + // We want to expand it to include the whole assignment, but only when this + // is an ordinary assignment, not a destructuring assignment. So, the direct + // parent is an assignment expression. + span = d.span.with_value(SyntaxNodePtr::new(&parent)); + } + }; + let fixes = (|| { if d.local.is_ref(ctx.sema.db) { // There is no simple way to add `mut` to `ref x` and `ref mut x` return None; } - let file_id = d.span.file_id.file_id()?; + let file_id = span.file_id.file_id()?; let mut edit_builder = TextEdit::builder(); - let use_range = d.span.value.text_range(); + let use_range = span.value.text_range(); for source in d.local.sources(ctx.sema.db) { let Some(ast) = source.name() else { continue }; // FIXME: macros @@ -33,6 +43,7 @@ pub(crate) fn need_mut(ctx: &DiagnosticsContext<'_>, d: &hir::NeedMut) -> Option use_range, )]) })(); + Some( Diagnostic::new_with_syntax_node_ptr( ctx, @@ -42,7 +53,7 @@ pub(crate) fn need_mut(ctx: &DiagnosticsContext<'_>, d: &hir::NeedMut) -> Option "cannot mutate immutable variable `{}`", d.local.name(ctx.sema.db).display(ctx.sema.db, ctx.edition) ), - d.span, + span, ) .with_fixes(fixes), ) @@ -53,10 +64,6 @@ pub(crate) fn need_mut(ctx: &DiagnosticsContext<'_>, d: &hir::NeedMut) -> Option // This diagnostic is triggered when a mutable variable isn't actually mutated. pub(crate) fn unused_mut(ctx: &DiagnosticsContext<'_>, d: &hir::UnusedMut) -> Option<Diagnostic> { let ast = d.local.primary_source(ctx.sema.db).syntax_ptr(); - if ast.file_id.macro_file().is_some() { - // FIXME: Our infra can't handle allow from within macro expansions rn - return None; - } let fixes = (|| { let file_id = ast.file_id.file_id()?; let mut edit_builder = TextEdit::builder(); @@ -937,7 +944,6 @@ fn fn_once(mut x: impl FnOnce(u8) -> u8) -> u8 { #[test] fn closure() { - // FIXME: Diagnostic spans are inconsistent inside and outside closure check_diagnostics( r#" //- minicore: copy, fn @@ -950,11 +956,11 @@ fn fn_once(mut x: impl FnOnce(u8) -> u8) -> u8 { fn f() { let x = 5; let closure1 = || { x = 2; }; - //^ 💡 error: cannot mutate immutable variable `x` + //^^^^^ 💡 error: cannot mutate immutable variable `x` let _ = closure1(); //^^^^^^^^ 💡 error: cannot mutate immutable variable `closure1` let closure2 = || { x = x; }; - //^ 💡 error: cannot mutate immutable variable `x` + //^^^^^ 💡 error: cannot mutate immutable variable `x` let closure3 = || { let x = 2; x = 5; @@ -996,7 +1002,7 @@ fn f() { || { let x = 2; || { || { x = 5; } } - //^ 💡 error: cannot mutate immutable variable `x` + //^^^^^ 💡 error: cannot mutate immutable variable `x` } } }; @@ -1283,4 +1289,19 @@ fn main() { "#, ); } + + #[test] + fn destructuring_assignment_needs_mut() { + check_diagnostics( + r#" +//- minicore: fn + +fn main() { + let mut var = 1; + let mut func = || (var,) = (2,); + func(); +} + "#, + ); + } } diff --git a/src/tools/rust-analyzer/crates/ide-diagnostics/src/handlers/no_such_field.rs b/src/tools/rust-analyzer/crates/ide-diagnostics/src/handlers/no_such_field.rs index dfadef11fde..e5d871975b6 100644 --- a/src/tools/rust-analyzer/crates/ide-diagnostics/src/handlers/no_such_field.rs +++ b/src/tools/rust-analyzer/crates/ide-diagnostics/src/handlers/no_such_field.rs @@ -1,11 +1,11 @@ use either::Either; use hir::{db::ExpandDatabase, HasSource, HirDisplay, HirFileIdExt, Semantics, VariantId}; +use ide_db::text_edit::TextEdit; use ide_db::{source_change::SourceChange, EditionedFileId, RootDatabase}; use syntax::{ ast::{self, edit::IndentLevel, make}, AstNode, }; -use text_edit::TextEdit; use crate::{fix, Assist, Diagnostic, DiagnosticCode, DiagnosticsContext}; diff --git a/src/tools/rust-analyzer/crates/ide-diagnostics/src/handlers/remove_trailing_return.rs b/src/tools/rust-analyzer/crates/ide-diagnostics/src/handlers/remove_trailing_return.rs index 62bc1f3d06f..c8e3cff364a 100644 --- a/src/tools/rust-analyzer/crates/ide-diagnostics/src/handlers/remove_trailing_return.rs +++ b/src/tools/rust-analyzer/crates/ide-diagnostics/src/handlers/remove_trailing_return.rs @@ -1,7 +1,7 @@ use hir::{db::ExpandDatabase, diagnostics::RemoveTrailingReturn, FileRange}; +use ide_db::text_edit::TextEdit; use ide_db::{assists::Assist, source_change::SourceChange}; use syntax::{ast, AstNode}; -use text_edit::TextEdit; use crate::{adjusted_display_range, fix, Diagnostic, DiagnosticCode, DiagnosticsContext}; diff --git a/src/tools/rust-analyzer/crates/ide-diagnostics/src/handlers/remove_unnecessary_else.rs b/src/tools/rust-analyzer/crates/ide-diagnostics/src/handlers/remove_unnecessary_else.rs index 448df1ca163..a46c48608f7 100644 --- a/src/tools/rust-analyzer/crates/ide-diagnostics/src/handlers/remove_unnecessary_else.rs +++ b/src/tools/rust-analyzer/crates/ide-diagnostics/src/handlers/remove_unnecessary_else.rs @@ -1,4 +1,5 @@ use hir::{db::ExpandDatabase, diagnostics::RemoveUnnecessaryElse, HirFileIdExt}; +use ide_db::text_edit::TextEdit; use ide_db::{assists::Assist, source_change::SourceChange}; use itertools::Itertools; use syntax::{ @@ -8,7 +9,6 @@ use syntax::{ }, AstNode, SyntaxToken, TextRange, }; -use text_edit::TextEdit; use crate::{ adjusted_display_range, fix, Diagnostic, DiagnosticCode, DiagnosticsContext, Severity, diff --git a/src/tools/rust-analyzer/crates/ide-diagnostics/src/handlers/replace_filter_map_next_with_find_map.rs b/src/tools/rust-analyzer/crates/ide-diagnostics/src/handlers/replace_filter_map_next_with_find_map.rs index 18647206236..f481365f2a5 100644 --- a/src/tools/rust-analyzer/crates/ide-diagnostics/src/handlers/replace_filter_map_next_with_find_map.rs +++ b/src/tools/rust-analyzer/crates/ide-diagnostics/src/handlers/replace_filter_map_next_with_find_map.rs @@ -1,10 +1,10 @@ use hir::{db::ExpandDatabase, HirFileIdExt, InFile}; use ide_db::source_change::SourceChange; +use ide_db::text_edit::TextEdit; use syntax::{ ast::{self, HasArgList}, AstNode, TextRange, }; -use text_edit::TextEdit; use crate::{fix, Assist, Diagnostic, DiagnosticCode, DiagnosticsContext}; diff --git a/src/tools/rust-analyzer/crates/ide-diagnostics/src/handlers/trait_impl_redundant_assoc_item.rs b/src/tools/rust-analyzer/crates/ide-diagnostics/src/handlers/trait_impl_redundant_assoc_item.rs index 3de51ca4a30..1363a8ff0dd 100644 --- a/src/tools/rust-analyzer/crates/ide-diagnostics/src/handlers/trait_impl_redundant_assoc_item.rs +++ b/src/tools/rust-analyzer/crates/ide-diagnostics/src/handlers/trait_impl_redundant_assoc_item.rs @@ -1,11 +1,11 @@ use hir::{db::ExpandDatabase, HasSource, HirDisplay}; +use ide_db::text_edit::TextRange; use ide_db::{ assists::{Assist, AssistId, AssistKind}, label::Label, source_change::SourceChangeBuilder, }; use syntax::ToSmolStr; -use text_edit::TextRange; use crate::{Diagnostic, DiagnosticCode, DiagnosticsContext}; diff --git a/src/tools/rust-analyzer/crates/ide-diagnostics/src/handlers/type_mismatch.rs b/src/tools/rust-analyzer/crates/ide-diagnostics/src/handlers/type_mismatch.rs index 90f88d6705b..93fe9374a3e 100644 --- a/src/tools/rust-analyzer/crates/ide-diagnostics/src/handlers/type_mismatch.rs +++ b/src/tools/rust-analyzer/crates/ide-diagnostics/src/handlers/type_mismatch.rs @@ -1,5 +1,6 @@ use either::Either; use hir::{db::ExpandDatabase, ClosureStyle, HirDisplay, HirFileIdExt, InFile, Type}; +use ide_db::text_edit::TextEdit; use ide_db::{famous_defs::FamousDefs, source_change::SourceChange}; use syntax::{ ast::{ @@ -9,7 +10,6 @@ use syntax::{ }, AstNode, AstPtr, TextSize, }; -use text_edit::TextEdit; use crate::{adjusted_display_range, fix, Assist, Diagnostic, DiagnosticCode, DiagnosticsContext}; diff --git a/src/tools/rust-analyzer/crates/ide-diagnostics/src/handlers/typed_hole.rs b/src/tools/rust-analyzer/crates/ide-diagnostics/src/handlers/typed_hole.rs index 6994a7ed146..3ad84f7bda2 100644 --- a/src/tools/rust-analyzer/crates/ide-diagnostics/src/handlers/typed_hole.rs +++ b/src/tools/rust-analyzer/crates/ide-diagnostics/src/handlers/typed_hole.rs @@ -3,13 +3,13 @@ use hir::{ term_search::{term_search, TermSearchConfig, TermSearchCtx}, ClosureStyle, HirDisplay, ImportPathConfig, }; +use ide_db::text_edit::TextEdit; use ide_db::{ assists::{Assist, AssistId, AssistKind, GroupLabel}, label::Label, source_change::SourceChange, }; use itertools::Itertools; -use text_edit::TextEdit; use crate::{Diagnostic, DiagnosticCode, DiagnosticsContext}; diff --git a/src/tools/rust-analyzer/crates/ide-diagnostics/src/handlers/undeclared_label.rs b/src/tools/rust-analyzer/crates/ide-diagnostics/src/handlers/undeclared_label.rs index 6af36fb9e73..d16bfb80024 100644 --- a/src/tools/rust-analyzer/crates/ide-diagnostics/src/handlers/undeclared_label.rs +++ b/src/tools/rust-analyzer/crates/ide-diagnostics/src/handlers/undeclared_label.rs @@ -107,4 +107,34 @@ async fn foo() { "#, ); } + + #[test] + fn macro_expansion_can_refer_label_defined_before_macro_definition() { + check_diagnostics( + r#" +fn foo() { + 'bar: loop { + macro_rules! m { + () => { break 'bar }; + } + m!(); + } +} +"#, + ); + check_diagnostics( + r#" +fn foo() { + 'bar: loop { + macro_rules! m { + () => { break 'bar }; + } + 'bar: loop { + m!(); + } + } +} +"#, + ); + } } diff --git a/src/tools/rust-analyzer/crates/ide-diagnostics/src/handlers/unlinked_file.rs b/src/tools/rust-analyzer/crates/ide-diagnostics/src/handlers/unlinked_file.rs index e0822fc5b33..13591dfb2ee 100644 --- a/src/tools/rust-analyzer/crates/ide-diagnostics/src/handlers/unlinked_file.rs +++ b/src/tools/rust-analyzer/crates/ide-diagnostics/src/handlers/unlinked_file.rs @@ -3,6 +3,7 @@ use std::iter; use hir::{db::DefDatabase, DefMap, InFile, ModuleSource}; +use ide_db::text_edit::TextEdit; use ide_db::{ base_db::{FileLoader, SourceDatabase, SourceRootDatabase}, source_change::SourceChange, @@ -13,7 +14,6 @@ use syntax::{ ast::{self, edit::IndentLevel, HasModuleItem, HasName}, AstNode, TextRange, }; -use text_edit::TextEdit; use crate::{fix, Assist, Diagnostic, DiagnosticCode, DiagnosticsContext, Severity}; diff --git a/src/tools/rust-analyzer/crates/ide-diagnostics/src/handlers/unresolved_field.rs b/src/tools/rust-analyzer/crates/ide-diagnostics/src/handlers/unresolved_field.rs index 76d624c47ab..656bedff1a8 100644 --- a/src/tools/rust-analyzer/crates/ide-diagnostics/src/handlers/unresolved_field.rs +++ b/src/tools/rust-analyzer/crates/ide-diagnostics/src/handlers/unresolved_field.rs @@ -1,6 +1,7 @@ use std::iter; use hir::{db::ExpandDatabase, Adt, FileRange, HasSource, HirDisplay, InFile, Struct, Union}; +use ide_db::text_edit::TextEdit; use ide_db::{ assists::{Assist, AssistId, AssistKind}, helpers::is_editable_crate, @@ -16,7 +17,6 @@ use syntax::{ ast::{edit::AstNodeEdit, Type}, SyntaxNode, }; -use text_edit::TextEdit; use crate::{adjusted_display_range, Diagnostic, DiagnosticCode, DiagnosticsContext}; diff --git a/src/tools/rust-analyzer/crates/ide-diagnostics/src/handlers/unresolved_ident.rs b/src/tools/rust-analyzer/crates/ide-diagnostics/src/handlers/unresolved_ident.rs index 9a81682aaeb..68f14a97f59 100644 --- a/src/tools/rust-analyzer/crates/ide-diagnostics/src/handlers/unresolved_ident.rs +++ b/src/tools/rust-analyzer/crates/ide-diagnostics/src/handlers/unresolved_ident.rs @@ -11,7 +11,7 @@ pub(crate) fn unresolved_ident( ctx, DiagnosticCode::RustcHardError("E0425"), "no such value in this scope", - d.expr.map(Into::into), + d.expr_or_pat.map(Into::into), ) .experimental() } diff --git a/src/tools/rust-analyzer/crates/ide-diagnostics/src/handlers/unresolved_macro_call.rs b/src/tools/rust-analyzer/crates/ide-diagnostics/src/handlers/unresolved_macro_call.rs index 5b596123e75..0d1c9775062 100644 --- a/src/tools/rust-analyzer/crates/ide-diagnostics/src/handlers/unresolved_macro_call.rs +++ b/src/tools/rust-analyzer/crates/ide-diagnostics/src/handlers/unresolved_macro_call.rs @@ -82,4 +82,29 @@ self::m!(); self::m2!(); "#, ); } + + #[test] + fn no_unresolved_panic_inside_mod_inside_fn() { + check_diagnostics( + r#" +//- /core.rs library crate:core +#[macro_export] +macro_rules! panic { + () => {}; +} + +//- /lib.rs crate:foo deps:core +#[macro_use] +extern crate core; + +fn foo() { + mod init { + pub fn init() { + panic!(); + } + } +} + "#, + ); + } } diff --git a/src/tools/rust-analyzer/crates/ide-diagnostics/src/handlers/unresolved_method.rs b/src/tools/rust-analyzer/crates/ide-diagnostics/src/handlers/unresolved_method.rs index c0d038a238b..81cb4521218 100644 --- a/src/tools/rust-analyzer/crates/ide-diagnostics/src/handlers/unresolved_method.rs +++ b/src/tools/rust-analyzer/crates/ide-diagnostics/src/handlers/unresolved_method.rs @@ -1,4 +1,5 @@ use hir::{db::ExpandDatabase, AssocItem, FileRange, HirDisplay, InFile}; +use ide_db::text_edit::TextEdit; use ide_db::{ assists::{Assist, AssistId, AssistKind}, label::Label, @@ -8,7 +9,6 @@ use syntax::{ ast::{self, make, HasArgList}, format_smolstr, AstNode, SmolStr, TextRange, ToSmolStr, }; -use text_edit::TextEdit; use crate::{adjusted_display_range, Diagnostic, DiagnosticCode, DiagnosticsContext}; diff --git a/src/tools/rust-analyzer/crates/ide-diagnostics/src/handlers/unused_variables.rs b/src/tools/rust-analyzer/crates/ide-diagnostics/src/handlers/unused_variables.rs index 84007b16aa6..67ece566941 100644 --- a/src/tools/rust-analyzer/crates/ide-diagnostics/src/handlers/unused_variables.rs +++ b/src/tools/rust-analyzer/crates/ide-diagnostics/src/handlers/unused_variables.rs @@ -1,4 +1,5 @@ use hir::Name; +use ide_db::text_edit::TextEdit; use ide_db::{ assists::{Assist, AssistId, AssistKind}, label::Label, @@ -6,7 +7,6 @@ use ide_db::{ FileRange, RootDatabase, }; use syntax::{Edition, TextRange}; -use text_edit::TextEdit; use crate::{Diagnostic, DiagnosticCode, DiagnosticsContext}; diff --git a/src/tools/rust-analyzer/crates/ide-diagnostics/src/handlers/useless_braces.rs b/src/tools/rust-analyzer/crates/ide-diagnostics/src/handlers/useless_braces.rs index 2d380ae0457..e5c2eca171a 100644 --- a/src/tools/rust-analyzer/crates/ide-diagnostics/src/handlers/useless_braces.rs +++ b/src/tools/rust-analyzer/crates/ide-diagnostics/src/handlers/useless_braces.rs @@ -1,8 +1,8 @@ use hir::InFile; +use ide_db::text_edit::TextEdit; use ide_db::{source_change::SourceChange, EditionedFileId, FileRange}; use itertools::Itertools; use syntax::{ast, AstNode, SyntaxNode, SyntaxNodePtr}; -use text_edit::TextEdit; use crate::{fix, Diagnostic, DiagnosticCode}; diff --git a/src/tools/rust-analyzer/crates/ide-ssr/Cargo.toml b/src/tools/rust-analyzer/crates/ide-ssr/Cargo.toml index fad62fa3b96..25614676288 100644 --- a/src/tools/rust-analyzer/crates/ide-ssr/Cargo.toml +++ b/src/tools/rust-analyzer/crates/ide-ssr/Cargo.toml @@ -24,7 +24,6 @@ ide-db.workspace = true parser.workspace = true stdx.workspace = true syntax.workspace = true -text-edit.workspace = true [dev-dependencies] expect-test = "1.4.0" @@ -34,4 +33,4 @@ test-utils.workspace = true test-fixture.workspace = true [lints] -workspace = true \ No newline at end of file +workspace = true diff --git a/src/tools/rust-analyzer/crates/ide-ssr/src/lib.rs b/src/tools/rust-analyzer/crates/ide-ssr/src/lib.rs index 54236ea8bc4..eaca95d98c2 100644 --- a/src/tools/rust-analyzer/crates/ide-ssr/src/lib.rs +++ b/src/tools/rust-analyzer/crates/ide-ssr/src/lib.rs @@ -84,10 +84,10 @@ pub use crate::{errors::SsrError, from_comment::ssr_from_comment, matching::Matc use crate::{errors::bail, matching::MatchFailureReason}; use hir::{FileRange, Semantics}; +use ide_db::text_edit::TextEdit; use ide_db::{base_db::SourceDatabase, EditionedFileId, FileId, FxHashMap, RootDatabase}; use resolving::ResolvedRule; use syntax::{ast, AstNode, SyntaxNode, TextRange}; -use text_edit::TextEdit; // A structured search replace rule. Create by calling `parse` on a str. #[derive(Debug)] diff --git a/src/tools/rust-analyzer/crates/ide-ssr/src/parsing.rs b/src/tools/rust-analyzer/crates/ide-ssr/src/parsing.rs index e752ee3d775..ea40d5b815e 100644 --- a/src/tools/rust-analyzer/crates/ide-ssr/src/parsing.rs +++ b/src/tools/rust-analyzer/crates/ide-ssr/src/parsing.rs @@ -190,7 +190,7 @@ impl RawPattern { let mut res = FxHashMap::default(); for t in &self.tokens { if let PatternElement::Placeholder(placeholder) = t { - res.insert(SmolStr::new(placeholder.stand_in_name.clone()), placeholder.clone()); + res.insert(SmolStr::new(&placeholder.stand_in_name), placeholder.clone()); } } res diff --git a/src/tools/rust-analyzer/crates/ide-ssr/src/replacing.rs b/src/tools/rust-analyzer/crates/ide-ssr/src/replacing.rs index 65756601f66..11c1615a560 100644 --- a/src/tools/rust-analyzer/crates/ide-ssr/src/replacing.rs +++ b/src/tools/rust-analyzer/crates/ide-ssr/src/replacing.rs @@ -1,5 +1,6 @@ //! Code for applying replacement templates for matches that have previously been found. +use ide_db::text_edit::TextEdit; use ide_db::{FxHashMap, FxHashSet}; use itertools::Itertools; use parser::Edition; @@ -7,7 +8,6 @@ use syntax::{ ast::{self, AstNode, AstToken}, SyntaxElement, SyntaxKind, SyntaxNode, SyntaxToken, TextRange, TextSize, }; -use text_edit::TextEdit; use crate::{fragments, resolving::ResolvedRule, Match, SsrMatches}; diff --git a/src/tools/rust-analyzer/crates/ide/Cargo.toml b/src/tools/rust-analyzer/crates/ide/Cargo.toml index d976d604f1a..7c66b36dc8e 100644 --- a/src/tools/rust-analyzer/crates/ide/Cargo.toml +++ b/src/tools/rust-analyzer/crates/ide/Cargo.toml @@ -39,7 +39,6 @@ profile.workspace = true stdx.workspace = true syntax.workspace = true span.workspace = true -text-edit.workspace = true # ide should depend only on the top-level `hir` package. if you need # something from some `hir-xxx` subpackage, reexport the API via `hir`. hir.workspace = true diff --git a/src/tools/rust-analyzer/crates/ide/src/call_hierarchy.rs b/src/tools/rust-analyzer/crates/ide/src/call_hierarchy.rs index 1b82c00d1dc..e5b4ed17b2a 100644 --- a/src/tools/rust-analyzer/crates/ide/src/call_hierarchy.rs +++ b/src/tools/rust-analyzer/crates/ide/src/call_hierarchy.rs @@ -510,6 +510,7 @@ fn caller$0() { expect![[]], ); } + #[test] fn test_call_hierarchy_in_macros_incoming_different_files() { check_hierarchy( @@ -591,9 +592,9 @@ macro_rules! call { "#, expect!["callee Function FileId(0) 22..37 30..36"], expect![[r#" - callee Function FileId(0) 38..52 44..50 : FileId(0):44..50 caller Function FileId(0) 38..52 : FileId(0):44..50 - caller Function FileId(1) 130..136 130..136 : FileId(0):44..50"#]], + caller Function FileId(1) 130..136 130..136 : FileId(0):44..50 + callee Function FileId(0) 38..52 44..50 : FileId(0):44..50"#]], expect![[]], ); } diff --git a/src/tools/rust-analyzer/crates/ide/src/file_structure.rs b/src/tools/rust-analyzer/crates/ide/src/file_structure.rs index 92458185849..055080ad17b 100644 --- a/src/tools/rust-analyzer/crates/ide/src/file_structure.rs +++ b/src/tools/rust-analyzer/crates/ide/src/file_structure.rs @@ -187,6 +187,24 @@ fn structure_node(node: &SyntaxNode) -> Option<StructureNode> { }; Some(node) }, + ast::LetStmt(it) => { + let pat = it.pat()?; + + let mut label = String::new(); + collapse_ws(pat.syntax(), &mut label); + + let node = StructureNode { + parent: None, + label, + navigation_range: pat.syntax().text_range(), + node_range: it.syntax().text_range(), + kind: StructureNodeKind::SymbolKind(SymbolKind::Local), + detail: it.ty().map(|ty| ty.to_string()), + deprecated: false, + }; + + Some(node) + }, ast::Macro(it) => decl(it, StructureNodeKind::SymbolKind(SymbolKind::Macro)), _ => None, } @@ -308,6 +326,17 @@ fn f() {} // endregion fn g() {} } + +fn let_statements() { + let x = 42; + let mut y = x; + let Foo { + .. + } = Foo { x }; + if let None = Some(x) {} + _ = (); + let _ = g(); +} "#, expect![[r#" [ @@ -633,6 +662,71 @@ fn g() {} ), deprecated: false, }, + StructureNode { + parent: None, + label: "let_statements", + navigation_range: 641..655, + node_range: 638..798, + kind: SymbolKind( + Function, + ), + detail: Some( + "fn()", + ), + deprecated: false, + }, + StructureNode { + parent: Some( + 26, + ), + label: "x", + navigation_range: 668..669, + node_range: 664..675, + kind: SymbolKind( + Local, + ), + detail: None, + deprecated: false, + }, + StructureNode { + parent: Some( + 26, + ), + label: "mut y", + navigation_range: 684..689, + node_range: 680..694, + kind: SymbolKind( + Local, + ), + detail: None, + deprecated: false, + }, + StructureNode { + parent: Some( + 26, + ), + label: "Foo { .. }", + navigation_range: 703..725, + node_range: 699..738, + kind: SymbolKind( + Local, + ), + detail: None, + deprecated: false, + }, + StructureNode { + parent: Some( + 26, + ), + label: "_", + navigation_range: 788..789, + node_range: 784..796, + kind: SymbolKind( + Local, + ), + detail: None, + deprecated: false, + }, ] "#]], ); diff --git a/src/tools/rust-analyzer/crates/ide/src/goto_definition.rs b/src/tools/rust-analyzer/crates/ide/src/goto_definition.rs index 4cbcb6ed050..363f852e0e4 100644 --- a/src/tools/rust-analyzer/crates/ide/src/goto_definition.rs +++ b/src/tools/rust-analyzer/crates/ide/src/goto_definition.rs @@ -13,7 +13,6 @@ use ide_db::{ RootDatabase, SymbolKind, }; use itertools::Itertools; - use span::{Edition, FileId}; use syntax::{ ast::{self, HasLoopBody}, @@ -99,6 +98,7 @@ pub(crate) fn goto_definition( return Some(vec![x]); } } + Some( IdentClass::classify_node(sema, &parent)? .definitions() @@ -418,10 +418,10 @@ fn expr_to_nav( #[cfg(test)] mod tests { + use crate::fixture; use ide_db::FileRange; use itertools::Itertools; - - use crate::fixture; + use syntax::SmolStr; #[track_caller] fn check(ra_fixture: &str) { @@ -450,6 +450,170 @@ mod tests { assert!(navs.is_empty(), "didn't expect this to resolve anywhere: {navs:?}") } + fn check_name(expected_name: &str, ra_fixture: &str) { + let (analysis, position, _) = fixture::annotations(ra_fixture); + let navs = analysis.goto_definition(position).unwrap().expect("no definition found").info; + assert!(navs.len() < 2, "expected single navigation target but encountered {}", navs.len()); + let Some(target) = navs.into_iter().next() else { + panic!("expected single navigation target but encountered none"); + }; + assert_eq!(target.name, SmolStr::new_inline(expected_name)); + } + + #[test] + fn goto_def_pat_range_to_inclusive() { + check_name( + "RangeToInclusive", + r#" +//- minicore: range +fn f(ch: char) -> bool { + match ch { + ..$0='z' => true, + _ => false + } +} +"#, + ); + } + + #[test] + fn goto_def_pat_range_to() { + check_name( + "RangeTo", + r#" +//- minicore: range +fn f(ch: char) -> bool { + match ch { + .$0.'z' => true, + _ => false + } +} +"#, + ); + } + + #[test] + fn goto_def_pat_range() { + check_name( + "Range", + r#" +//- minicore: range +fn f(ch: char) -> bool { + match ch { + 'a'.$0.'z' => true, + _ => false + } +} +"#, + ); + } + + #[test] + fn goto_def_pat_range_inclusive() { + check_name( + "RangeInclusive", + r#" +//- minicore: range +fn f(ch: char) -> bool { + match ch { + 'a'..$0='z' => true, + _ => false + } +} +"#, + ); + } + + #[test] + fn goto_def_pat_range_from() { + check_name( + "RangeFrom", + r#" +//- minicore: range +fn f(ch: char) -> bool { + match ch { + 'a'..$0 => true, + _ => false + } +} +"#, + ); + } + + #[test] + fn goto_def_expr_range() { + check_name( + "Range", + r#" +//- minicore: range +let x = 0.$0.1; +"#, + ); + } + + #[test] + fn goto_def_expr_range_from() { + check_name( + "RangeFrom", + r#" +//- minicore: range +fn f(arr: &[i32]) -> &[i32] { + &arr[0.$0.] +} +"#, + ); + } + + #[test] + fn goto_def_expr_range_inclusive() { + check_name( + "RangeInclusive", + r#" +//- minicore: range +let x = 0.$0.=1; +"#, + ); + } + + #[test] + fn goto_def_expr_range_full() { + check_name( + "RangeFull", + r#" +//- minicore: range +fn f(arr: &[i32]) -> &[i32] { + &arr[.$0.] +} +"#, + ); + } + + #[test] + fn goto_def_expr_range_to() { + check_name( + "RangeTo", + r#" +//- minicore: range +fn f(arr: &[i32]) -> &[i32] { + &arr[.$0.10] +} +"#, + ); + } + + #[test] + fn goto_def_expr_range_to_inclusive() { + check_name( + "RangeToInclusive", + r#" +//- minicore: range +fn f(arr: &[i32]) -> &[i32] { + &arr[.$0.=10] +} +"#, + ); + } + #[test] fn goto_def_in_included_file() { check( @@ -2838,4 +3002,24 @@ use foo::m; "#, ); } + + #[test] + fn macro_label_hygiene() { + check( + r#" +macro_rules! m { + ($x:stmt) => { + 'bar: loop { $x } + }; +} + +fn foo() { + 'bar: loop { + // ^^^^ + m!(continue 'bar$0); + } +} +"#, + ); + } } diff --git a/src/tools/rust-analyzer/crates/ide/src/hover.rs b/src/tools/rust-analyzer/crates/ide/src/hover.rs index 124db2985bf..6cac4f1ee48 100644 --- a/src/tools/rust-analyzer/crates/ide/src/hover.rs +++ b/src/tools/rust-analyzer/crates/ide/src/hover.rs @@ -11,7 +11,7 @@ use ide_db::{ defs::{Definition, IdentClass, NameRefClass, OperatorClass}, famous_defs::FamousDefs, helpers::pick_best_token, - FileRange, FxIndexSet, RootDatabase, + FileRange, FxIndexSet, Ranker, RootDatabase, }; use itertools::{multizip, Itertools}; use span::Edition; @@ -182,27 +182,13 @@ fn hover_offset( // equivalency is more important let mut descended = sema.descend_into_macros(original_token.clone()); - let kind = original_token.kind(); - let text = original_token.text(); - let ident_kind = kind.is_any_identifier(); - - descended.sort_by_cached_key(|tok| { - let tok_kind = tok.kind(); - - let exact_same_kind = tok_kind == kind; - let both_idents = exact_same_kind || (tok_kind.is_any_identifier() && ident_kind); - let same_text = tok.text() == text; - // anything that mapped into a token tree has likely no semantic information - let no_tt_parent = tok.parent().map_or(false, |it| it.kind() != TOKEN_TREE); - !((both_idents as usize) - | ((exact_same_kind as usize) << 1) - | ((same_text as usize) << 2) - | ((no_tt_parent as usize) << 3)) - }); + let ranker = Ranker::from_token(&original_token); + + descended.sort_by_cached_key(|tok| !ranker.rank_token(tok)); let mut res = vec![]; for token in descended { - let is_same_kind = token.kind() == kind; + let is_same_kind = token.kind() == ranker.kind; let lint_hover = (|| { // FIXME: Definition should include known lints and the like instead of having this special case here let attr = token.parent_ancestors().find_map(ast::Attr::cast)?; diff --git a/src/tools/rust-analyzer/crates/ide/src/hover/render.rs b/src/tools/rust-analyzer/crates/ide/src/hover/render.rs index 01fa316d5fc..a31b14dbd3e 100644 --- a/src/tools/rust-analyzer/crates/ide/src/hover/render.rs +++ b/src/tools/rust-analyzer/crates/ide/src/hover/render.rs @@ -1042,7 +1042,7 @@ fn render_dyn_compatibility( } DynCompatibilityViolation::HasNonCompatibleSuperTrait(super_trait) => { let name = hir::Trait::from(super_trait).name(db); - format_to!(buf, "has a object unsafe supertrait `{}`", name.as_str()); + format_to!(buf, "has a dyn incompatible supertrait `{}`", name.as_str()); } } } diff --git a/src/tools/rust-analyzer/crates/ide/src/hover/tests.rs b/src/tools/rust-analyzer/crates/ide/src/hover/tests.rs index 81397b07855..3e402630419 100644 --- a/src/tools/rust-analyzer/crates/ide/src/hover/tests.rs +++ b/src/tools/rust-analyzer/crates/ide/src/hover/tests.rs @@ -289,7 +289,7 @@ m!(ab$0c); *abc* ```rust - test::module + test ``` ```rust @@ -298,11 +298,11 @@ m!(ab$0c); --- - Inner + Outer --- ```rust - test + test::module ``` ```rust @@ -311,7 +311,7 @@ m!(ab$0c); --- - Outer + Inner "#]], ); } @@ -9018,3 +9018,156 @@ foo!(BAR_$0); "#]], ); } + +#[test] +fn type_alias_without_docs() { + // Simple. + check( + r#" +/// Docs for B +struct B; + +type A$0 = B; +"#, + expect![[r#" + *A* + + ```rust + test + ``` + + ```rust + // size = 0, align = 1 + type A = B + ``` + + --- + + *This is the documentation for* `struct B` + + Docs for B + "#]], + ); + + // Nested. + check( + r#" +/// Docs for C +struct C; + +type B = C; + +type A$0 = B; +"#, + expect![[r#" + *A* + + ```rust + test + ``` + + ```rust + // size = 0, align = 1 + type A = B + ``` + + --- + + *This is the documentation for* `struct C` + + Docs for C + "#]], + ); + + // Showing the docs for aliased struct instead of intermediate type. + check( + r#" +/// Docs for C +struct C; + +/// Docs for B +type B = C; + +type A$0 = B; +"#, + expect![[r#" + *A* + + ```rust + test + ``` + + ```rust + // size = 0, align = 1 + type A = B + ``` + + --- + + *This is the documentation for* `struct C` + + Docs for C + "#]], + ); + + // No docs found. + check( + r#" +struct C; + +type B = C; + +type A$0 = B; +"#, + expect![[r#" + *A* + + ```rust + test + ``` + + ```rust + // size = 0, align = 1 + type A = B + ``` + "#]], + ); + + // Multiple nested crate. + check( + r#" +//- /lib.rs crate:c +/// Docs for C +pub struct C; + +//- /lib.rs crate:b deps:c +pub use c::C; +pub type B = C; + +//- /lib.rs crate:a deps:b +pub use b::B; +pub type A = B; + +//- /main.rs crate:main deps:a +use a::A$0; +"#, + expect![[r#" + *A* + + ```rust + a + ``` + + ```rust + // size = 0, align = 1 + pub type A = B + ``` + + --- + + *This is the documentation for* `pub struct C` + + Docs for C + "#]], + ); +} diff --git a/src/tools/rust-analyzer/crates/ide/src/inlay_hints.rs b/src/tools/rust-analyzer/crates/ide/src/inlay_hints.rs index 97e712356b5..c58ca0f01cd 100644 --- a/src/tools/rust-analyzer/crates/ide/src/inlay_hints.rs +++ b/src/tools/rust-analyzer/crates/ide/src/inlay_hints.rs @@ -8,6 +8,7 @@ use hir::{ sym, ClosureStyle, HasVisibility, HirDisplay, HirDisplayError, HirWrite, ModuleDef, ModuleDefId, Semantics, }; +use ide_db::text_edit::TextEdit; use ide_db::{famous_defs::FamousDefs, FileRange, RootDatabase}; use itertools::Itertools; use smallvec::{smallvec, SmallVec}; @@ -17,7 +18,6 @@ use syntax::{ ast::{self, AstNode, HasGenericParams}, format_smolstr, match_ast, SmolStr, SyntaxNode, TextRange, TextSize, WalkEvent, }; -use text_edit::TextEdit; use crate::{navigation_target::TryToNav, FileId}; @@ -410,19 +410,6 @@ impl InlayHint { } } - fn opening_paren_before(kind: InlayKind, range: TextRange) -> InlayHint { - InlayHint { - range, - kind, - label: InlayHintLabel::from("("), - text_edit: None, - position: InlayHintPosition::Before, - pad_left: false, - pad_right: false, - resolve_parent: None, - } - } - pub fn needs_resolve(&self) -> Option<TextRange> { self.resolve_parent.filter(|_| self.text_edit.is_some() || self.label.needs_resolve()) } @@ -475,6 +462,18 @@ impl InlayHintLabel { } } + pub fn append_part(&mut self, part: InlayHintLabelPart) { + if part.linked_location.is_none() && part.tooltip.is_none() { + if let Some(InlayHintLabelPart { text, linked_location: None, tooltip: None }) = + self.parts.last_mut() + { + text.push_str(&part.text); + return; + } + } + self.parts.push(part); + } + pub fn needs_resolve(&self) -> bool { self.parts.iter().any(|part| part.linked_location.is_some() || part.tooltip.is_some()) } diff --git a/src/tools/rust-analyzer/crates/ide/src/inlay_hints/adjustment.rs b/src/tools/rust-analyzer/crates/ide/src/inlay_hints/adjustment.rs index c37c469dff4..4d7d6e270e0 100644 --- a/src/tools/rust-analyzer/crates/ide/src/inlay_hints/adjustment.rs +++ b/src/tools/rust-analyzer/crates/ide/src/inlay_hints/adjustment.rs @@ -3,12 +3,15 @@ //! let _: u32 = /* <never-to-any> */ loop {}; //! let _: &u32 = /* &* */ &mut 0; //! ``` +use std::ops::Not; + use either::Either; use hir::{ Adjust, Adjustment, AutoBorrow, HirDisplay, Mutability, OverloadedDeref, PointerCast, Safety, }; use ide_db::famous_defs::FamousDefs; +use ide_db::text_edit::TextEditBuilder; use span::EditionedFileId; use stdx::never; use syntax::{ @@ -17,8 +20,8 @@ use syntax::{ }; use crate::{ - AdjustmentHints, AdjustmentHintsMode, InlayHint, InlayHintLabel, InlayHintPosition, - InlayHintsConfig, InlayKind, InlayTooltip, + AdjustmentHints, AdjustmentHintsMode, InlayHint, InlayHintLabel, InlayHintLabelPart, + InlayHintPosition, InlayHintsConfig, InlayKind, InlayTooltip, }; pub(super) fn hints( @@ -51,32 +54,47 @@ pub(super) fn hints( let adjustments = sema.expr_adjustments(desc_expr).filter(|it| !it.is_empty())?; if let ast::Expr::BlockExpr(_) | ast::Expr::IfExpr(_) | ast::Expr::MatchExpr(_) = desc_expr { - if let [Adjustment { kind: Adjust::Deref(_), source, .. }, Adjustment { kind: Adjust::Borrow(_), source: _, target }] = - &*adjustments - { - // Don't show unnecessary reborrows for these, they will just repeat the inner ones again - if source == target { - return None; - } + // Don't show unnecessary reborrows for these, they will just repeat the inner ones again + if matches!( + &*adjustments, + [Adjustment { kind: Adjust::Deref(_), source, .. }, Adjustment { kind: Adjust::Borrow(_), target, .. }] + if source == target + ) { + return None; } } let (postfix, needs_outer_parens, needs_inner_parens) = mode_and_needs_parens_for_adjustment_hints(expr, config.adjustment_hints_mode); - if needs_outer_parens { - acc.push(InlayHint::opening_paren_before( - InlayKind::Adjustment, - expr.syntax().text_range(), - )); + let range = expr.syntax().text_range(); + let mut pre = InlayHint { + range, + position: InlayHintPosition::Before, + pad_left: false, + pad_right: false, + kind: InlayKind::Adjustment, + label: InlayHintLabel::default(), + text_edit: None, + resolve_parent: Some(range), + }; + let mut post = InlayHint { + range, + position: InlayHintPosition::After, + pad_left: false, + pad_right: false, + kind: InlayKind::Adjustment, + label: InlayHintLabel::default(), + text_edit: None, + resolve_parent: Some(range), + }; + + if needs_outer_parens || (postfix && needs_inner_parens) { + pre.label.append_str("("); } if postfix && needs_inner_parens { - acc.push(InlayHint::opening_paren_before( - InlayKind::Adjustment, - expr.syntax().text_range(), - )); - acc.push(InlayHint::closing_paren_after(InlayKind::Adjustment, expr.syntax().text_range())); + post.label.append_str(")"); } let mut iter = if postfix { @@ -86,6 +104,7 @@ pub(super) fn hints( }; let iter: &mut dyn Iterator<Item = _> = iter.as_mut().either(|it| it as _, |it| it as _); + let mut allow_edit = !postfix; for Adjustment { source, target, kind } in iter { if source == target { cov_mark::hit!(same_type_adjustment); @@ -95,6 +114,7 @@ pub(super) fn hints( // FIXME: Add some nicer tooltips to each of these let (text, coercion) = match kind { Adjust::NeverToAny if config.adjustment_hints == AdjustmentHints::Always => { + allow_edit = false; ("<never-to-any>", "never to any") } Adjust::Deref(None) => ("*", "dereference"), @@ -115,6 +135,7 @@ pub(super) fn hints( // some of these could be represented via `as` casts, but that's not too nice and // handling everything as a prefix expr makes the `(` and `)` insertion easier Adjust::Pointer(cast) if config.adjustment_hints == AdjustmentHints::Always => { + allow_edit = false; match cast { PointerCast::ReifyFnPointer => { ("<fn-item-to-fn-pointer>", "fn item to fn pointer") @@ -138,36 +159,58 @@ pub(super) fn hints( } _ => continue, }; - let label = InlayHintLabel::simple( - if postfix { format!(".{}", text.trim_end()) } else { text.to_owned() }, - Some(InlayTooltip::Markdown(format!( + let label = InlayHintLabelPart { + text: if postfix { format!(".{}", text.trim_end()) } else { text.to_owned() }, + linked_location: None, + tooltip: Some(InlayTooltip::Markdown(format!( "`{}` → `{}` ({coercion} coercion)", source.display(sema.db, file_id.edition()), target.display(sema.db, file_id.edition()), ))), - None, - ); - acc.push(InlayHint { - range: expr.syntax().text_range(), - pad_left: false, - pad_right: false, - position: if postfix { InlayHintPosition::After } else { InlayHintPosition::Before }, - kind: InlayKind::Adjustment, - label, - text_edit: None, - resolve_parent: Some(expr.syntax().text_range()), - }); + }; + if postfix { &mut post } else { &mut pre }.label.append_part(label); } if !postfix && needs_inner_parens { - acc.push(InlayHint::opening_paren_before( - InlayKind::Adjustment, - expr.syntax().text_range(), - )); - acc.push(InlayHint::closing_paren_after(InlayKind::Adjustment, expr.syntax().text_range())); + pre.label.append_str("("); + } + if needs_outer_parens || (!postfix && needs_inner_parens) { + post.label.append_str(")"); } - if needs_outer_parens { - acc.push(InlayHint::closing_paren_after(InlayKind::Adjustment, expr.syntax().text_range())); + + let mut pre = pre.label.parts.is_empty().not().then_some(pre); + let mut post = post.label.parts.is_empty().not().then_some(post); + if pre.is_none() && post.is_none() { + return None; } + if allow_edit { + let edit = { + let mut b = TextEditBuilder::default(); + if let Some(pre) = &pre { + b.insert( + pre.range.start(), + pre.label.parts.iter().map(|part| &*part.text).collect::<String>(), + ); + } + if let Some(post) = &post { + b.insert( + post.range.end(), + post.label.parts.iter().map(|part| &*part.text).collect::<String>(), + ); + } + b.finish() + }; + match (&mut pre, &mut post) { + (Some(pre), Some(post)) => { + pre.text_edit = Some(edit.clone()); + post.text_edit = Some(edit); + } + (Some(pre), None) => pre.text_edit = Some(edit), + (None, Some(post)) => post.text_edit = Some(edit), + (None, None) => (), + } + } + acc.extend(pre); + acc.extend(post); Some(()) } @@ -293,25 +336,19 @@ fn main() { let _: u32 = loop {}; //^^^^^^^<never-to-any> let _: &u32 = &mut 0; - //^^^^^^& - //^^^^^^* + //^^^^^^&* let _: &mut u32 = &mut 0; - //^^^^^^&mut $ - //^^^^^^* + //^^^^^^&mut * let _: *const u32 = &mut 0; - //^^^^^^&raw const $ - //^^^^^^* + //^^^^^^&raw const * let _: *mut u32 = &mut 0; - //^^^^^^&raw mut $ - //^^^^^^* + //^^^^^^&raw mut * let _: fn() = main; //^^^^<fn-item-to-fn-pointer> let _: unsafe fn() = main; - //^^^^<safe-fn-pointer-to-unsafe-fn-pointer> - //^^^^<fn-item-to-fn-pointer> + //^^^^<safe-fn-pointer-to-unsafe-fn-pointer><fn-item-to-fn-pointer> let _: unsafe fn() = main as fn(); - //^^^^^^^^^^^^<safe-fn-pointer-to-unsafe-fn-pointer> - //^^^^^^^^^^^^( + //^^^^^^^^^^^^<safe-fn-pointer-to-unsafe-fn-pointer>( //^^^^^^^^^^^^) //^^^^<fn-item-to-fn-pointer> let _: fn() = || {}; @@ -319,72 +356,51 @@ fn main() { let _: unsafe fn() = || {}; //^^^^^<closure-to-unsafe-fn-pointer> let _: *const u32 = &mut 0u32 as *mut u32; - //^^^^^^^^^^^^^^^^^^^^^<mut-ptr-to-const-ptr> - //^^^^^^^^^^^^^^^^^^^^^( + //^^^^^^^^^^^^^^^^^^^^^<mut-ptr-to-const-ptr>( //^^^^^^^^^^^^^^^^^^^^^) - //^^^^^^^^^&raw mut $ - //^^^^^^^^^* + //^^^^^^^^^&raw mut * let _: &mut [_] = &mut [0; 0]; - //^^^^^^^^^^^<unsize> - //^^^^^^^^^^^&mut $ - //^^^^^^^^^^^* + //^^^^^^^^^^^<unsize>&mut * Struct.consume(); Struct.by_ref(); - //^^^^^^( - //^^^^^^& + //^^^^^^(& //^^^^^^) Struct.by_ref_mut(); - //^^^^^^( - //^^^^^^&mut $ + //^^^^^^(&mut $ //^^^^^^) (&Struct).consume(); //^^^^^^^* (&Struct).by_ref(); - //^^^^^^^& - //^^^^^^^* + //^^^^^^^&* (&mut Struct).consume(); //^^^^^^^^^^^* (&mut Struct).by_ref(); - //^^^^^^^^^^^& - //^^^^^^^^^^^* + //^^^^^^^^^^^&* (&mut Struct).by_ref_mut(); - //^^^^^^^^^^^&mut $ - //^^^^^^^^^^^* + //^^^^^^^^^^^&mut * // Check that block-like expressions don't duplicate hints let _: &mut [u32] = (&mut []); - //^^^^^^^<unsize> - //^^^^^^^&mut $ - //^^^^^^^* + //^^^^^^^<unsize>&mut * let _: &mut [u32] = { &mut [] }; - //^^^^^^^<unsize> - //^^^^^^^&mut $ - //^^^^^^^* + //^^^^^^^<unsize>&mut * let _: &mut [u32] = unsafe { &mut [] }; - //^^^^^^^<unsize> - //^^^^^^^&mut $ - //^^^^^^^* + //^^^^^^^<unsize>&mut * let _: &mut [u32] = if true { &mut [] - //^^^^^^^<unsize> - //^^^^^^^&mut $ - //^^^^^^^* + //^^^^^^^<unsize>&mut * } else { loop {} //^^^^^^^<never-to-any> }; let _: &mut [u32] = match () { () => &mut [] }; - //^^^^^^^<unsize> - //^^^^^^^&mut $ - //^^^^^^^* + //^^^^^^^<unsize>&mut * let _: &mut dyn Fn() = &mut || (); - //^^^^^^^^^^<unsize> - //^^^^^^^^^^&mut $ - //^^^^^^^^^^* + //^^^^^^^^^^<unsize>&mut * () == (); // ^^& // ^^& @@ -393,16 +409,13 @@ fn main() { // ^^^^& let closure: dyn Fn = || (); closure(); - //^^^^^^^( - //^^^^^^^& + //^^^^^^^(& //^^^^^^^) Struct[0]; - //^^^^^^( - //^^^^^^& + //^^^^^^(& //^^^^^^) &mut Struct[0]; - //^^^^^^( - //^^^^^^&mut $ + //^^^^^^(&mut $ //^^^^^^) } @@ -442,72 +455,46 @@ fn main() { (&Struct).consume(); //^^^^^^^( - //^^^^^^^) - //^^^^^^^.* + //^^^^^^^).* (&Struct).by_ref(); //^^^^^^^( - //^^^^^^^) - //^^^^^^^.* - //^^^^^^^.& + //^^^^^^^).*.& (&mut Struct).consume(); //^^^^^^^^^^^( - //^^^^^^^^^^^) - //^^^^^^^^^^^.* + //^^^^^^^^^^^).* (&mut Struct).by_ref(); //^^^^^^^^^^^( - //^^^^^^^^^^^) - //^^^^^^^^^^^.* - //^^^^^^^^^^^.& + //^^^^^^^^^^^).*.& (&mut Struct).by_ref_mut(); //^^^^^^^^^^^( - //^^^^^^^^^^^) - //^^^^^^^^^^^.* - //^^^^^^^^^^^.&mut + //^^^^^^^^^^^).*.&mut // Check that block-like expressions don't duplicate hints let _: &mut [u32] = (&mut []); //^^^^^^^( - //^^^^^^^) - //^^^^^^^.* - //^^^^^^^.&mut - //^^^^^^^.<unsize> + //^^^^^^^).*.&mut.<unsize> let _: &mut [u32] = { &mut [] }; //^^^^^^^( - //^^^^^^^) - //^^^^^^^.* - //^^^^^^^.&mut - //^^^^^^^.<unsize> + //^^^^^^^).*.&mut.<unsize> let _: &mut [u32] = unsafe { &mut [] }; //^^^^^^^( - //^^^^^^^) - //^^^^^^^.* - //^^^^^^^.&mut - //^^^^^^^.<unsize> + //^^^^^^^).*.&mut.<unsize> let _: &mut [u32] = if true { &mut [] //^^^^^^^( - //^^^^^^^) - //^^^^^^^.* - //^^^^^^^.&mut - //^^^^^^^.<unsize> + //^^^^^^^).*.&mut.<unsize> } else { loop {} //^^^^^^^.<never-to-any> }; let _: &mut [u32] = match () { () => &mut [] }; //^^^^^^^( - //^^^^^^^) - //^^^^^^^.* - //^^^^^^^.&mut - //^^^^^^^.<unsize> + //^^^^^^^).*.&mut.<unsize> let _: &mut dyn Fn() = &mut || (); //^^^^^^^^^^( - //^^^^^^^^^^) - //^^^^^^^^^^.* - //^^^^^^^^^^.&mut - //^^^^^^^^^^.<unsize> + //^^^^^^^^^^).*.&mut.<unsize> () == (); // ^^.& // ^^.& @@ -619,9 +606,7 @@ fn or_else() { r#" unsafe fn enabled() { f(&&()); - //^^^^& - //^^^^* - //^^^^* + //^^^^&** } fn disabled() { @@ -633,9 +618,7 @@ fn mixed() { unsafe { f(&&()); - //^^^^& - //^^^^* - //^^^^* + //^^^^&** } } @@ -644,9 +627,7 @@ const _: () = { unsafe { f(&&()); - //^^^^& - //^^^^* - //^^^^* + //^^^^&** } }; @@ -655,18 +636,14 @@ static STATIC: () = { unsafe { f(&&()); - //^^^^& - //^^^^* - //^^^^* + //^^^^&** } }; enum E { Disable = { f(&&()); 0 }, Enable = unsafe { f(&&()); 1 }, - //^^^^& - //^^^^* - //^^^^* + //^^^^&** } const fn f(_: &()) {} @@ -692,8 +669,7 @@ fn a() { _ = Struct.by_ref(); _ = unsafe { Struct.by_ref() }; - //^^^^^^( - //^^^^^^& + //^^^^^^(& //^^^^^^) } "#, @@ -726,10 +702,7 @@ trait T<RHS = Self> {} fn hello(it: &&[impl T]) { it.len(); - //^^( - //^^& - //^^* - //^^* + //^^(&** //^^) } "#, diff --git a/src/tools/rust-analyzer/crates/ide/src/inlay_hints/binding_mode.rs b/src/tools/rust-analyzer/crates/ide/src/inlay_hints/binding_mode.rs index d1c0677863d..cfe8657fd05 100644 --- a/src/tools/rust-analyzer/crates/ide/src/inlay_hints/binding_mode.rs +++ b/src/tools/rust-analyzer/crates/ide/src/inlay_hints/binding_mode.rs @@ -2,13 +2,16 @@ //! ```no_run //! let /* & */ (/* ref */ x,) = &(0,); //! ``` +use std::mem; + use hir::Mutability; use ide_db::famous_defs::FamousDefs; +use ide_db::text_edit::TextEditBuilder; use span::EditionedFileId; use syntax::ast::{self, AstNode}; -use crate::{InlayHint, InlayHintPosition, InlayHintsConfig, InlayKind}; +use crate::{InlayHint, InlayHintLabel, InlayHintPosition, InlayHintsConfig, InlayKind}; pub(super) fn hints( acc: &mut Vec<InlayHint>, @@ -21,16 +24,7 @@ pub(super) fn hints( return None; } - let outer_paren_pat = pat - .syntax() - .ancestors() - .skip(1) - .map_while(ast::Pat::cast) - .map_while(|pat| match pat { - ast::Pat::ParenPat(pat) => Some(pat), - _ => None, - }) - .last(); + let outer_paren_pat = pat.syntax().ancestors().skip(1).map_while(ast::ParenPat::cast).last(); let range = outer_paren_pat.as_ref().map_or_else( || match pat { // for ident patterns that @ bind a name, render the un-ref patterns in front of the inner pattern @@ -42,7 +36,18 @@ pub(super) fn hints( }, |it| it.syntax().text_range(), ); + let mut hint = InlayHint { + range, + kind: InlayKind::BindingMode, + label: InlayHintLabel::default(), + text_edit: None, + position: InlayHintPosition::Before, + pad_left: false, + pad_right: false, + resolve_parent: Some(pat.syntax().text_range()), + }; let pattern_adjustments = sema.pattern_adjustments(pat); + let mut was_mut_last = false; pattern_adjustments.iter().for_each(|ty| { let reference = ty.is_reference(); let mut_reference = ty.is_mutable_reference(); @@ -51,41 +56,36 @@ pub(super) fn hints( (true, false) => "&", _ => return, }; - acc.push(InlayHint { - range, - kind: InlayKind::BindingMode, - label: r.into(), - text_edit: None, - position: InlayHintPosition::Before, - pad_left: false, - pad_right: mut_reference, - resolve_parent: Some(pat.syntax().text_range()), - }); + if mem::replace(&mut was_mut_last, mut_reference) { + hint.label.append_str(" "); + } + hint.label.append_str(r); }); + hint.pad_right = was_mut_last; + let acc_base = acc.len(); match pat { ast::Pat::IdentPat(pat) if pat.ref_token().is_none() && pat.mut_token().is_none() => { let bm = sema.binding_mode_of_pat(pat)?; let bm = match bm { - hir::BindingMode::Move => return None, - hir::BindingMode::Ref(Mutability::Mut) => "ref mut", - hir::BindingMode::Ref(Mutability::Shared) => "ref", + hir::BindingMode::Move => None, + hir::BindingMode::Ref(Mutability::Mut) => Some("ref mut"), + hir::BindingMode::Ref(Mutability::Shared) => Some("ref"), }; - acc.push(InlayHint { - range: pat.syntax().text_range(), - kind: InlayKind::BindingMode, - label: bm.into(), - text_edit: None, - position: InlayHintPosition::Before, - pad_left: false, - pad_right: true, - resolve_parent: Some(pat.syntax().text_range()), - }); + if let Some(bm) = bm { + acc.push(InlayHint { + range: pat.syntax().text_range(), + kind: InlayKind::BindingMode, + label: bm.into(), + text_edit: None, + position: InlayHintPosition::Before, + pad_left: false, + pad_right: true, + resolve_parent: Some(pat.syntax().text_range()), + }); + } } ast::Pat::OrPat(pat) if !pattern_adjustments.is_empty() && outer_paren_pat.is_none() => { - acc.push(InlayHint::opening_paren_before( - InlayKind::BindingMode, - pat.syntax().text_range(), - )); + hint.label.append_str("("); acc.push(InlayHint::closing_paren_after( InlayKind::BindingMode, pat.syntax().text_range(), @@ -93,6 +93,24 @@ pub(super) fn hints( } _ => (), } + if !hint.label.parts.is_empty() { + acc.push(hint); + } + + if let hints @ [_, ..] = &mut acc[acc_base..] { + let mut edit = TextEditBuilder::default(); + for h in &mut *hints { + edit.insert( + match h.position { + InlayHintPosition::Before => h.range.start(), + InlayHintPosition::After => h.range.end(), + }, + h.label.parts.iter().map(|p| &*p.text).collect(), + ); + } + let edit = edit.finish(); + hints.iter_mut().for_each(|h| h.text_edit = Some(edit.clone())); + } Some(()) } @@ -117,6 +135,13 @@ fn __( (x,): &mut (u32,) //^^^^&mut //^ ref mut + (x,): &mut &mut (u32,) + //^^^^&mut &mut + //^ ref mut + (x,): &&(u32,) + //^^^^&& + //^ ref + ) { let (x,) = (0,); let (x,) = &(0,); @@ -136,11 +161,10 @@ fn __( } match &(0,) { (x,) | (x,) => (), - //^^^^^^^^^^^& + //^^^^^^^^^^^) + //^^^^^^^^^^^&( //^ ref //^ ref - //^^^^^^^^^^^( - //^^^^^^^^^^^) ((x,) | (x,)) => (), //^^^^^^^^^^^^^& //^ ref diff --git a/src/tools/rust-analyzer/crates/ide/src/inlay_hints/chaining.rs b/src/tools/rust-analyzer/crates/ide/src/inlay_hints/chaining.rs index 58d8f97a8ce..028ed1650f4 100644 --- a/src/tools/rust-analyzer/crates/ide/src/inlay_hints/chaining.rs +++ b/src/tools/rust-analyzer/crates/ide/src/inlay_hints/chaining.rs @@ -77,7 +77,7 @@ pub(super) fn hints( #[cfg(test)] mod tests { use expect_test::{expect, Expect}; - use text_edit::{TextRange, TextSize}; + use ide_db::text_edit::{TextRange, TextSize}; use crate::{ fixture, diff --git a/src/tools/rust-analyzer/crates/ide/src/inlay_hints/closure_captures.rs b/src/tools/rust-analyzer/crates/ide/src/inlay_hints/closure_captures.rs index f399bd01d07..906f2acf0c4 100644 --- a/src/tools/rust-analyzer/crates/ide/src/inlay_hints/closure_captures.rs +++ b/src/tools/rust-analyzer/crates/ide/src/inlay_hints/closure_captures.rs @@ -2,12 +2,14 @@ //! //! Tests live in [`bind_pat`][super::bind_pat] module. use ide_db::famous_defs::FamousDefs; +use ide_db::text_edit::{TextRange, TextSize}; use span::EditionedFileId; use stdx::{never, TupleExt}; use syntax::ast::{self, AstNode}; -use text_edit::{TextRange, TextSize}; -use crate::{InlayHint, InlayHintLabel, InlayHintPosition, InlayHintsConfig, InlayKind}; +use crate::{ + InlayHint, InlayHintLabel, InlayHintLabelPart, InlayHintPosition, InlayHintsConfig, InlayKind, +}; pub(super) fn hints( acc: &mut Vec<InlayHint>, @@ -27,34 +29,27 @@ pub(super) fn hints( return None; } - let move_kw_range = match closure.move_token() { - Some(t) => t.text_range(), + let (range, label) = match closure.move_token() { + Some(t) => (t.text_range(), InlayHintLabel::default()), None => { - let range = closure.syntax().first_token()?.prev_token()?.text_range(); - let range = TextRange::new(range.end() - TextSize::from(1), range.end()); - acc.push(InlayHint { - range, - kind: InlayKind::ClosureCapture, - label: InlayHintLabel::from("move"), - text_edit: None, - position: InlayHintPosition::After, - pad_left: false, - pad_right: false, - resolve_parent: Some(closure.syntax().text_range()), - }); - range + let prev_token = closure.syntax().first_token()?.prev_token()?.text_range(); + ( + TextRange::new(prev_token.end() - TextSize::from(1), prev_token.end()), + InlayHintLabel::from("move"), + ) } }; - acc.push(InlayHint { - range: move_kw_range, + let mut hint = InlayHint { + range, kind: InlayKind::ClosureCapture, - label: InlayHintLabel::from("("), + label, text_edit: None, position: InlayHintPosition::After, pad_left: false, - pad_right: false, - resolve_parent: None, - }); + pad_right: true, + resolve_parent: Some(closure.syntax().text_range()), + }; + hint.label.append_str("("); let last = captures.len() - 1; for (idx, capture) in captures.into_iter().enumerate() { let local = capture.local(); @@ -76,48 +71,20 @@ pub(super) fn hints( if never!(label.is_empty()) { continue; } - let label = InlayHintLabel::simple( - label, - None, - source.name().and_then(|name| { + hint.label.append_part(InlayHintLabelPart { + text: label, + linked_location: source.name().and_then(|name| { name.syntax().original_file_range_opt(sema.db).map(TupleExt::head).map(Into::into) }), - ); - acc.push(InlayHint { - range: move_kw_range, - kind: InlayKind::ClosureCapture, - label, - text_edit: None, - position: InlayHintPosition::After, - pad_left: false, - pad_right: false, - resolve_parent: Some(closure.syntax().text_range()), + tooltip: None, }); if idx != last { - acc.push(InlayHint { - range: move_kw_range, - kind: InlayKind::ClosureCapture, - label: InlayHintLabel::from(", "), - text_edit: None, - position: InlayHintPosition::After, - pad_left: false, - pad_right: false, - resolve_parent: None, - }); + hint.label.append_str(", "); } } - acc.push(InlayHint { - range: move_kw_range, - kind: InlayKind::ClosureCapture, - label: InlayHintLabel::from(")"), - text_edit: None, - position: InlayHintPosition::After, - pad_left: false, - pad_right: true, - resolve_parent: None, - }); - + hint.label.append_str(")"); + acc.push(hint); Some(()) } @@ -147,51 +114,25 @@ fn main() { let mut baz = NonCopy; let qux = &mut NonCopy; || { -// ^ move -// ^ ( -// ^ &foo -// ^ , $ -// ^ bar -// ^ , $ -// ^ baz -// ^ , $ -// ^ qux -// ^ ) +// ^ move(&foo, bar, baz, qux) foo; bar; baz; qux; }; || { -// ^ move -// ^ ( -// ^ &foo -// ^ , $ -// ^ &bar -// ^ , $ -// ^ &baz -// ^ , $ -// ^ &qux -// ^ ) +// ^ move(&foo, &bar, &baz, &qux) &foo; &bar; &baz; &qux; }; || { -// ^ move -// ^ ( -// ^ &mut baz -// ^ ) +// ^ move(&mut baz) &mut baz; }; || { -// ^ move -// ^ ( -// ^ &mut baz -// ^ , $ -// ^ &mut *qux -// ^ ) +// ^ move(&mut baz, &mut *qux) baz = NonCopy; *qux = NonCopy; }; @@ -209,9 +150,7 @@ fn main() { fn main() { let foo = u32; move || { -// ^^^^ ( -// ^^^^ foo -// ^^^^ ) +// ^^^^ (foo) foo; }; } diff --git a/src/tools/rust-analyzer/crates/ide/src/inlay_hints/discriminant.rs b/src/tools/rust-analyzer/crates/ide/src/inlay_hints/discriminant.rs index 35b62878329..cd77c3ec3e9 100644 --- a/src/tools/rust-analyzer/crates/ide/src/inlay_hints/discriminant.rs +++ b/src/tools/rust-analyzer/crates/ide/src/inlay_hints/discriminant.rs @@ -5,6 +5,7 @@ //! } //! ``` use hir::Semantics; +use ide_db::text_edit::TextEdit; use ide_db::{famous_defs::FamousDefs, RootDatabase}; use span::EditionedFileId; use syntax::ast::{self, AstNode, HasName}; @@ -65,11 +66,11 @@ fn variant_hints( let eq_ = if eq_token.is_none() { " =" } else { "" }; let label = InlayHintLabel::simple( match d { - Ok(x) => { - if x >= 10 { - format!("{eq_} {x} ({x:#X})") + Ok(val) => { + if val >= 10 { + format!("{eq_} {val} ({val:#X})") } else { - format!("{eq_} {x}") + format!("{eq_} {val}") } } Err(_) => format!("{eq_} ?"), @@ -87,7 +88,7 @@ fn variant_hints( }, kind: InlayKind::Discriminant, label, - text_edit: None, + text_edit: d.ok().map(|val| TextEdit::insert(range.start(), format!("{eq_} {val}"))), position: InlayHintPosition::After, pad_left: false, pad_right: false, diff --git a/src/tools/rust-analyzer/crates/ide/src/inlay_hints/implicit_static.rs b/src/tools/rust-analyzer/crates/ide/src/inlay_hints/implicit_static.rs index 8d422478cbf..1560df37d0d 100644 --- a/src/tools/rust-analyzer/crates/ide/src/inlay_hints/implicit_static.rs +++ b/src/tools/rust-analyzer/crates/ide/src/inlay_hints/implicit_static.rs @@ -4,6 +4,7 @@ //! ``` use either::Either; use ide_db::famous_defs::FamousDefs; +use ide_db::text_edit::TextEdit; use span::EditionedFileId; use syntax::{ ast::{self, AstNode}, @@ -38,7 +39,7 @@ pub(super) fn hints( range: t.text_range(), kind: InlayKind::Lifetime, label: "'static".into(), - text_edit: None, + text_edit: Some(TextEdit::insert(t.text_range().start(), "'static ".into())), position: InlayHintPosition::After, pad_left: false, pad_right: true, diff --git a/src/tools/rust-analyzer/crates/ide/src/join_lines.rs b/src/tools/rust-analyzer/crates/ide/src/join_lines.rs index 9d8ba90b2ff..5192f91a4a6 100644 --- a/src/tools/rust-analyzer/crates/ide/src/join_lines.rs +++ b/src/tools/rust-analyzer/crates/ide/src/join_lines.rs @@ -8,7 +8,7 @@ use syntax::{ SyntaxToken, TextRange, TextSize, T, }; -use text_edit::{TextEdit, TextEditBuilder}; +use ide_db::text_edit::{TextEdit, TextEditBuilder}; pub struct JoinLinesConfig { pub join_else_if: bool, diff --git a/src/tools/rust-analyzer/crates/ide/src/lib.rs b/src/tools/rust-analyzer/crates/ide/src/lib.rs index d7163d57d22..d053c4b3c93 100644 --- a/src/tools/rust-analyzer/crates/ide/src/lib.rs +++ b/src/tools/rust-analyzer/crates/ide/src/lib.rs @@ -122,6 +122,7 @@ pub use ide_completion::{ CallableSnippets, CompletionConfig, CompletionFieldsToResolve, CompletionItem, CompletionItemKind, CompletionRelevance, Snippet, SnippetScope, }; +pub use ide_db::text_edit::{Indel, TextEdit}; pub use ide_db::{ base_db::{Cancelled, CrateGraph, CrateId, FileChange, SourceRoot, SourceRootId}, documentation::Documentation, @@ -139,7 +140,6 @@ pub use ide_diagnostics::{ pub use ide_ssr::SsrError; pub use span::Edition; pub use syntax::{TextRange, TextSize}; -pub use text_edit::{Indel, TextEdit}; pub type Cancellable<T> = Result<T, Cancelled>; diff --git a/src/tools/rust-analyzer/crates/ide/src/move_item.rs b/src/tools/rust-analyzer/crates/ide/src/move_item.rs index ea6cc9d6de2..a232df2b82b 100644 --- a/src/tools/rust-analyzer/crates/ide/src/move_item.rs +++ b/src/tools/rust-analyzer/crates/ide/src/move_item.rs @@ -1,10 +1,11 @@ use std::{iter::once, mem}; use hir::Semantics; +use ide_db::syntax_helpers::tree_diff::diff; +use ide_db::text_edit::{TextEdit, TextEditBuilder}; use ide_db::{helpers::pick_best_token, FileRange, RootDatabase}; use itertools::Itertools; -use syntax::{algo, ast, match_ast, AstNode, SyntaxElement, SyntaxKind, SyntaxNode, TextRange}; -use text_edit::{TextEdit, TextEditBuilder}; +use syntax::{ast, match_ast, AstNode, SyntaxElement, SyntaxKind, SyntaxNode, TextRange}; #[derive(Copy, Clone, Debug)] pub enum Direction { @@ -166,7 +167,7 @@ fn replace_nodes<'a>( let mut edit = TextEditBuilder::default(); - algo::diff(first, second).into_text_edit(&mut edit); + diff(first, second).into_text_edit(&mut edit); edit.replace(second.text_range(), first_with_cursor); edit.finish() diff --git a/src/tools/rust-analyzer/crates/ide/src/references.rs b/src/tools/rust-analyzer/crates/ide/src/references.rs index e7cb8a253f4..339315db571 100644 --- a/src/tools/rust-analyzer/crates/ide/src/references.rs +++ b/src/tools/rust-analyzer/crates/ide/src/references.rs @@ -1701,14 +1701,14 @@ fn f() { } "#, expect![[r#" - func Function FileId(0) 137..146 140..144 + func Function FileId(0) 137..146 140..144 module - FileId(0) 161..165 + FileId(0) 181..185 - func Function FileId(0) 137..146 140..144 module + func Function FileId(0) 137..146 140..144 - FileId(0) 181..185 + FileId(0) 161..165 "#]], ) } diff --git a/src/tools/rust-analyzer/crates/ide/src/rename.rs b/src/tools/rust-analyzer/crates/ide/src/rename.rs index f17c1fa5c62..665fc954d23 100644 --- a/src/tools/rust-analyzer/crates/ide/src/rename.rs +++ b/src/tools/rust-analyzer/crates/ide/src/rename.rs @@ -15,7 +15,7 @@ use itertools::Itertools; use stdx::{always, never}; use syntax::{ast, AstNode, SyntaxKind, SyntaxNode, TextRange, TextSize}; -use text_edit::TextEdit; +use ide_db::text_edit::TextEdit; use crate::{FilePosition, RangeInfo, SourceChange}; @@ -449,9 +449,9 @@ fn text_edit_from_self_param(self_param: &ast::SelfParam, new_name: &str) -> Opt mod tests { use expect_test::{expect, Expect}; use ide_db::source_change::SourceChange; + use ide_db::text_edit::TextEdit; use stdx::trim_indent; use test_utils::assert_eq_text; - use text_edit::TextEdit; use crate::fixture; diff --git a/src/tools/rust-analyzer/crates/ide/src/syntax_highlighting.rs b/src/tools/rust-analyzer/crates/ide/src/syntax_highlighting.rs index 961b2a4c938..0747d1b404b 100644 --- a/src/tools/rust-analyzer/crates/ide/src/syntax_highlighting.rs +++ b/src/tools/rust-analyzer/crates/ide/src/syntax_highlighting.rs @@ -16,7 +16,7 @@ mod tests; use std::ops::ControlFlow; use hir::{InRealFile, Name, Semantics}; -use ide_db::{FxHashMap, RootDatabase, SymbolKind}; +use ide_db::{FxHashMap, Ranker, RootDatabase, SymbolKind}; use span::EditionedFileId; use syntax::{ ast::{self, IsString}, @@ -397,13 +397,12 @@ fn traverse( Some(AttrOrDerive::Derive(_)) => inside_attribute, None => false, }; + let descended_element = if in_macro { // Attempt to descend tokens into macro-calls. let res = match element { NodeOrToken::Token(token) if token.kind() != COMMENT => { - let kind = token.kind(); - let text = token.text(); - let ident_kind = kind.is_any_identifier(); + let ranker = Ranker::from_token(&token); let mut t = None; let mut r = 0; @@ -412,21 +411,9 @@ fn traverse( |tok, _ctx| { // FIXME: Consider checking ctx transparency for being opaque? let tok = tok.value; - let tok_kind = tok.kind(); - - let exact_same_kind = tok_kind == kind; - let both_idents = - exact_same_kind || (tok_kind.is_any_identifier() && ident_kind); - let same_text = tok.text() == text; - // anything that mapped into a token tree has likely no semantic information - let no_tt_parent = - tok.parent().map_or(false, |it| it.kind() != TOKEN_TREE); - let my_rank = (both_idents as usize) - | ((exact_same_kind as usize) << 1) - | ((same_text as usize) << 2) - | ((no_tt_parent as usize) << 3); - - if my_rank > 0b1110 { + let my_rank = ranker.rank_token(&tok); + + if my_rank >= Ranker::MAX_RANK { // a rank of 0b1110 means that we have found a maximally interesting // token so stop early. t = Some(tok); diff --git a/src/tools/rust-analyzer/crates/ide/src/syntax_highlighting/test_data/highlight_issue_18089.html b/src/tools/rust-analyzer/crates/ide/src/syntax_highlighting/test_data/highlight_issue_18089.html index d07ba74db24..361dcd1bc37 100644 --- a/src/tools/rust-analyzer/crates/ide/src/syntax_highlighting/test_data/highlight_issue_18089.html +++ b/src/tools/rust-analyzer/crates/ide/src/syntax_highlighting/test_data/highlight_issue_18089.html @@ -50,4 +50,4 @@ pre { color: #DCDCCC; background: #3F3F3F; font-size: 22px; padd <span class="brace">}</span> <span class="attribute_bracket attribute">#</span><span class="attribute_bracket attribute">[</span><span class="module attribute crate_root library">proc_macros</span><span class="operator attribute">::</span><span class="attribute attribute library">issue_18089</span><span class="attribute_bracket attribute">]</span> -<span class="keyword">fn</span> <span class="function declaration">template</span><span class="parenthesis">(</span><span class="parenthesis">)</span> <span class="brace">{</span><span class="brace">}</span></code></pre> \ No newline at end of file +<span class="keyword">fn</span> <span class="macro declaration">template</span><span class="parenthesis">(</span><span class="parenthesis">)</span> <span class="brace">{</span><span class="brace">}</span></code></pre> \ No newline at end of file diff --git a/src/tools/rust-analyzer/crates/ide/src/typing.rs b/src/tools/rust-analyzer/crates/ide/src/typing.rs index a09e1e85ae1..9bb5de9f2e3 100644 --- a/src/tools/rust-analyzer/crates/ide/src/typing.rs +++ b/src/tools/rust-analyzer/crates/ide/src/typing.rs @@ -23,7 +23,7 @@ use syntax::{ AstNode, Parse, SourceFile, SyntaxKind, TextRange, TextSize, T, }; -use text_edit::{Indel, TextEdit}; +use ide_db::text_edit::TextEdit; use crate::SourceChange; @@ -126,7 +126,7 @@ fn on_opening_bracket_typed( return None; } // FIXME: Edition - let file = file.reparse(&Indel::delete(range), span::Edition::CURRENT_FIXME); + let file = file.reparse(range, "", span::Edition::CURRENT_FIXME); if let Some(edit) = bracket_expr(&file.tree(), offset, opening_bracket, closing_bracket) { return Some(edit); diff --git a/src/tools/rust-analyzer/crates/ide/src/typing/on_enter.rs b/src/tools/rust-analyzer/crates/ide/src/typing/on_enter.rs index 6e56bd61850..773e352220e 100644 --- a/src/tools/rust-analyzer/crates/ide/src/typing/on_enter.rs +++ b/src/tools/rust-analyzer/crates/ide/src/typing/on_enter.rs @@ -12,7 +12,7 @@ use syntax::{ SyntaxNode, SyntaxToken, TextRange, TextSize, TokenAtOffset, }; -use text_edit::TextEdit; +use ide_db::text_edit::TextEdit; // Feature: On Enter // diff --git a/src/tools/rust-analyzer/crates/parser/src/grammar/generic_params.rs b/src/tools/rust-analyzer/crates/parser/src/grammar/generic_params.rs index ecfabca092c..92311238c23 100644 --- a/src/tools/rust-analyzer/crates/parser/src/grammar/generic_params.rs +++ b/src/tools/rust-analyzer/crates/parser/src/grammar/generic_params.rs @@ -144,10 +144,31 @@ fn type_bound(p: &mut Parser<'_>) -> bool { LIFETIME_IDENT => lifetime(p), T![for] => types::for_type(p, false), // test precise_capturing - // fn captures<'a: 'a, 'b: 'b, T>() -> impl Sized + use<'b, T> {} + // fn captures<'a: 'a, 'b: 'b, T>() -> impl Sized + use<'b, T, Self> {} T![use] if p.nth_at(1, T![<]) => { p.bump_any(); - generic_param_list(p) + let m = p.start(); + delimited( + p, + T![<], + T![>], + T![,], + || "expected identifier or lifetime".into(), + TokenSet::new(&[T![Self], IDENT, LIFETIME_IDENT]), + |p| { + if p.at(T![Self]) { + let m = p.start(); + p.bump(T![Self]); + m.complete(p, NAME_REF); + } else if p.at(LIFETIME_IDENT) { + lifetime(p); + } else { + name_ref(p); + } + true + }, + ); + m.complete(p, USE_BOUND_GENERIC_ARGS); } T![?] if p.nth_at(1, T![for]) => { // test question_for_type_trait_bound diff --git a/src/tools/rust-analyzer/crates/parser/src/grammar/patterns.rs b/src/tools/rust-analyzer/crates/parser/src/grammar/patterns.rs index 882c243b0cd..ed01fca2acd 100644 --- a/src/tools/rust-analyzer/crates/parser/src/grammar/patterns.rs +++ b/src/tools/rust-analyzer/crates/parser/src/grammar/patterns.rs @@ -21,7 +21,8 @@ const RANGE_PAT_END_FIRST: TokenSet = expressions::LITERAL_FIRST.union(paths::PATH_FIRST).union(TokenSet::new(&[T![-], T![const]])); pub(crate) fn pattern(p: &mut Parser<'_>) { - pattern_r(p, PAT_RECOVERY_SET); + let m = p.start(); + pattern_r(p, m, false, PAT_RECOVERY_SET); } /// Parses a pattern list separated by pipes `|`. @@ -36,13 +37,11 @@ pub(crate) fn pattern_single(p: &mut Parser<'_>) { /// Parses a pattern list separated by pipes `|` /// using the given `recovery_set`. pub(super) fn pattern_top_r(p: &mut Parser<'_>, recovery_set: TokenSet) { - p.eat(T![|]); - pattern_r(p, recovery_set); + let m = p.start(); + let has_leading_pipe = p.eat(T![|]); + pattern_r(p, m, has_leading_pipe, recovery_set); } -/// Parses a pattern list separated by pipes `|`, with no leading `|`,using the -/// given `recovery_set`. - // test or_pattern // fn main() { // match () { @@ -52,11 +51,12 @@ pub(super) fn pattern_top_r(p: &mut Parser<'_>, recovery_set: TokenSet) { // [_ | _,] => (), // } // } -fn pattern_r(p: &mut Parser<'_>, recovery_set: TokenSet) { - let m = p.start(); +/// Parses a pattern list separated by pipes `|`, with no leading `|`,using the +/// given `recovery_set`. +fn pattern_r(p: &mut Parser<'_>, m: Marker, has_leading_pipe: bool, recovery_set: TokenSet) { pattern_single_r(p, recovery_set); - if !p.at(T![|]) { + if !p.at(T![|]) && !has_leading_pipe { m.abandon(p); return; } diff --git a/src/tools/rust-analyzer/crates/parser/src/lexed_str.rs b/src/tools/rust-analyzer/crates/parser/src/lexed_str.rs index 5322463a713..3c0eb1b42a6 100644 --- a/src/tools/rust-analyzer/crates/parser/src/lexed_str.rs +++ b/src/tools/rust-analyzer/crates/parser/src/lexed_str.rs @@ -39,7 +39,9 @@ impl<'a> LexedStr<'a> { conv.offset = shebang_len; }; - for token in rustc_lexer::tokenize(&text[conv.offset..]) { + // Re-create the tokenizer from scratch every token because `GuardedStrPrefix` is one token in the lexer + // but we want to split it to two in edition <2024. + while let Some(token) = rustc_lexer::tokenize(&text[conv.offset..]).next() { let token_text = &text[conv.offset..][..token.len as usize]; conv.extend_token(&token.kind, token_text); @@ -158,7 +160,7 @@ impl<'a> Converter<'a> { } } - fn extend_token(&mut self, kind: &rustc_lexer::TokenKind, token_text: &str) { + fn extend_token(&mut self, kind: &rustc_lexer::TokenKind, mut token_text: &str) { // A note on an intended tradeoff: // We drop some useful information here (see patterns with double dots `..`) // Storing that info in `SyntaxKind` is not possible due to its layout requirements of @@ -189,10 +191,15 @@ impl<'a> Converter<'a> { rustc_lexer::TokenKind::RawIdent => IDENT, rustc_lexer::TokenKind::GuardedStrPrefix if self.edition.at_least_2024() => { + // FIXME: rustc does something better for recovery. err = "Invalid string literal (reserved syntax)"; ERROR } - rustc_lexer::TokenKind::GuardedStrPrefix => POUND, + rustc_lexer::TokenKind::GuardedStrPrefix => { + // The token is `#"` or `##`, split it into two. + token_text = &token_text[1..]; + POUND + } rustc_lexer::TokenKind::Literal { kind, .. } => { self.extend_literal(token_text.len(), kind); diff --git a/src/tools/rust-analyzer/crates/parser/src/syntax_kind/generated.rs b/src/tools/rust-analyzer/crates/parser/src/syntax_kind/generated.rs index 8da338c0a2c..21730244a33 100644 --- a/src/tools/rust-analyzer/crates/parser/src/syntax_kind/generated.rs +++ b/src/tools/rust-analyzer/crates/parser/src/syntax_kind/generated.rs @@ -312,6 +312,8 @@ pub enum SyntaxKind { UNDERSCORE_EXPR, UNION, USE, + USE_BOUND_GENERIC_ARG, + USE_BOUND_GENERIC_ARGS, USE_TREE, USE_TREE_LIST, VARIANT, diff --git a/src/tools/rust-analyzer/crates/parser/src/tests.rs b/src/tools/rust-analyzer/crates/parser/src/tests.rs index e7bccb6685c..4b19ddc752a 100644 --- a/src/tools/rust-analyzer/crates/parser/src/tests.rs +++ b/src/tools/rust-analyzer/crates/parser/src/tests.rs @@ -15,11 +15,20 @@ use crate::{Edition, LexedStr, TopEntryPoint}; #[path = "../test_data/generated/runner.rs"] mod runner; +fn infer_edition(file_path: &Path) -> Edition { + let file_content = std::fs::read_to_string(file_path).unwrap(); + if let Some(edition) = file_content.strip_prefix("//@ edition: ") { + edition[..4].parse().expect("invalid edition directive") + } else { + Edition::CURRENT + } +} + #[test] fn lex_ok() { for case in TestCase::list("lexer/ok") { let _guard = stdx::panic_context::enter(format!("{:?}", case.rs)); - let actual = lex(&case.text); + let actual = lex(&case.text, infer_edition(&case.rs)); expect_file![case.rast].assert_eq(&actual) } } @@ -28,13 +37,13 @@ fn lex_ok() { fn lex_err() { for case in TestCase::list("lexer/err") { let _guard = stdx::panic_context::enter(format!("{:?}", case.rs)); - let actual = lex(&case.text); + let actual = lex(&case.text, infer_edition(&case.rs)); expect_file![case.rast].assert_eq(&actual) } } -fn lex(text: &str) -> String { - let lexed = LexedStr::new(Edition::CURRENT, text); +fn lex(text: &str, edition: Edition) -> String { + let lexed = LexedStr::new(edition, text); let mut res = String::new(); for i in 0..lexed.len() { diff --git a/src/tools/rust-analyzer/crates/parser/src/tests/top_entries.rs b/src/tools/rust-analyzer/crates/parser/src/tests/top_entries.rs index c56bf0b6448..7076e03ba4b 100644 --- a/src/tools/rust-analyzer/crates/parser/src/tests/top_entries.rs +++ b/src/tools/rust-analyzer/crates/parser/src/tests/top_entries.rs @@ -195,6 +195,38 @@ fn macro_pattern() { error 0: expected pattern "#]], ); + + check( + TopEntryPoint::Pattern, + "| 42 | 43", + expect![[r#" + OR_PAT + PIPE "|" + WHITESPACE " " + LITERAL_PAT + LITERAL + INT_NUMBER "42" + WHITESPACE " " + PIPE "|" + WHITESPACE " " + LITERAL_PAT + LITERAL + INT_NUMBER "43" + "#]], + ); + + check( + TopEntryPoint::Pattern, + "| 42", + expect![[r#" + OR_PAT + PIPE "|" + WHITESPACE " " + LITERAL_PAT + LITERAL + INT_NUMBER "42" + "#]], + ); } #[test] diff --git a/src/tools/rust-analyzer/crates/parser/test_data/lexer/ok/guarded_str_prefix_edition_2021.rast b/src/tools/rust-analyzer/crates/parser/test_data/lexer/ok/guarded_str_prefix_edition_2021.rast new file mode 100644 index 00000000000..1bdd6720441 --- /dev/null +++ b/src/tools/rust-analyzer/crates/parser/test_data/lexer/ok/guarded_str_prefix_edition_2021.rast @@ -0,0 +1,4 @@ +COMMENT "//@ edition: 2021" +WHITESPACE "\n\n" +POUND "#" +STRING "\"foo\"" diff --git a/src/tools/rust-analyzer/crates/parser/test_data/lexer/ok/guarded_str_prefix_edition_2021.rs b/src/tools/rust-analyzer/crates/parser/test_data/lexer/ok/guarded_str_prefix_edition_2021.rs new file mode 100644 index 00000000000..f00f949f0db --- /dev/null +++ b/src/tools/rust-analyzer/crates/parser/test_data/lexer/ok/guarded_str_prefix_edition_2021.rs @@ -0,0 +1,3 @@ +//@ edition: 2021 + +#"foo" \ No newline at end of file diff --git a/src/tools/rust-analyzer/crates/parser/test_data/parser/inline/ok/match_arm.rast b/src/tools/rust-analyzer/crates/parser/test_data/parser/inline/ok/match_arm.rast index 8189cf0a8e5..92210281629 100644 --- a/src/tools/rust-analyzer/crates/parser/test_data/parser/inline/ok/match_arm.rast +++ b/src/tools/rust-analyzer/crates/parser/test_data/parser/inline/ok/match_arm.rast @@ -102,9 +102,9 @@ SOURCE_FILE COMMA "," WHITESPACE "\n " MATCH_ARM - PIPE "|" - WHITESPACE " " OR_PAT + PIPE "|" + WHITESPACE " " IDENT_PAT NAME IDENT "X" @@ -132,11 +132,12 @@ SOURCE_FILE COMMA "," WHITESPACE "\n " MATCH_ARM - PIPE "|" - WHITESPACE " " - IDENT_PAT - NAME - IDENT "X" + OR_PAT + PIPE "|" + WHITESPACE " " + IDENT_PAT + NAME + IDENT "X" WHITESPACE " " FAT_ARROW "=>" WHITESPACE " " diff --git a/src/tools/rust-analyzer/crates/parser/test_data/parser/inline/ok/precise_capturing.rast b/src/tools/rust-analyzer/crates/parser/test_data/parser/inline/ok/precise_capturing.rast index cf52f1e4799..f9c0a245af8 100644 --- a/src/tools/rust-analyzer/crates/parser/test_data/parser/inline/ok/precise_capturing.rast +++ b/src/tools/rust-analyzer/crates/parser/test_data/parser/inline/ok/precise_capturing.rast @@ -50,16 +50,18 @@ SOURCE_FILE WHITESPACE " " TYPE_BOUND USE_KW "use" - GENERIC_PARAM_LIST + USE_BOUND_GENERIC_ARGS L_ANGLE "<" - LIFETIME_PARAM - LIFETIME - LIFETIME_IDENT "'b" + LIFETIME + LIFETIME_IDENT "'b" COMMA "," WHITESPACE " " - TYPE_PARAM - NAME - IDENT "T" + NAME_REF + IDENT "T" + COMMA "," + WHITESPACE " " + NAME_REF + SELF_TYPE_KW "Self" R_ANGLE ">" WHITESPACE " " BLOCK_EXPR diff --git a/src/tools/rust-analyzer/crates/parser/test_data/parser/inline/ok/precise_capturing.rs b/src/tools/rust-analyzer/crates/parser/test_data/parser/inline/ok/precise_capturing.rs index ec208d5062b..9ac2305f3a0 100644 --- a/src/tools/rust-analyzer/crates/parser/test_data/parser/inline/ok/precise_capturing.rs +++ b/src/tools/rust-analyzer/crates/parser/test_data/parser/inline/ok/precise_capturing.rs @@ -1 +1 @@ -fn captures<'a: 'a, 'b: 'b, T>() -> impl Sized + use<'b, T> {} +fn captures<'a: 'a, 'b: 'b, T>() -> impl Sized + use<'b, T, Self> {} diff --git a/src/tools/rust-analyzer/crates/parser/test_data/parser/inline/ok/slice_pat.rast b/src/tools/rust-analyzer/crates/parser/test_data/parser/inline/ok/slice_pat.rast index dff72ba886f..06c30bba59f 100644 --- a/src/tools/rust-analyzer/crates/parser/test_data/parser/inline/ok/slice_pat.rast +++ b/src/tools/rust-analyzer/crates/parser/test_data/parser/inline/ok/slice_pat.rast @@ -43,11 +43,12 @@ SOURCE_FILE WHITESPACE " " SLICE_PAT L_BRACK "[" - PIPE "|" - WHITESPACE " " - IDENT_PAT - NAME - IDENT "a" + OR_PAT + PIPE "|" + WHITESPACE " " + IDENT_PAT + NAME + IDENT "a" COMMA "," WHITESPACE " " REST_PAT diff --git a/src/tools/rust-analyzer/crates/parser/test_data/parser/inline/ok/tuple_pat.rast b/src/tools/rust-analyzer/crates/parser/test_data/parser/inline/ok/tuple_pat.rast index 1a01e0f6938..c7cd11f774b 100644 --- a/src/tools/rust-analyzer/crates/parser/test_data/parser/inline/ok/tuple_pat.rast +++ b/src/tools/rust-analyzer/crates/parser/test_data/parser/inline/ok/tuple_pat.rast @@ -91,9 +91,9 @@ SOURCE_FILE WHITESPACE " " TUPLE_PAT L_PAREN "(" - PIPE "|" - WHITESPACE " " OR_PAT + PIPE "|" + WHITESPACE " " IDENT_PAT NAME IDENT "a" @@ -105,11 +105,12 @@ SOURCE_FILE IDENT "a" COMMA "," WHITESPACE " " - PIPE "|" - WHITESPACE " " - IDENT_PAT - NAME - IDENT "b" + OR_PAT + PIPE "|" + WHITESPACE " " + IDENT_PAT + NAME + IDENT "b" R_PAREN ")" WHITESPACE " " EQ "=" diff --git a/src/tools/rust-analyzer/crates/parser/test_data/parser/inline/ok/tuple_pat_fields.rast b/src/tools/rust-analyzer/crates/parser/test_data/parser/inline/ok/tuple_pat_fields.rast index 55baf2fdcb4..96353f46976 100644 --- a/src/tools/rust-analyzer/crates/parser/test_data/parser/inline/ok/tuple_pat_fields.rast +++ b/src/tools/rust-analyzer/crates/parser/test_data/parser/inline/ok/tuple_pat_fields.rast @@ -110,11 +110,12 @@ SOURCE_FILE NAME_REF IDENT "S" L_PAREN "(" - PIPE "|" - WHITESPACE " " - IDENT_PAT - NAME - IDENT "a" + OR_PAT + PIPE "|" + WHITESPACE " " + IDENT_PAT + NAME + IDENT "a" R_PAREN ")" WHITESPACE " " EQ "=" diff --git a/src/tools/rust-analyzer/crates/proc-macro-api/src/msg/flat.rs b/src/tools/rust-analyzer/crates/proc-macro-api/src/msg/flat.rs index 88256e98b58..5443a9bd67b 100644 --- a/src/tools/rust-analyzer/crates/proc-macro-api/src/msg/flat.rs +++ b/src/tools/rust-analyzer/crates/proc-macro-api/src/msg/flat.rs @@ -401,7 +401,7 @@ struct Writer<'a, 'span, S: InternableSpan> { text: Vec<String>, } -impl<'a, 'span, S: InternableSpan> Writer<'a, 'span, S> { +impl<'a, S: InternableSpan> Writer<'a, '_, S> { fn write(&mut self, root: &'a tt::Subtree<S>) { self.enqueue(root); while let Some((idx, subtree)) = self.work.pop_front() { @@ -524,7 +524,7 @@ struct Reader<'span, S: InternableSpan> { span_data_table: &'span S::Table, } -impl<'span, S: InternableSpan> Reader<'span, S> { +impl<S: InternableSpan> Reader<'_, S> { pub(crate) fn read(self) -> tt::Subtree<S> { let mut res: Vec<Option<tt::Subtree<S>>> = vec![None; self.subtree.len()]; let read_span = |id| S::span_for_token_id(self.span_data_table, id); diff --git a/src/tools/rust-analyzer/crates/project-model/src/rustc_cfg.rs b/src/tools/rust-analyzer/crates/project-model/src/rustc_cfg.rs index aa73ff89100..bc1f0e6fbf2 100644 --- a/src/tools/rust-analyzer/crates/project-model/src/rustc_cfg.rs +++ b/src/tools/rust-analyzer/crates/project-model/src/rustc_cfg.rs @@ -24,14 +24,15 @@ pub(crate) fn get( config: RustcCfgConfig<'_>, ) -> Vec<CfgAtom> { let _p = tracing::info_span!("rustc_cfg::get").entered(); - let mut res: Vec<_> = Vec::with_capacity(6 * 2 + 1); + let mut res: Vec<_> = Vec::with_capacity(7 * 2 + 1); // Some nightly-only cfgs, which are required for stdlib res.push(CfgAtom::Flag(Symbol::intern("target_thread_local"))); - for ty in ["8", "16", "32", "64", "cas", "ptr"] { - for key in ["target_has_atomic", "target_has_atomic_load_store"] { + for key in ["target_has_atomic", "target_has_atomic_load_store"] { + for ty in ["8", "16", "32", "64", "cas", "ptr"] { res.push(CfgAtom::KeyValue { key: Symbol::intern(key), value: Symbol::intern(ty) }); } + res.push(CfgAtom::Flag(Symbol::intern(key))); } let rustc_cfgs = get_rust_cfgs(target, extra_env, config); diff --git a/src/tools/rust-analyzer/crates/project-model/src/workspace.rs b/src/tools/rust-analyzer/crates/project-model/src/workspace.rs index d1ee579c0d8..d53639e2423 100644 --- a/src/tools/rust-analyzer/crates/project-model/src/workspace.rs +++ b/src/tools/rust-analyzer/crates/project-model/src/workspace.rs @@ -1062,7 +1062,7 @@ fn cargo_to_crate_graph( proc_macros, cargo, pkg_data, - build_data, + build_data.zip(Some(build_scripts.error().is_some())), cfg_options.clone(), file_id, name, @@ -1285,7 +1285,7 @@ fn handle_rustc_crates( proc_macros, rustc_workspace, &rustc_workspace[pkg], - build_scripts.get_output(pkg), + build_scripts.get_output(pkg).zip(Some(build_scripts.error().is_some())), cfg_options.clone(), file_id, &rustc_workspace[tgt].name, @@ -1345,7 +1345,7 @@ fn add_target_crate_root( proc_macros: &mut ProcMacroPaths, cargo: &CargoWorkspace, pkg: &PackageData, - build_data: Option<&BuildScriptOutput>, + build_data: Option<(&BuildScriptOutput, bool)>, cfg_options: CfgOptions, file_id: FileId, cargo_name: &str, @@ -1368,7 +1368,7 @@ fn add_target_crate_root( for feature in pkg.active_features.iter() { opts.insert_key_value(sym::feature.clone(), Symbol::intern(feature)); } - if let Some(cfgs) = build_data.as_ref().map(|it| &it.cfgs) { + if let Some(cfgs) = build_data.map(|(it, _)| &it.cfgs) { opts.extend(cfgs.iter().cloned()); } opts @@ -1379,7 +1379,7 @@ fn add_target_crate_root( inject_cargo_env(&mut env); inject_rustc_tool_env(&mut env, cargo, cargo_name, kind); - if let Some(envs) = build_data.map(|it| &it.envs) { + if let Some(envs) = build_data.map(|(it, _)| &it.envs) { for (k, v) in envs { env.set(k, v.clone()); } @@ -1396,11 +1396,14 @@ fn add_target_crate_root( origin, ); if let TargetKind::Lib { is_proc_macro: true } = kind { - let proc_macro = match build_data.as_ref().map(|it| it.proc_macro_dylib_path.as_ref()) { - Some(it) => match it { - Some(path) => Ok((cargo_name.to_owned(), path.clone())), - None => Err("proc-macro crate build data is missing dylib path".to_owned()), - }, + let proc_macro = match build_data { + Some((BuildScriptOutput { proc_macro_dylib_path, .. }, has_errors)) => { + match proc_macro_dylib_path { + Some(path) => Ok((cargo_name.to_owned(), path.clone())), + None if has_errors => Err("failed to build proc-macro".to_owned()), + None => Err("proc-macro crate build data is missing dylib path".to_owned()), + } + } None => Err("proc-macro crate is missing its build data".to_owned()), }; proc_macros.insert(crate_id, proc_macro); diff --git a/src/tools/rust-analyzer/crates/project-model/test_data/output/cargo_hello_world_project_model.txt b/src/tools/rust-analyzer/crates/project-model/test_data/output/cargo_hello_world_project_model.txt index 3401d7f7e47..880e90c52a5 100644 --- a/src/tools/rust-analyzer/crates/project-model/test_data/output/cargo_hello_world_project_model.txt +++ b/src/tools/rust-analyzer/crates/project-model/test_data/output/cargo_hello_world_project_model.txt @@ -19,6 +19,7 @@ [ "rust_analyzer", "test", + "true", ], ), potential_cfg_options: None, @@ -81,6 +82,7 @@ [ "rust_analyzer", "test", + "true", ], ), potential_cfg_options: None, @@ -151,6 +153,7 @@ [ "rust_analyzer", "test", + "true", ], ), potential_cfg_options: None, @@ -221,6 +224,7 @@ [ "rust_analyzer", "test", + "true", ], ), potential_cfg_options: None, @@ -291,6 +295,7 @@ [ "feature=default", "feature=std", + "true", ], ), potential_cfg_options: Some( @@ -303,6 +308,7 @@ "feature=rustc-dep-of-std", "feature=std", "feature=use_std", + "true", ], ), ), diff --git a/src/tools/rust-analyzer/crates/project-model/test_data/output/cargo_hello_world_project_model_with_selective_overrides.txt b/src/tools/rust-analyzer/crates/project-model/test_data/output/cargo_hello_world_project_model_with_selective_overrides.txt index 3401d7f7e47..880e90c52a5 100644 --- a/src/tools/rust-analyzer/crates/project-model/test_data/output/cargo_hello_world_project_model_with_selective_overrides.txt +++ b/src/tools/rust-analyzer/crates/project-model/test_data/output/cargo_hello_world_project_model_with_selective_overrides.txt @@ -19,6 +19,7 @@ [ "rust_analyzer", "test", + "true", ], ), potential_cfg_options: None, @@ -81,6 +82,7 @@ [ "rust_analyzer", "test", + "true", ], ), potential_cfg_options: None, @@ -151,6 +153,7 @@ [ "rust_analyzer", "test", + "true", ], ), potential_cfg_options: None, @@ -221,6 +224,7 @@ [ "rust_analyzer", "test", + "true", ], ), potential_cfg_options: None, @@ -291,6 +295,7 @@ [ "feature=default", "feature=std", + "true", ], ), potential_cfg_options: Some( @@ -303,6 +308,7 @@ "feature=rustc-dep-of-std", "feature=std", "feature=use_std", + "true", ], ), ), diff --git a/src/tools/rust-analyzer/crates/project-model/test_data/output/cargo_hello_world_project_model_with_wildcard_overrides.txt b/src/tools/rust-analyzer/crates/project-model/test_data/output/cargo_hello_world_project_model_with_wildcard_overrides.txt index 491568d4b75..7746acd225e 100644 --- a/src/tools/rust-analyzer/crates/project-model/test_data/output/cargo_hello_world_project_model_with_wildcard_overrides.txt +++ b/src/tools/rust-analyzer/crates/project-model/test_data/output/cargo_hello_world_project_model_with_wildcard_overrides.txt @@ -18,6 +18,7 @@ cfg_options: CfgOptions( [ "rust_analyzer", + "true", ], ), potential_cfg_options: None, @@ -79,6 +80,7 @@ cfg_options: CfgOptions( [ "rust_analyzer", + "true", ], ), potential_cfg_options: None, @@ -148,6 +150,7 @@ cfg_options: CfgOptions( [ "rust_analyzer", + "true", ], ), potential_cfg_options: None, @@ -217,6 +220,7 @@ cfg_options: CfgOptions( [ "rust_analyzer", + "true", ], ), potential_cfg_options: None, @@ -287,6 +291,7 @@ [ "feature=default", "feature=std", + "true", ], ), potential_cfg_options: Some( @@ -299,6 +304,7 @@ "feature=rustc-dep-of-std", "feature=std", "feature=use_std", + "true", ], ), ), diff --git a/src/tools/rust-analyzer/crates/project-model/test_data/output/rust_project_cfg_groups.txt b/src/tools/rust-analyzer/crates/project-model/test_data/output/rust_project_cfg_groups.txt index 8261e5a2d90..90f41a9c2fc 100644 --- a/src/tools/rust-analyzer/crates/project-model/test_data/output/rust_project_cfg_groups.txt +++ b/src/tools/rust-analyzer/crates/project-model/test_data/output/rust_project_cfg_groups.txt @@ -17,6 +17,7 @@ [ "debug_assertions", "miri", + "true", ], ), potential_cfg_options: None, @@ -56,6 +57,7 @@ [ "debug_assertions", "miri", + "true", ], ), potential_cfg_options: None, @@ -86,6 +88,7 @@ [ "debug_assertions", "miri", + "true", ], ), potential_cfg_options: None, @@ -116,6 +119,7 @@ [ "debug_assertions", "miri", + "true", ], ), potential_cfg_options: None, @@ -146,6 +150,7 @@ [ "debug_assertions", "miri", + "true", ], ), potential_cfg_options: None, @@ -193,6 +198,7 @@ [ "debug_assertions", "miri", + "true", ], ), potential_cfg_options: None, @@ -223,6 +229,7 @@ [ "debug_assertions", "miri", + "true", ], ), potential_cfg_options: None, @@ -318,6 +325,7 @@ [ "debug_assertions", "miri", + "true", ], ), potential_cfg_options: None, @@ -348,6 +356,7 @@ [ "debug_assertions", "miri", + "true", ], ), potential_cfg_options: None, @@ -378,6 +387,7 @@ [ "debug_assertions", "miri", + "true", ], ), potential_cfg_options: None, @@ -410,6 +420,7 @@ "group1_other_cfg=other_config", "group2_cfg=yet_another_config", "rust_analyzer", + "true", ], ), potential_cfg_options: None, @@ -485,6 +496,7 @@ "group2_cfg=fourth_config", "group2_cfg=yet_another_config", "rust_analyzer", + "true", "unrelated_cfg", ], ), diff --git a/src/tools/rust-analyzer/crates/project-model/test_data/output/rust_project_hello_world_project_model.txt b/src/tools/rust-analyzer/crates/project-model/test_data/output/rust_project_hello_world_project_model.txt index c123df80a6a..a0e14b8fcb2 100644 --- a/src/tools/rust-analyzer/crates/project-model/test_data/output/rust_project_hello_world_project_model.txt +++ b/src/tools/rust-analyzer/crates/project-model/test_data/output/rust_project_hello_world_project_model.txt @@ -17,6 +17,7 @@ [ "debug_assertions", "miri", + "true", ], ), potential_cfg_options: None, @@ -56,6 +57,7 @@ [ "debug_assertions", "miri", + "true", ], ), potential_cfg_options: None, @@ -86,6 +88,7 @@ [ "debug_assertions", "miri", + "true", ], ), potential_cfg_options: None, @@ -116,6 +119,7 @@ [ "debug_assertions", "miri", + "true", ], ), potential_cfg_options: None, @@ -146,6 +150,7 @@ [ "debug_assertions", "miri", + "true", ], ), potential_cfg_options: None, @@ -193,6 +198,7 @@ [ "debug_assertions", "miri", + "true", ], ), potential_cfg_options: None, @@ -223,6 +229,7 @@ [ "debug_assertions", "miri", + "true", ], ), potential_cfg_options: None, @@ -318,6 +325,7 @@ [ "debug_assertions", "miri", + "true", ], ), potential_cfg_options: None, @@ -348,6 +356,7 @@ [ "debug_assertions", "miri", + "true", ], ), potential_cfg_options: None, @@ -378,6 +387,7 @@ [ "debug_assertions", "miri", + "true", ], ), potential_cfg_options: None, @@ -407,6 +417,7 @@ cfg_options: CfgOptions( [ "rust_analyzer", + "true", ], ), potential_cfg_options: None, diff --git a/src/tools/rust-analyzer/crates/ra-salsa/src/derived/slot.rs b/src/tools/rust-analyzer/crates/ra-salsa/src/derived/slot.rs index de7a3976074..6c5ccba173b 100644 --- a/src/tools/rust-analyzer/crates/ra-salsa/src/derived/slot.rs +++ b/src/tools/rust-analyzer/crates/ra-salsa/src/derived/slot.rs @@ -616,7 +616,7 @@ Please report this bug to https://github.com/salsa-rs/salsa/issues." } } -impl<'me, Q> Drop for PanicGuard<'me, Q> +impl<Q> Drop for PanicGuard<'_, Q> where Q: QueryFunction, Q::Value: Eq, diff --git a/src/tools/rust-analyzer/crates/ra-salsa/src/derived_lru/slot.rs b/src/tools/rust-analyzer/crates/ra-salsa/src/derived_lru/slot.rs index d0e4b5422b5..ff9cc4eade2 100644 --- a/src/tools/rust-analyzer/crates/ra-salsa/src/derived_lru/slot.rs +++ b/src/tools/rust-analyzer/crates/ra-salsa/src/derived_lru/slot.rs @@ -666,7 +666,7 @@ Please report this bug to https://github.com/salsa-rs/salsa/issues." } } -impl<'me, Q, MP> Drop for PanicGuard<'me, Q, MP> +impl<Q, MP> Drop for PanicGuard<'_, Q, MP> where Q: QueryFunction, MP: MemoizationPolicy<Q>, diff --git a/src/tools/rust-analyzer/crates/ra-salsa/src/interned.rs b/src/tools/rust-analyzer/crates/ra-salsa/src/interned.rs index 359662ec6b2..42c398d697d 100644 --- a/src/tools/rust-analyzer/crates/ra-salsa/src/interned.rs +++ b/src/tools/rust-analyzer/crates/ra-salsa/src/interned.rs @@ -493,7 +493,7 @@ where is_static::<Slot<K>>(); } -impl<'me, Q> QueryTable<'me, Q> +impl<Q> QueryTable<'_, Q> where Q: Query<Storage = InternedStorage<Q>>, Q::Key: InternValue, diff --git a/src/tools/rust-analyzer/crates/ra-salsa/src/lib.rs b/src/tools/rust-analyzer/crates/ra-salsa/src/lib.rs index 1b327773ec6..bd1ab6971cb 100644 --- a/src/tools/rust-analyzer/crates/ra-salsa/src/lib.rs +++ b/src/tools/rust-analyzer/crates/ra-salsa/src/lib.rs @@ -149,7 +149,7 @@ where db: &'me D, } -impl<'me, D: ?Sized> fmt::Debug for EventDebug<'me, D> +impl<D: ?Sized> fmt::Debug for EventDebug<'_, D> where D: plumbing::DatabaseOps, { @@ -242,7 +242,7 @@ where db: &'me D, } -impl<'me, D: ?Sized> fmt::Debug for EventKindDebug<'me, D> +impl<D: ?Sized> fmt::Debug for EventKindDebug<'_, D> where D: plumbing::DatabaseOps, { @@ -729,7 +729,7 @@ impl Cycle { db: &'me dyn Database, } - impl<'me> std::fmt::Debug for UnexpectedCycleDebug<'me> { + impl std::fmt::Debug for UnexpectedCycleDebug<'_> { fn fmt(&self, fmt: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { fmt.debug_struct("UnexpectedCycle") .field("all_participants", &self.c.all_participants(self.db)) diff --git a/src/tools/rust-analyzer/crates/rust-analyzer/src/bin/main.rs b/src/tools/rust-analyzer/crates/rust-analyzer/src/bin/main.rs index ecc8333503e..e872585c571 100644 --- a/src/tools/rust-analyzer/crates/rust-analyzer/src/bin/main.rs +++ b/src/tools/rust-analyzer/crates/rust-analyzer/src/bin/main.rs @@ -85,7 +85,9 @@ fn actual_main() -> anyhow::Result<ExitCode> { flags::RustAnalyzerCmd::UnresolvedReferences(cmd) => cmd.run()?, flags::RustAnalyzerCmd::Ssr(cmd) => cmd.run()?, flags::RustAnalyzerCmd::Search(cmd) => cmd.run()?, - flags::RustAnalyzerCmd::Lsif(cmd) => cmd.run()?, + flags::RustAnalyzerCmd::Lsif(cmd) => { + cmd.run(&mut std::io::stdout(), Some(project_model::RustLibSource::Discover))? + } flags::RustAnalyzerCmd::Scip(cmd) => cmd.run()?, flags::RustAnalyzerCmd::RunTests(cmd) => cmd.run()?, flags::RustAnalyzerCmd::RustcTests(cmd) => cmd.run()?, diff --git a/src/tools/rust-analyzer/crates/rust-analyzer/src/cli/lsif.rs b/src/tools/rust-analyzer/crates/rust-analyzer/src/cli/lsif.rs index ca8acf57bff..33c4f31fbee 100644 --- a/src/tools/rust-analyzer/crates/rust-analyzer/src/cli/lsif.rs +++ b/src/tools/rust-analyzer/crates/rust-analyzer/src/cli/lsif.rs @@ -12,6 +12,7 @@ use load_cargo::{load_workspace, LoadCargoConfig, ProcMacroServerChoice}; use lsp_types::lsif; use project_model::{CargoConfig, ProjectManifest, ProjectWorkspace, RustLibSource}; use rustc_hash::FxHashMap; +use stdx::format_to; use vfs::{AbsPathBuf, Vfs}; use crate::{ @@ -21,7 +22,7 @@ use crate::{ version::version, }; -struct LsifManager<'a> { +struct LsifManager<'a, 'w> { count: i32, token_map: FxHashMap<TokenId, Id>, range_map: FxHashMap<FileRange, Id>, @@ -30,6 +31,7 @@ struct LsifManager<'a> { analysis: &'a Analysis, db: &'a RootDatabase, vfs: &'a Vfs, + out: &'w mut dyn std::io::Write, } #[derive(Clone, Copy)] @@ -41,8 +43,13 @@ impl From<Id> for lsp_types::NumberOrString { } } -impl LsifManager<'_> { - fn new<'a>(analysis: &'a Analysis, db: &'a RootDatabase, vfs: &'a Vfs) -> LsifManager<'a> { +impl LsifManager<'_, '_> { + fn new<'a, 'w>( + analysis: &'a Analysis, + db: &'a RootDatabase, + vfs: &'a Vfs, + out: &'w mut dyn std::io::Write, + ) -> LsifManager<'a, 'w> { LsifManager { count: 0, token_map: FxHashMap::default(), @@ -52,6 +59,7 @@ impl LsifManager<'_> { analysis, db, vfs, + out, } } @@ -70,9 +78,8 @@ impl LsifManager<'_> { self.add(lsif::Element::Edge(edge)) } - // FIXME: support file in addition to stdout here - fn emit(&self, data: &str) { - println!("{data}"); + fn emit(&mut self, data: &str) { + format_to!(self.out, "{data}\n"); } fn get_token_id(&mut self, id: TokenId) -> Id { @@ -272,14 +279,14 @@ impl LsifManager<'_> { } impl flags::Lsif { - pub fn run(self) -> anyhow::Result<()> { + pub fn run( + self, + out: &mut dyn std::io::Write, + sysroot: Option<RustLibSource>, + ) -> anyhow::Result<()> { let now = Instant::now(); - let cargo_config = &CargoConfig { - sysroot: Some(RustLibSource::Discover), - all_targets: true, - set_test: true, - ..Default::default() - }; + let cargo_config = + &CargoConfig { sysroot, all_targets: true, set_test: true, ..Default::default() }; let no_progress = &|_| (); let load_cargo_config = LoadCargoConfig { load_out_dirs_from_check: true, @@ -308,7 +315,7 @@ impl flags::Lsif { let si = StaticIndex::compute(&analysis, vendored_libs_config); - let mut lsif = LsifManager::new(&analysis, db, &vfs); + let mut lsif = LsifManager::new(&analysis, db, &vfs, out); lsif.add_vertex(lsif::Vertex::MetaData(lsif::MetaData { version: String::from("0.5.0"), project_root: lsp_types::Url::from_file_path(path).unwrap(), diff --git a/src/tools/rust-analyzer/crates/rust-analyzer/src/config.rs b/src/tools/rust-analyzer/crates/rust-analyzer/src/config.rs index 518b588cb7d..f5b0fcecf39 100644 --- a/src/tools/rust-analyzer/crates/rust-analyzer/src/config.rs +++ b/src/tools/rust-analyzer/crates/rust-analyzer/src/config.rs @@ -727,7 +727,7 @@ enum RatomlFile { Crate(LocalConfigInput), } -#[derive(Debug, Clone)] +#[derive(Clone)] pub struct Config { /// Projects that have a Cargo.toml or a rust-project.json in a /// parent directory, so we can discover them by walking the @@ -765,6 +765,26 @@ pub struct Config { detached_files: Vec<AbsPathBuf>, } +impl fmt::Debug for Config { + fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { + f.debug_struct("Config") + .field("discovered_projects_from_filesystem", &self.discovered_projects_from_filesystem) + .field("discovered_projects_from_command", &self.discovered_projects_from_command) + .field("workspace_roots", &self.workspace_roots) + .field("caps", &self.caps) + .field("root_path", &self.root_path) + .field("snippets", &self.snippets) + .field("visual_studio_code_version", &self.visual_studio_code_version) + .field("client_config", &self.client_config) + .field("user_config", &self.user_config) + .field("ratoml_file", &self.ratoml_file) + .field("source_root_parent_map", &self.source_root_parent_map) + .field("validation_errors", &self.validation_errors) + .field("detached_files", &self.detached_files) + .finish() + } +} + // Delegate capability fetching methods impl std::ops::Deref for Config { type Target = ClientCapabilities; diff --git a/src/tools/rust-analyzer/crates/rust-analyzer/src/diagnostics.rs b/src/tools/rust-analyzer/crates/rust-analyzer/src/diagnostics.rs index 5f2871ac992..22910ee4c68 100644 --- a/src/tools/rust-analyzer/crates/rust-analyzer/src/diagnostics.rs +++ b/src/tools/rust-analyzer/crates/rust-analyzer/src/diagnostics.rs @@ -173,21 +173,6 @@ pub(crate) fn fetch_native_diagnostics( let _p = tracing::info_span!("fetch_native_diagnostics").entered(); let _ctx = stdx::panic_context::enter("fetch_native_diagnostics".to_owned()); - let convert_diagnostic = - |line_index: &crate::line_index::LineIndex, d: ide::Diagnostic| lsp_types::Diagnostic { - range: lsp::to_proto::range(line_index, d.range.range), - severity: Some(lsp::to_proto::diagnostic_severity(d.severity)), - code: Some(lsp_types::NumberOrString::String(d.code.as_str().to_owned())), - code_description: Some(lsp_types::CodeDescription { - href: lsp_types::Url::parse(&d.code.url()).unwrap(), - }), - source: Some("rust-analyzer".to_owned()), - message: d.message, - related_information: None, - tags: d.unused.then(|| vec![lsp_types::DiagnosticTag::UNNECESSARY]), - data: None, - }; - // the diagnostics produced may point to different files not requested by the concrete request, // put those into here and filter later let mut odd_ones = Vec::new(); @@ -203,10 +188,12 @@ pub(crate) fn fetch_native_diagnostics( NativeDiagnosticsFetchKind::Syntax => { snapshot.analysis.syntax_diagnostics(config, file_id).ok()? } - NativeDiagnosticsFetchKind::Semantic => snapshot + + NativeDiagnosticsFetchKind::Semantic if config.enabled => snapshot .analysis .semantic_diagnostics(config, ide::AssistResolveStrategy::None, file_id) .ok()?, + NativeDiagnosticsFetchKind::Semantic => return None, }; let diagnostics = diagnostics .into_iter() @@ -246,3 +233,22 @@ pub(crate) fn fetch_native_diagnostics( } diagnostics } + +pub(crate) fn convert_diagnostic( + line_index: &crate::line_index::LineIndex, + d: ide::Diagnostic, +) -> lsp_types::Diagnostic { + lsp_types::Diagnostic { + range: lsp::to_proto::range(line_index, d.range.range), + severity: Some(lsp::to_proto::diagnostic_severity(d.severity)), + code: Some(lsp_types::NumberOrString::String(d.code.as_str().to_owned())), + code_description: Some(lsp_types::CodeDescription { + href: lsp_types::Url::parse(&d.code.url()).unwrap(), + }), + source: Some("rust-analyzer".to_owned()), + message: d.message, + related_information: None, + tags: d.unused.then(|| vec![lsp_types::DiagnosticTag::UNNECESSARY]), + data: None, + } +} diff --git a/src/tools/rust-analyzer/crates/rust-analyzer/src/handlers/dispatch.rs b/src/tools/rust-analyzer/crates/rust-analyzer/src/handlers/dispatch.rs index ed7bf27843b..03759b036b4 100644 --- a/src/tools/rust-analyzer/crates/rust-analyzer/src/handlers/dispatch.rs +++ b/src/tools/rust-analyzer/crates/rust-analyzer/src/handlers/dispatch.rs @@ -5,7 +5,7 @@ use std::{ }; use ide::Cancelled; -use lsp_server::ExtractError; +use lsp_server::{ExtractError, Response, ResponseError}; use serde::{de::DeserializeOwned, Serialize}; use stdx::thread::ThreadIntent; @@ -117,7 +117,36 @@ impl RequestDispatcher<'_> { } return self; } - self.on_with_thread_intent::<true, ALLOW_RETRYING, R>(ThreadIntent::Worker, f) + self.on_with_thread_intent::<true, ALLOW_RETRYING, R>( + ThreadIntent::Worker, + f, + Self::content_modified_error, + ) + } + + /// Dispatches a non-latency-sensitive request onto the thread pool. When the VFS is marked not + /// ready this will return a `default` constructed [`R::Result`]. + pub(crate) fn on_with<R>( + &mut self, + f: fn(GlobalStateSnapshot, R::Params) -> anyhow::Result<R::Result>, + default: impl FnOnce() -> R::Result, + on_cancelled: fn() -> ResponseError, + ) -> &mut Self + where + R: lsp_types::request::Request< + Params: DeserializeOwned + panic::UnwindSafe + Send + fmt::Debug, + Result: Serialize, + > + 'static, + { + if !self.global_state.vfs_done { + if let Some(lsp_server::Request { id, .. }) = + self.req.take_if(|it| it.method == R::METHOD) + { + self.global_state.respond(lsp_server::Response::new_ok(id, default())); + } + return self; + } + self.on_with_thread_intent::<true, false, R>(ThreadIntent::Worker, f, on_cancelled) } /// Dispatches a non-latency-sensitive request onto the thread pool. When the VFS is marked not @@ -136,7 +165,11 @@ impl RequestDispatcher<'_> { } return self; } - self.on_with_thread_intent::<true, ALLOW_RETRYING, R>(ThreadIntent::Worker, f) + self.on_with_thread_intent::<true, ALLOW_RETRYING, R>( + ThreadIntent::Worker, + f, + Self::content_modified_error, + ) } /// Dispatches a latency-sensitive request onto the thread pool. When the VFS is marked not @@ -159,7 +192,11 @@ impl RequestDispatcher<'_> { } return self; } - self.on_with_thread_intent::<true, ALLOW_RETRYING, R>(ThreadIntent::LatencySensitive, f) + self.on_with_thread_intent::<true, ALLOW_RETRYING, R>( + ThreadIntent::LatencySensitive, + f, + Self::content_modified_error, + ) } /// Formatting requests should never block on waiting a for task thread to open up, editors will wait @@ -174,7 +211,11 @@ impl RequestDispatcher<'_> { R::Params: DeserializeOwned + panic::UnwindSafe + Send + fmt::Debug, R::Result: Serialize, { - self.on_with_thread_intent::<false, false, R>(ThreadIntent::LatencySensitive, f) + self.on_with_thread_intent::<false, false, R>( + ThreadIntent::LatencySensitive, + f, + Self::content_modified_error, + ) } pub(crate) fn finish(&mut self) { @@ -193,6 +234,7 @@ impl RequestDispatcher<'_> { &mut self, intent: ThreadIntent, f: fn(GlobalStateSnapshot, R::Params) -> anyhow::Result<R::Result>, + on_cancelled: fn() -> ResponseError, ) -> &mut Self where R: lsp_types::request::Request + 'static, @@ -221,11 +263,10 @@ impl RequestDispatcher<'_> { match thread_result_to_response::<R>(req.id.clone(), result) { Ok(response) => Task::Response(response), Err(_cancelled) if ALLOW_RETRYING => Task::Retry(req), - Err(_cancelled) => Task::Response(lsp_server::Response::new_err( - req.id, - lsp_server::ErrorCode::ContentModified as i32, - "content modified".to_owned(), - )), + Err(_cancelled) => { + let error = on_cancelled(); + Task::Response(Response { id: req.id, result: None, error: Some(error) }) + } } }); @@ -256,6 +297,14 @@ impl RequestDispatcher<'_> { } } } + + fn content_modified_error() -> ResponseError { + ResponseError { + code: lsp_server::ErrorCode::ContentModified as i32, + message: "content modified".to_owned(), + data: None, + } + } } fn thread_result_to_response<R>( diff --git a/src/tools/rust-analyzer/crates/rust-analyzer/src/handlers/request.rs b/src/tools/rust-analyzer/crates/rust-analyzer/src/handlers/request.rs index a9f8ac3a80a..fa584ab4d21 100644 --- a/src/tools/rust-analyzer/crates/rust-analyzer/src/handlers/request.rs +++ b/src/tools/rust-analyzer/crates/rust-analyzer/src/handlers/request.rs @@ -4,6 +4,7 @@ use std::{ fs, io::Write as _, + ops::Not, process::{self, Stdio}, }; @@ -14,7 +15,7 @@ use ide::{ FilePosition, FileRange, HoverAction, HoverGotoTypeData, InlayFieldsToResolve, Query, RangeInfo, ReferenceCategory, Runnable, RunnableKind, SingleResolve, SourceChange, TextEdit, }; -use ide_db::SymbolKind; +use ide_db::{FxHashMap, SymbolKind}; use itertools::Itertools; use lsp_server::ErrorCode; use lsp_types::{ @@ -36,6 +37,7 @@ use vfs::{AbsPath, AbsPathBuf, FileId, VfsPath}; use crate::{ config::{Config, RustfmtConfig, WorkspaceSymbolConfig}, + diagnostics::convert_diagnostic, global_state::{FetchWorkspaceRequest, GlobalState, GlobalStateSnapshot}, hack_recover_crate_name, line_index::LineEndings, @@ -119,7 +121,7 @@ pub(crate) fn handle_analyzer_status( format_to!(buf, "{}", crate::version()); buf.push_str("\nConfiguration: \n"); - format_to!(buf, "{:?}", snap.config); + format_to!(buf, "{:#?}", snap.config); Ok(buf) } @@ -473,6 +475,74 @@ pub(crate) fn handle_on_type_formatting( Ok(Some(change)) } +pub(crate) fn handle_document_diagnostics( + snap: GlobalStateSnapshot, + params: lsp_types::DocumentDiagnosticParams, +) -> anyhow::Result<lsp_types::DocumentDiagnosticReportResult> { + const EMPTY: lsp_types::DocumentDiagnosticReportResult = + lsp_types::DocumentDiagnosticReportResult::Report( + lsp_types::DocumentDiagnosticReport::Full( + lsp_types::RelatedFullDocumentDiagnosticReport { + related_documents: None, + full_document_diagnostic_report: lsp_types::FullDocumentDiagnosticReport { + result_id: None, + items: vec![], + }, + }, + ), + ); + + let file_id = from_proto::file_id(&snap, ¶ms.text_document.uri)?; + let source_root = snap.analysis.source_root_id(file_id)?; + if !snap.analysis.is_local_source_root(source_root)? { + return Ok(EMPTY); + } + let config = snap.config.diagnostics(Some(source_root)); + if !config.enabled { + return Ok(EMPTY); + } + let line_index = snap.file_line_index(file_id)?; + let supports_related = snap.config.text_document_diagnostic_related_document_support(); + + let mut related_documents = FxHashMap::default(); + let diagnostics = snap + .analysis + .full_diagnostics(&config, AssistResolveStrategy::None, file_id)? + .into_iter() + .filter_map(|d| { + let file = d.range.file_id; + let diagnostic = convert_diagnostic(&line_index, d); + if file == file_id { + return Some(diagnostic); + } + if supports_related { + related_documents.entry(file).or_insert_with(Vec::new).push(diagnostic); + } + None + }); + Ok(lsp_types::DocumentDiagnosticReportResult::Report( + lsp_types::DocumentDiagnosticReport::Full(lsp_types::RelatedFullDocumentDiagnosticReport { + full_document_diagnostic_report: lsp_types::FullDocumentDiagnosticReport { + result_id: None, + items: diagnostics.collect(), + }, + related_documents: related_documents.is_empty().not().then(|| { + related_documents + .into_iter() + .map(|(id, items)| { + ( + to_proto::url(&snap, id), + lsp_types::DocumentDiagnosticReportKind::Full( + lsp_types::FullDocumentDiagnosticReport { result_id: None, items }, + ), + ) + }) + .collect() + }), + }), + )) +} + pub(crate) fn handle_document_symbol( snap: GlobalStateSnapshot, params: lsp_types::DocumentSymbolParams, @@ -539,18 +609,11 @@ pub(crate) fn handle_document_symbol( url: &Url, res: &mut Vec<SymbolInformation>, ) { - let mut tags = Vec::new(); - - #[allow(deprecated)] - if let Some(true) = symbol.deprecated { - tags.push(SymbolTag::DEPRECATED) - } - #[allow(deprecated)] res.push(SymbolInformation { name: symbol.name.clone(), kind: symbol.kind, - tags: Some(tags), + tags: symbol.tags.clone(), deprecated: symbol.deprecated, location: Location::new(url.clone(), symbol.range), container_name, diff --git a/src/tools/rust-analyzer/crates/rust-analyzer/src/lsp/capabilities.rs b/src/tools/rust-analyzer/crates/rust-analyzer/src/lsp/capabilities.rs index 3b19284f241..271a9c0f3d1 100644 --- a/src/tools/rust-analyzer/crates/rust-analyzer/src/lsp/capabilities.rs +++ b/src/tools/rust-analyzer/crates/rust-analyzer/src/lsp/capabilities.rs @@ -155,7 +155,15 @@ pub fn server_capabilities(config: &Config) -> ServerCapabilities { "ssr": true, "workspaceSymbolScopeKindFiltering": true, })), - diagnostic_provider: None, + diagnostic_provider: Some(lsp_types::DiagnosticServerCapabilities::Options( + lsp_types::DiagnosticOptions { + identifier: None, + inter_file_dependencies: true, + // FIXME + workspace_diagnostics: false, + work_done_progress_options: WorkDoneProgressOptions { work_done_progress: None }, + }, + )), inline_completion_provider: None, } } @@ -210,9 +218,7 @@ impl ClientCapabilities { .completion_item .as_ref()? .label_details_support - .as_ref() - })() - .is_some() + })() == Some(true) } fn completion_item(&self) -> Option<CompletionOptionsCompletionItem> { @@ -382,6 +388,15 @@ impl ClientCapabilities { .unwrap_or_default() } + pub fn text_document_diagnostic(&self) -> bool { + (|| -> _ { self.0.text_document.as_ref()?.diagnostic.as_ref() })().is_some() + } + + pub fn text_document_diagnostic_related_document_support(&self) -> bool { + (|| -> _ { self.0.text_document.as_ref()?.diagnostic.as_ref()?.related_document_support })() + == Some(true) + } + pub fn code_action_group(&self) -> bool { self.experimental_bool("codeActionGroup") } diff --git a/src/tools/rust-analyzer/crates/rust-analyzer/src/main_loop.rs b/src/tools/rust-analyzer/crates/rust-analyzer/src/main_loop.rs index 20be38a9e4b..9a51df80fe1 100644 --- a/src/tools/rust-analyzer/crates/rust-analyzer/src/main_loop.rs +++ b/src/tools/rust-analyzer/crates/rust-analyzer/src/main_loop.rs @@ -417,6 +417,8 @@ impl GlobalState { } } + let supports_diagnostic_pull_model = self.config.text_document_diagnostic(); + let client_refresh = became_quiescent || state_changed; if client_refresh { // Refresh semantic tokens if the client supports it. @@ -434,11 +436,21 @@ impl GlobalState { if self.config.inlay_hints_refresh() { self.send_request::<lsp_types::request::InlayHintRefreshRequest>((), |_, _| ()); } + + if supports_diagnostic_pull_model { + self.send_request::<lsp_types::request::WorkspaceDiagnosticRefresh>( + (), + |_, _| (), + ); + } } let project_or_mem_docs_changed = became_quiescent || state_changed || memdocs_added_or_removed; - if project_or_mem_docs_changed && self.config.publish_diagnostics(None) { + if project_or_mem_docs_changed + && !supports_diagnostic_pull_model + && self.config.publish_diagnostics(None) + { self.update_diagnostics(); } if project_or_mem_docs_changed && self.config.test_explorer() { @@ -1080,6 +1092,23 @@ impl GlobalState { .on_latency_sensitive::<NO_RETRY, lsp_request::SemanticTokensRangeRequest>(handlers::handle_semantic_tokens_range) // FIXME: Some of these NO_RETRY could be retries if the file they are interested didn't change. // All other request handlers + .on_with::<lsp_request::DocumentDiagnosticRequest>(handlers::handle_document_diagnostics, || lsp_types::DocumentDiagnosticReportResult::Report( + lsp_types::DocumentDiagnosticReport::Full( + lsp_types::RelatedFullDocumentDiagnosticReport { + related_documents: None, + full_document_diagnostic_report: lsp_types::FullDocumentDiagnosticReport { + result_id: None, + items: vec![], + }, + }, + ), + ), || lsp_server::ResponseError { + code: lsp_server::ErrorCode::ServerCancelled as i32, + message: "server cancelled the request".to_owned(), + data: serde_json::to_value(lsp_types::DiagnosticServerCancellationData { + retrigger_request: true + }).ok(), + }) .on::<RETRY, lsp_request::DocumentSymbolRequest>(handlers::handle_document_symbol) .on::<RETRY, lsp_request::FoldingRangeRequest>(handlers::handle_folding_range) .on::<NO_RETRY, lsp_request::SignatureHelpRequest>(handlers::handle_signature_help) diff --git a/src/tools/rust-analyzer/crates/rust-analyzer/src/tracing/config.rs b/src/tools/rust-analyzer/crates/rust-analyzer/src/tracing/config.rs index 5ab2dc2b67a..02ae4186ab6 100644 --- a/src/tools/rust-analyzer/crates/rust-analyzer/src/tracing/config.rs +++ b/src/tools/rust-analyzer/crates/rust-analyzer/src/tracing/config.rs @@ -58,14 +58,22 @@ where let writer = self.writer; let ra_fmt_layer = tracing_subscriber::fmt::layer() - .with_timer( - time::OffsetTime::local_rfc_3339() - .expect("Could not get local offset, make sure you're on the main thread"), - ) .with_target(false) .with_ansi(false) - .with_writer(writer) - .with_filter(targets_filter); + .with_writer(writer); + + let ra_fmt_layer = match time::OffsetTime::local_rfc_3339() { + Ok(timer) => { + // If we can get the time offset, format logs with the timezone. + ra_fmt_layer.with_timer(timer).boxed() + } + Err(_) => { + // Use system time if we can't get the time offset. This should + // never happen on Linux, but can happen on e.g. OpenBSD. + ra_fmt_layer.boxed() + } + } + .with_filter(targets_filter); let chalk_layer = match self.chalk_filter { Some(chalk_filter) => { diff --git a/src/tools/rust-analyzer/crates/rust-analyzer/src/tracing/hprof.rs b/src/tools/rust-analyzer/crates/rust-analyzer/src/tracing/hprof.rs index cad92962f34..d466acef011 100644 --- a/src/tools/rust-analyzer/crates/rust-analyzer/src/tracing/hprof.rs +++ b/src/tools/rust-analyzer/crates/rust-analyzer/src/tracing/hprof.rs @@ -120,7 +120,7 @@ pub struct DataVisitor<'a> { string: &'a mut String, } -impl<'a> Visit for DataVisitor<'a> { +impl Visit for DataVisitor<'_> { fn record_debug(&mut self, field: &Field, value: &dyn std::fmt::Debug) { write!(self.string, "{} = {:?} ", field.name(), value).unwrap(); } diff --git a/src/tools/rust-analyzer/crates/rust-analyzer/tests/slow-tests/cli.rs b/src/tools/rust-analyzer/crates/rust-analyzer/tests/slow-tests/cli.rs new file mode 100644 index 00000000000..fba54666912 --- /dev/null +++ b/src/tools/rust-analyzer/crates/rust-analyzer/tests/slow-tests/cli.rs @@ -0,0 +1,131 @@ +use expect_test::expect; +use test_utils::skip_slow_tests; + +use crate::support::Project; + +// If you choose to change the test fixture here, please inform the ferrocene/needy maintainers by +// opening an issue at https://github.com/ferrocene/needy as the tool relies on specific token +// mapping behavior. +#[test] +fn lsif_contains_generated_constant() { + if skip_slow_tests() { + return; + } + + let stdout = Project::with_fixture( + r#" +//- /Cargo.toml +[package] +name = "foo" +version = "0.0.0" + +//- /src/lib.rs +#![allow(unused)] + +macro_rules! generate_const_from_identifier( + ($id:ident) => ( + const _: () = { const $id: &str = "encoded_data"; }; + ) +); + +generate_const_from_identifier!(REQ_001); +mod tests { + use super::*; + generate_const_from_identifier!(REQ_002); +} +"#, + ) + .root("foo") + .run_lsif(); + let n = stdout.find(r#"{"id":2,"#).unwrap(); + // the first 2 entries contain paths that are not stable + let stdout = &stdout[n..]; + expect![[r#" + {"id":2,"type":"vertex","label":"foldingRangeResult","result":[{"startLine":2,"startCharacter":43,"endLine":6,"endCharacter":1},{"startLine":3,"startCharacter":19,"endLine":5,"endCharacter":5},{"startLine":9,"startCharacter":10,"endLine":12,"endCharacter":1}]} + {"id":3,"type":"edge","label":"textDocument/foldingRange","inV":2,"outV":1} + {"id":4,"type":"vertex","label":"range","start":{"line":0,"character":3},"end":{"line":0,"character":8}} + {"id":5,"type":"vertex","label":"resultSet"} + {"id":6,"type":"edge","label":"next","inV":5,"outV":4} + {"id":7,"type":"vertex","label":"range","start":{"line":2,"character":13},"end":{"line":2,"character":43}} + {"id":8,"type":"vertex","label":"resultSet"} + {"id":9,"type":"edge","label":"next","inV":8,"outV":7} + {"id":10,"type":"vertex","label":"range","start":{"line":8,"character":0},"end":{"line":8,"character":30}} + {"id":11,"type":"edge","label":"next","inV":8,"outV":10} + {"id":12,"type":"vertex","label":"range","start":{"line":8,"character":32},"end":{"line":8,"character":39}} + {"id":13,"type":"vertex","label":"resultSet"} + {"id":14,"type":"edge","label":"next","inV":13,"outV":12} + {"id":15,"type":"vertex","label":"range","start":{"line":9,"character":4},"end":{"line":9,"character":9}} + {"id":16,"type":"vertex","label":"resultSet"} + {"id":17,"type":"edge","label":"next","inV":16,"outV":15} + {"id":18,"type":"vertex","label":"range","start":{"line":10,"character":8},"end":{"line":10,"character":13}} + {"id":19,"type":"vertex","label":"resultSet"} + {"id":20,"type":"edge","label":"next","inV":19,"outV":18} + {"id":21,"type":"vertex","label":"range","start":{"line":11,"character":4},"end":{"line":11,"character":34}} + {"id":22,"type":"edge","label":"next","inV":8,"outV":21} + {"id":23,"type":"vertex","label":"range","start":{"line":11,"character":36},"end":{"line":11,"character":43}} + {"id":24,"type":"vertex","label":"resultSet"} + {"id":25,"type":"edge","label":"next","inV":24,"outV":23} + {"id":26,"type":"edge","label":"contains","inVs":[4,7,10,12,15,18,21,23],"outV":1} + {"id":27,"type":"vertex","label":"hoverResult","result":{"contents":{"kind":"markdown","value":"\n```rust\n#[allow]\n```\n\n---\n\nValid forms are:\n\n* \\#\\[allow(lint1, lint2, ..., /\\*opt\\*/ reason = \"...\")\\]"}}} + {"id":28,"type":"edge","label":"textDocument/hover","inV":27,"outV":5} + {"id":29,"type":"vertex","label":"referenceResult"} + {"id":30,"type":"edge","label":"textDocument/references","inV":29,"outV":5} + {"id":31,"type":"edge","label":"item","document":1,"property":"references","inVs":[4],"outV":29} + {"id":32,"type":"vertex","label":"hoverResult","result":{"contents":{"kind":"markdown","value":"\n```rust\nfoo\n```\n\n```rust\nmacro_rules! generate_const_from_identifier\n```"}}} + {"id":33,"type":"edge","label":"textDocument/hover","inV":32,"outV":8} + {"id":34,"type":"vertex","label":"packageInformation","name":"foo","manager":"cargo","version":"0.0.0"} + {"id":35,"type":"vertex","label":"moniker","scheme":"rust-analyzer","identifier":"foo::generate_const_from_identifier","unique":"scheme","kind":"export"} + {"id":36,"type":"edge","label":"packageInformation","inV":34,"outV":35} + {"id":37,"type":"edge","label":"moniker","inV":35,"outV":8} + {"id":38,"type":"vertex","label":"definitionResult"} + {"id":39,"type":"edge","label":"item","document":1,"inVs":[7],"outV":38} + {"id":40,"type":"edge","label":"textDocument/definition","inV":38,"outV":8} + {"id":41,"type":"vertex","label":"referenceResult"} + {"id":42,"type":"edge","label":"textDocument/references","inV":41,"outV":8} + {"id":43,"type":"edge","label":"item","document":1,"property":"definitions","inVs":[7],"outV":41} + {"id":44,"type":"edge","label":"item","document":1,"property":"references","inVs":[10,21],"outV":41} + {"id":45,"type":"vertex","label":"hoverResult","result":{"contents":{"kind":"markdown","value":"\n```rust\nfoo\n```\n\n```rust\nconst REQ_001: &str = \"encoded_data\"\n```"}}} + {"id":46,"type":"edge","label":"textDocument/hover","inV":45,"outV":13} + {"id":47,"type":"vertex","label":"moniker","scheme":"rust-analyzer","identifier":"foo::REQ_001","unique":"scheme","kind":"export"} + {"id":48,"type":"edge","label":"packageInformation","inV":34,"outV":47} + {"id":49,"type":"edge","label":"moniker","inV":47,"outV":13} + {"id":50,"type":"vertex","label":"definitionResult"} + {"id":51,"type":"edge","label":"item","document":1,"inVs":[12],"outV":50} + {"id":52,"type":"edge","label":"textDocument/definition","inV":50,"outV":13} + {"id":53,"type":"vertex","label":"referenceResult"} + {"id":54,"type":"edge","label":"textDocument/references","inV":53,"outV":13} + {"id":55,"type":"edge","label":"item","document":1,"property":"definitions","inVs":[12],"outV":53} + {"id":56,"type":"vertex","label":"hoverResult","result":{"contents":{"kind":"markdown","value":"\n```rust\nfoo\n```\n\n```rust\nmod tests\n```"}}} + {"id":57,"type":"edge","label":"textDocument/hover","inV":56,"outV":16} + {"id":58,"type":"vertex","label":"moniker","scheme":"rust-analyzer","identifier":"foo::tests","unique":"scheme","kind":"export"} + {"id":59,"type":"edge","label":"packageInformation","inV":34,"outV":58} + {"id":60,"type":"edge","label":"moniker","inV":58,"outV":16} + {"id":61,"type":"vertex","label":"definitionResult"} + {"id":62,"type":"edge","label":"item","document":1,"inVs":[15],"outV":61} + {"id":63,"type":"edge","label":"textDocument/definition","inV":61,"outV":16} + {"id":64,"type":"vertex","label":"referenceResult"} + {"id":65,"type":"edge","label":"textDocument/references","inV":64,"outV":16} + {"id":66,"type":"edge","label":"item","document":1,"property":"definitions","inVs":[15],"outV":64} + {"id":67,"type":"vertex","label":"hoverResult","result":{"contents":{"kind":"markdown","value":"\n```rust\nextern crate foo\n```"}}} + {"id":68,"type":"edge","label":"textDocument/hover","inV":67,"outV":19} + {"id":69,"type":"vertex","label":"definitionResult"} + {"id":70,"type":"vertex","label":"range","start":{"line":0,"character":0},"end":{"line":13,"character":0}} + {"id":71,"type":"edge","label":"contains","inVs":[70],"outV":1} + {"id":72,"type":"edge","label":"item","document":1,"inVs":[70],"outV":69} + {"id":73,"type":"edge","label":"textDocument/definition","inV":69,"outV":19} + {"id":74,"type":"vertex","label":"referenceResult"} + {"id":75,"type":"edge","label":"textDocument/references","inV":74,"outV":19} + {"id":76,"type":"edge","label":"item","document":1,"property":"references","inVs":[18],"outV":74} + {"id":77,"type":"vertex","label":"hoverResult","result":{"contents":{"kind":"markdown","value":"\n```rust\nfoo::tests\n```\n\n```rust\nconst REQ_002: &str = \"encoded_data\"\n```"}}} + {"id":78,"type":"edge","label":"textDocument/hover","inV":77,"outV":24} + {"id":79,"type":"vertex","label":"moniker","scheme":"rust-analyzer","identifier":"foo::tests::REQ_002","unique":"scheme","kind":"export"} + {"id":80,"type":"edge","label":"packageInformation","inV":34,"outV":79} + {"id":81,"type":"edge","label":"moniker","inV":79,"outV":24} + {"id":82,"type":"vertex","label":"definitionResult"} + {"id":83,"type":"edge","label":"item","document":1,"inVs":[23],"outV":82} + {"id":84,"type":"edge","label":"textDocument/definition","inV":82,"outV":24} + {"id":85,"type":"vertex","label":"referenceResult"} + {"id":86,"type":"edge","label":"textDocument/references","inV":85,"outV":24} + {"id":87,"type":"edge","label":"item","document":1,"property":"definitions","inVs":[23],"outV":85} + "#]].assert_eq(stdout); +} diff --git a/src/tools/rust-analyzer/crates/rust-analyzer/tests/slow-tests/main.rs b/src/tools/rust-analyzer/crates/rust-analyzer/tests/slow-tests/main.rs index 54cd27f4b3b..97c76bf8d17 100644 --- a/src/tools/rust-analyzer/crates/rust-analyzer/tests/slow-tests/main.rs +++ b/src/tools/rust-analyzer/crates/rust-analyzer/tests/slow-tests/main.rs @@ -10,6 +10,7 @@ #![allow(clippy::disallowed_types)] +mod cli; mod ratoml; mod support; mod testdir; diff --git a/src/tools/rust-analyzer/crates/rust-analyzer/tests/slow-tests/support.rs b/src/tools/rust-analyzer/crates/rust-analyzer/tests/slow-tests/support.rs index 18aface632d..78572e37a9b 100644 --- a/src/tools/rust-analyzer/crates/rust-analyzer/tests/slow-tests/support.rs +++ b/src/tools/rust-analyzer/crates/rust-analyzer/tests/slow-tests/support.rs @@ -6,11 +6,13 @@ use std::{ }; use crossbeam_channel::{after, select, Receiver}; +use itertools::Itertools; use lsp_server::{Connection, Message, Notification, Request}; use lsp_types::{notification::Exit, request::Shutdown, TextDocumentIdentifier, Url}; use parking_lot::{Mutex, MutexGuard}; use paths::{Utf8Path, Utf8PathBuf}; use rust_analyzer::{ + cli::flags, config::{Config, ConfigChange, ConfigErrors}, lsp, main_loop, }; @@ -84,6 +86,46 @@ impl Project<'_> { self } + pub(crate) fn run_lsif(self) -> String { + let tmp_dir = self.tmp_dir.unwrap_or_else(|| { + if self.root_dir_contains_symlink { + TestDir::new_symlink() + } else { + TestDir::new() + } + }); + + let FixtureWithProjectMeta { + fixture, + mini_core, + proc_macro_names, + toolchain, + target_data_layout: _, + } = FixtureWithProjectMeta::parse(self.fixture); + assert!(proc_macro_names.is_empty()); + assert!(mini_core.is_none()); + assert!(toolchain.is_none()); + + for entry in fixture { + let path = tmp_dir.path().join(&entry.path['/'.len_utf8()..]); + fs::create_dir_all(path.parent().unwrap()).unwrap(); + fs::write(path.as_path(), entry.text.as_bytes()).unwrap(); + } + + let tmp_dir_path = AbsPathBuf::assert(tmp_dir.path().to_path_buf()); + let mut buf = Vec::new(); + flags::Lsif::run( + flags::Lsif { + path: tmp_dir_path.join(self.roots.iter().exactly_one().unwrap()).into(), + exclude_vendored_libraries: false, + }, + &mut buf, + None, + ) + .unwrap(); + String::from_utf8(buf).unwrap() + } + pub(crate) fn server(self) -> Server { static CONFIG_DIR_LOCK: Mutex<()> = Mutex::new(()); let tmp_dir = self.tmp_dir.unwrap_or_else(|| { diff --git a/src/tools/rust-analyzer/crates/span/src/ast_id.rs b/src/tools/rust-analyzer/crates/span/src/ast_id.rs index 0ebd72e1514..1d81d684511 100644 --- a/src/tools/rust-analyzer/crates/span/src/ast_id.rs +++ b/src/tools/rust-analyzer/crates/span/src/ast_id.rs @@ -224,9 +224,10 @@ impl AstIdMap { match self.map.raw_entry().from_hash(hash, |&idx| self.arena[idx] == ptr) { Some((&idx, &())) => ErasedFileAstId(idx.into_raw().into_u32()), None => panic!( - "Can't find {:?} in AstIdMap:\n{:?}", + "Can't find {:?} in AstIdMap:\n{:?}\n source text: {}", item, self.arena.iter().map(|(_id, i)| i).collect::<Vec<_>>(), + item ), } } diff --git a/src/tools/rust-analyzer/crates/stdx/src/lib.rs b/src/tools/rust-analyzer/crates/stdx/src/lib.rs index 76dbd42ff6b..04c2153abf4 100644 --- a/src/tools/rust-analyzer/crates/stdx/src/lib.rs +++ b/src/tools/rust-analyzer/crates/stdx/src/lib.rs @@ -10,6 +10,7 @@ pub mod non_empty_vec; pub mod panic_context; pub mod process; pub mod rand; +pub mod thin_vec; pub mod thread; pub use always_assert::{always, never}; @@ -304,22 +305,6 @@ pub fn slice_tails<T>(this: &[T]) -> impl Iterator<Item = &[T]> { (0..this.len()).map(|i| &this[i..]) } -pub trait IsNoneOr { - type Type; - #[allow(clippy::wrong_self_convention)] - fn is_none_or(self, s: impl FnOnce(Self::Type) -> bool) -> bool; -} -#[allow(unstable_name_collisions)] -impl<T> IsNoneOr for Option<T> { - type Type = T; - fn is_none_or(self, f: impl FnOnce(T) -> bool) -> bool { - match self { - Some(v) => f(v), - None => true, - } - } -} - #[cfg(test)] mod tests { use super::*; diff --git a/src/tools/rust-analyzer/crates/stdx/src/thin_vec.rs b/src/tools/rust-analyzer/crates/stdx/src/thin_vec.rs new file mode 100644 index 00000000000..700220e1d3e --- /dev/null +++ b/src/tools/rust-analyzer/crates/stdx/src/thin_vec.rs @@ -0,0 +1,472 @@ +use std::alloc::{dealloc, handle_alloc_error, Layout}; +use std::fmt; +use std::hash::{Hash, Hasher}; +use std::marker::PhantomData; +use std::ops::{Deref, DerefMut}; +use std::ptr::{addr_of_mut, slice_from_raw_parts_mut, NonNull}; + +/// A type that is functionally equivalent to `(Header, Box<[Item]>)`, +/// but all data is stored in one heap allocation and the pointer is thin, +/// so the whole thing's size is like a pointer. +pub struct ThinVecWithHeader<Header, Item> { + /// INVARIANT: Points to a valid heap allocation that contains `ThinVecInner<Header>`, + /// followed by (suitably aligned) `len` `Item`s. + ptr: NonNull<ThinVecInner<Header>>, + _marker: PhantomData<(Header, Box<[Item]>)>, +} + +// SAFETY: We essentially own both the header and the items. +unsafe impl<Header: Send, Item: Send> Send for ThinVecWithHeader<Header, Item> {} +unsafe impl<Header: Sync, Item: Sync> Sync for ThinVecWithHeader<Header, Item> {} + +#[derive(Clone)] +struct ThinVecInner<Header> { + header: Header, + len: usize, +} + +impl<Header, Item> ThinVecWithHeader<Header, Item> { + /// # Safety + /// + /// The iterator must produce `len` elements. + #[inline] + unsafe fn from_trusted_len_iter( + header: Header, + len: usize, + items: impl Iterator<Item = Item>, + ) -> Self { + let (ptr, layout, items_offset) = Self::allocate(len); + + struct DeallocGuard(*mut u8, Layout); + impl Drop for DeallocGuard { + fn drop(&mut self) { + // SAFETY: We allocated this above. + unsafe { + dealloc(self.0, self.1); + } + } + } + let _dealloc_guard = DeallocGuard(ptr.as_ptr().cast::<u8>(), layout); + + // INVARIANT: Between `0..1` there are only initialized items. + struct ItemsGuard<Item>(*mut Item, *mut Item); + impl<Item> Drop for ItemsGuard<Item> { + fn drop(&mut self) { + // SAFETY: Our invariant. + unsafe { + slice_from_raw_parts_mut(self.0, self.1.offset_from(self.0) as usize) + .drop_in_place(); + } + } + } + + // SAFETY: We allocated enough space. + let mut items_ptr = unsafe { ptr.as_ptr().byte_add(items_offset).cast::<Item>() }; + // INVARIANT: There are zero elements in this range. + let mut items_guard = ItemsGuard(items_ptr, items_ptr); + items.for_each(|item| { + // SAFETY: Our precondition guarantee we won't get more than `len` items, and we allocated + // enough space for `len` items. + unsafe { + items_ptr.write(item); + items_ptr = items_ptr.add(1); + } + // INVARIANT: We just initialized this item. + items_guard.1 = items_ptr; + }); + + // SAFETY: We allocated enough space. + unsafe { + ptr.write(ThinVecInner { header, len }); + } + + std::mem::forget(items_guard); + + std::mem::forget(_dealloc_guard); + + // INVARIANT: We allocated and initialized all fields correctly. + Self { ptr, _marker: PhantomData } + } + + #[inline] + fn allocate(len: usize) -> (NonNull<ThinVecInner<Header>>, Layout, usize) { + let (layout, items_offset) = Self::layout(len); + // SAFETY: We always have `len`, so our allocation cannot be zero-sized. + let ptr = unsafe { std::alloc::alloc(layout).cast::<ThinVecInner<Header>>() }; + let Some(ptr) = NonNull::<ThinVecInner<Header>>::new(ptr) else { + handle_alloc_error(layout); + }; + (ptr, layout, items_offset) + } + + #[inline] + #[allow(clippy::should_implement_trait)] + pub fn from_iter<I>(header: Header, items: I) -> Self + where + I: IntoIterator, + I::IntoIter: TrustedLen<Item = Item>, + { + let items = items.into_iter(); + // SAFETY: `TrustedLen` guarantees the iterator length is exact. + unsafe { Self::from_trusted_len_iter(header, items.len(), items) } + } + + #[inline] + fn items_offset(&self) -> usize { + // SAFETY: We `pad_to_align()` in `layout()`, so at most where accessing past the end of the allocation, + // which is allowed. + unsafe { + Layout::new::<ThinVecInner<Header>>().extend(Layout::new::<Item>()).unwrap_unchecked().1 + } + } + + #[inline] + fn header_and_len(&self) -> &ThinVecInner<Header> { + // SAFETY: By `ptr`'s invariant, it is correctly allocated and initialized. + unsafe { &*self.ptr.as_ptr() } + } + + #[inline] + fn items_ptr(&self) -> *mut [Item] { + let len = self.header_and_len().len; + // SAFETY: `items_offset()` returns the correct offset of the items, where they are allocated. + let ptr = unsafe { self.ptr.as_ptr().byte_add(self.items_offset()).cast::<Item>() }; + slice_from_raw_parts_mut(ptr, len) + } + + #[inline] + pub fn header(&self) -> &Header { + &self.header_and_len().header + } + + #[inline] + pub fn header_mut(&mut self) -> &mut Header { + // SAFETY: By `ptr`'s invariant, it is correctly allocated and initialized. + unsafe { &mut *addr_of_mut!((*self.ptr.as_ptr()).header) } + } + + #[inline] + pub fn items(&self) -> &[Item] { + // SAFETY: `items_ptr()` gives a valid pointer. + unsafe { &*self.items_ptr() } + } + + #[inline] + pub fn items_mut(&mut self) -> &mut [Item] { + // SAFETY: `items_ptr()` gives a valid pointer. + unsafe { &mut *self.items_ptr() } + } + + #[inline] + pub fn len(&self) -> usize { + self.header_and_len().len + } + + #[inline] + fn layout(len: usize) -> (Layout, usize) { + let (layout, items_offset) = Layout::new::<ThinVecInner<Header>>() + .extend(Layout::array::<Item>(len).expect("too big `ThinVec` requested")) + .expect("too big `ThinVec` requested"); + let layout = layout.pad_to_align(); + (layout, items_offset) + } +} + +/// # Safety +/// +/// The length reported must be exactly the number of items yielded. +pub unsafe trait TrustedLen: ExactSizeIterator {} + +unsafe impl<T> TrustedLen for std::vec::IntoIter<T> {} +unsafe impl<T> TrustedLen for std::slice::Iter<'_, T> {} +unsafe impl<'a, T: Clone + 'a, I: TrustedLen<Item = &'a T>> TrustedLen for std::iter::Cloned<I> {} +unsafe impl<T, I: TrustedLen, F: FnMut(I::Item) -> T> TrustedLen for std::iter::Map<I, F> {} +unsafe impl<T> TrustedLen for std::vec::Drain<'_, T> {} +unsafe impl<T, const N: usize> TrustedLen for std::array::IntoIter<T, N> {} + +impl<Header: Clone, Item: Clone> Clone for ThinVecWithHeader<Header, Item> { + #[inline] + fn clone(&self) -> Self { + Self::from_iter(self.header().clone(), self.items().iter().cloned()) + } +} + +impl<Header, Item> Drop for ThinVecWithHeader<Header, Item> { + #[inline] + fn drop(&mut self) { + // This must come before we drop `header`, because after that we cannot make a reference to it in `len()`. + let len = self.len(); + + // SAFETY: The contents are allocated and initialized. + unsafe { + addr_of_mut!((*self.ptr.as_ptr()).header).drop_in_place(); + self.items_ptr().drop_in_place(); + } + + let (layout, _) = Self::layout(len); + // SAFETY: This was allocated in `new()` with the same layout calculation. + unsafe { + dealloc(self.ptr.as_ptr().cast::<u8>(), layout); + } + } +} + +impl<Header: fmt::Debug, Item: fmt::Debug> fmt::Debug for ThinVecWithHeader<Header, Item> { + fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { + f.debug_struct("ThinVecWithHeader") + .field("header", self.header()) + .field("items", &self.items()) + .finish() + } +} + +impl<Header: PartialEq, Item: PartialEq> PartialEq for ThinVecWithHeader<Header, Item> { + #[inline] + fn eq(&self, other: &Self) -> bool { + self.header() == other.header() && self.items() == other.items() + } +} + +impl<Header: Eq, Item: Eq> Eq for ThinVecWithHeader<Header, Item> {} + +impl<Header: Hash, Item: Hash> Hash for ThinVecWithHeader<Header, Item> { + #[inline] + fn hash<H: Hasher>(&self, state: &mut H) { + self.header().hash(state); + self.items().hash(state); + } +} + +#[derive(Clone, PartialEq, Eq, Hash)] +pub struct ThinVec<T>(ThinVecWithHeader<(), T>); + +impl<T> ThinVec<T> { + #[inline] + #[allow(clippy::should_implement_trait)] + pub fn from_iter<I>(values: I) -> Self + where + I: IntoIterator, + I::IntoIter: TrustedLen<Item = T>, + { + Self(ThinVecWithHeader::from_iter((), values)) + } + + #[inline] + pub fn len(&self) -> usize { + self.0.len() + } + + #[inline] + pub fn iter(&self) -> std::slice::Iter<'_, T> { + (**self).iter() + } + + #[inline] + pub fn iter_mut(&mut self) -> std::slice::IterMut<'_, T> { + (**self).iter_mut() + } +} + +impl<T> Deref for ThinVec<T> { + type Target = [T]; + + #[inline] + fn deref(&self) -> &Self::Target { + self.0.items() + } +} + +impl<T> DerefMut for ThinVec<T> { + #[inline] + fn deref_mut(&mut self) -> &mut Self::Target { + self.0.items_mut() + } +} + +impl<'a, T> IntoIterator for &'a ThinVec<T> { + type IntoIter = std::slice::Iter<'a, T>; + type Item = &'a T; + + #[inline] + fn into_iter(self) -> Self::IntoIter { + self.iter() + } +} + +impl<'a, T> IntoIterator for &'a mut ThinVec<T> { + type IntoIter = std::slice::IterMut<'a, T>; + type Item = &'a mut T; + + #[inline] + fn into_iter(self) -> Self::IntoIter { + self.iter_mut() + } +} + +impl<T: fmt::Debug> fmt::Debug for ThinVec<T> { + fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { + f.debug_list().entries(&**self).finish() + } +} + +/// A [`ThinVec`] that requires no allocation for the empty case. +#[derive(Clone, PartialEq, Eq, Hash)] +pub struct EmptyOptimizedThinVec<T>(Option<ThinVec<T>>); + +impl<T> EmptyOptimizedThinVec<T> { + #[inline] + #[allow(clippy::should_implement_trait)] + pub fn from_iter<I>(values: I) -> Self + where + I: IntoIterator, + I::IntoIter: TrustedLen<Item = T>, + { + let values = values.into_iter(); + if values.len() == 0 { + Self::empty() + } else { + Self(Some(ThinVec::from_iter(values))) + } + } + + #[inline] + pub fn empty() -> Self { + Self(None) + } + + #[inline] + pub fn len(&self) -> usize { + self.0.as_ref().map_or(0, ThinVec::len) + } + + #[inline] + pub fn iter(&self) -> std::slice::Iter<'_, T> { + (**self).iter() + } + + #[inline] + pub fn iter_mut(&mut self) -> std::slice::IterMut<'_, T> { + (**self).iter_mut() + } +} + +impl<T> Default for EmptyOptimizedThinVec<T> { + #[inline] + fn default() -> Self { + Self::empty() + } +} + +impl<T> Deref for EmptyOptimizedThinVec<T> { + type Target = [T]; + + #[inline] + fn deref(&self) -> &Self::Target { + self.0.as_deref().unwrap_or_default() + } +} + +impl<T> DerefMut for EmptyOptimizedThinVec<T> { + #[inline] + fn deref_mut(&mut self) -> &mut Self::Target { + self.0.as_deref_mut().unwrap_or_default() + } +} + +impl<'a, T> IntoIterator for &'a EmptyOptimizedThinVec<T> { + type IntoIter = std::slice::Iter<'a, T>; + type Item = &'a T; + + #[inline] + fn into_iter(self) -> Self::IntoIter { + self.iter() + } +} + +impl<'a, T> IntoIterator for &'a mut EmptyOptimizedThinVec<T> { + type IntoIter = std::slice::IterMut<'a, T>; + type Item = &'a mut T; + + #[inline] + fn into_iter(self) -> Self::IntoIter { + self.iter_mut() + } +} + +impl<T: fmt::Debug> fmt::Debug for EmptyOptimizedThinVec<T> { + fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { + f.debug_list().entries(&**self).finish() + } +} + +/// Syntax: +/// +/// ```ignore +/// thin_vec_with_header_struct! { +/// pub new(pub(crate)) struct MyCoolStruct, MyCoolStructHeader { +/// pub(crate) variable_length: [Ty], +/// pub field1: CopyTy, +/// pub field2: NonCopyTy; ref, +/// } +/// } +/// ``` +#[doc(hidden)] +#[macro_export] +macro_rules! thin_vec_with_header_struct_ { + (@maybe_ref (ref) $($t:tt)*) => { &$($t)* }; + (@maybe_ref () $($t:tt)*) => { $($t)* }; + ( + $vis:vis new($new_vis:vis) struct $struct:ident, $header:ident { + $items_vis:vis $items:ident : [$items_ty:ty], + $( $header_var_vis:vis $header_var:ident : $header_var_ty:ty $(; $ref:ident)?, )+ + } + ) => { + #[derive(Debug, Clone, Eq, PartialEq, Hash)] + struct $header { + $( $header_var : $header_var_ty, )+ + } + + #[derive(Clone, Eq, PartialEq, Hash)] + $vis struct $struct($crate::thin_vec::ThinVecWithHeader<$header, $items_ty>); + + impl $struct { + #[inline] + #[allow(unused)] + $new_vis fn new<I>( + $( $header_var: $header_var_ty, )+ + $items: I, + ) -> Self + where + I: ::std::iter::IntoIterator, + I::IntoIter: $crate::thin_vec::TrustedLen<Item = $items_ty>, + { + Self($crate::thin_vec::ThinVecWithHeader::from_iter( + $header { $( $header_var, )+ }, + $items, + )) + } + + #[inline] + $items_vis fn $items(&self) -> &[$items_ty] { + self.0.items() + } + + $( + #[inline] + $header_var_vis fn $header_var(&self) -> $crate::thin_vec_with_header_struct_!(@maybe_ref ($($ref)?) $header_var_ty) { + $crate::thin_vec_with_header_struct_!(@maybe_ref ($($ref)?) self.0.header().$header_var) + } + )+ + } + + impl ::std::fmt::Debug for $struct { + fn fmt(&self, f: &mut ::std::fmt::Formatter<'_>) -> ::std::fmt::Result { + f.debug_struct(stringify!($struct)) + $( .field(stringify!($header_var), &self.$header_var()) )* + .field(stringify!($items), &self.$items()) + .finish() + } + } + }; +} +pub use crate::thin_vec_with_header_struct_ as thin_vec_with_header_struct; diff --git a/src/tools/rust-analyzer/crates/syntax/Cargo.toml b/src/tools/rust-analyzer/crates/syntax/Cargo.toml index fcb9b0ea354..51eaea54346 100644 --- a/src/tools/rust-analyzer/crates/syntax/Cargo.toml +++ b/src/tools/rust-analyzer/crates/syntax/Cargo.toml @@ -27,7 +27,6 @@ ra-ap-rustc_lexer.workspace = true parser.workspace = true stdx.workspace = true -text-edit.workspace = true [dev-dependencies] rayon.workspace = true diff --git a/src/tools/rust-analyzer/crates/syntax/rust.ungram b/src/tools/rust-analyzer/crates/syntax/rust.ungram index 90441c27f62..02c59646a99 100644 --- a/src/tools/rust-analyzer/crates/syntax/rust.ungram +++ b/src/tools/rust-analyzer/crates/syntax/rust.ungram @@ -657,7 +657,14 @@ TypeBoundList = TypeBound = Lifetime | ('~' 'const' | 'const')? 'async'? '?'? Type -| 'use' GenericParamList +| 'use' UseBoundGenericArgs + +UseBoundGenericArgs = + '<' (UseBoundGenericArg (',' UseBoundGenericArg)* ','?)? '>' + +UseBoundGenericArg = + Lifetime +| NameRef //************************// // Patterns // @@ -729,7 +736,7 @@ PathPat = Path OrPat = - (Pat ('|' Pat)* '|'?) + '|'? (Pat ('|' Pat)*) BoxPat = 'box' Pat diff --git a/src/tools/rust-analyzer/crates/syntax/src/algo.rs b/src/tools/rust-analyzer/crates/syntax/src/algo.rs index 8dc6d36a7e7..2acb2158318 100644 --- a/src/tools/rust-analyzer/crates/syntax/src/algo.rs +++ b/src/tools/rust-analyzer/crates/syntax/src/algo.rs @@ -1,11 +1,6 @@ //! Collection of assorted algorithms for syntax trees. -use std::hash::BuildHasherDefault; - -use indexmap::IndexMap; use itertools::Itertools; -use rustc_hash::FxHashMap; -use text_edit::TextEditBuilder; use crate::{ AstNode, Direction, NodeOrToken, SyntaxElement, SyntaxKind, SyntaxNode, SyntaxToken, TextRange, @@ -101,559 +96,3 @@ pub fn neighbor<T: AstNode>(me: &T, direction: Direction) -> Option<T> { pub fn has_errors(node: &SyntaxNode) -> bool { node.children().any(|it| it.kind() == SyntaxKind::ERROR) } - -type FxIndexMap<K, V> = IndexMap<K, V, BuildHasherDefault<rustc_hash::FxHasher>>; - -#[derive(Debug, Hash, PartialEq, Eq)] -enum TreeDiffInsertPos { - After(SyntaxElement), - AsFirstChild(SyntaxElement), -} - -#[derive(Debug)] -pub struct TreeDiff { - replacements: FxHashMap<SyntaxElement, SyntaxElement>, - deletions: Vec<SyntaxElement>, - // the vec as well as the indexmap are both here to preserve order - insertions: FxIndexMap<TreeDiffInsertPos, Vec<SyntaxElement>>, -} - -impl TreeDiff { - pub fn into_text_edit(&self, builder: &mut TextEditBuilder) { - let _p = tracing::info_span!("into_text_edit").entered(); - - for (anchor, to) in &self.insertions { - let offset = match anchor { - TreeDiffInsertPos::After(it) => it.text_range().end(), - TreeDiffInsertPos::AsFirstChild(it) => it.text_range().start(), - }; - to.iter().for_each(|to| builder.insert(offset, to.to_string())); - } - for (from, to) in &self.replacements { - builder.replace(from.text_range(), to.to_string()); - } - for text_range in self.deletions.iter().map(SyntaxElement::text_range) { - builder.delete(text_range); - } - } - - pub fn is_empty(&self) -> bool { - self.replacements.is_empty() && self.deletions.is_empty() && self.insertions.is_empty() - } -} - -/// Finds a (potentially minimal) diff, which, applied to `from`, will result in `to`. -/// -/// Specifically, returns a structure that consists of a replacements, insertions and deletions -/// such that applying this map on `from` will result in `to`. -/// -/// This function tries to find a fine-grained diff. -pub fn diff(from: &SyntaxNode, to: &SyntaxNode) -> TreeDiff { - let _p = tracing::info_span!("diff").entered(); - - let mut diff = TreeDiff { - replacements: FxHashMap::default(), - insertions: FxIndexMap::default(), - deletions: Vec::new(), - }; - let (from, to) = (from.clone().into(), to.clone().into()); - - if !syntax_element_eq(&from, &to) { - go(&mut diff, from, to); - } - return diff; - - fn syntax_element_eq(lhs: &SyntaxElement, rhs: &SyntaxElement) -> bool { - lhs.kind() == rhs.kind() - && lhs.text_range().len() == rhs.text_range().len() - && match (&lhs, &rhs) { - (NodeOrToken::Node(lhs), NodeOrToken::Node(rhs)) => { - lhs == rhs || lhs.text() == rhs.text() - } - (NodeOrToken::Token(lhs), NodeOrToken::Token(rhs)) => lhs.text() == rhs.text(), - _ => false, - } - } - - // FIXME: this is horribly inefficient. I bet there's a cool algorithm to diff trees properly. - fn go(diff: &mut TreeDiff, lhs: SyntaxElement, rhs: SyntaxElement) { - let (lhs, rhs) = match lhs.as_node().zip(rhs.as_node()) { - Some((lhs, rhs)) => (lhs, rhs), - _ => { - cov_mark::hit!(diff_node_token_replace); - diff.replacements.insert(lhs, rhs); - return; - } - }; - - let mut look_ahead_scratch = Vec::default(); - - let mut rhs_children = rhs.children_with_tokens(); - let mut lhs_children = lhs.children_with_tokens(); - let mut last_lhs = None; - loop { - let lhs_child = lhs_children.next(); - match (lhs_child.clone(), rhs_children.next()) { - (None, None) => break, - (None, Some(element)) => { - let insert_pos = match last_lhs.clone() { - Some(prev) => { - cov_mark::hit!(diff_insert); - TreeDiffInsertPos::After(prev) - } - // first iteration, insert into out parent as the first child - None => { - cov_mark::hit!(diff_insert_as_first_child); - TreeDiffInsertPos::AsFirstChild(lhs.clone().into()) - } - }; - diff.insertions.entry(insert_pos).or_default().push(element); - } - (Some(element), None) => { - cov_mark::hit!(diff_delete); - diff.deletions.push(element); - } - (Some(ref lhs_ele), Some(ref rhs_ele)) if syntax_element_eq(lhs_ele, rhs_ele) => {} - (Some(lhs_ele), Some(rhs_ele)) => { - // nodes differ, look for lhs_ele in rhs, if its found we can mark everything up - // until that element as insertions. This is important to keep the diff minimal - // in regards to insertions that have been actually done, this is important for - // use insertions as we do not want to replace the entire module node. - look_ahead_scratch.push(rhs_ele.clone()); - let mut rhs_children_clone = rhs_children.clone(); - let mut insert = false; - for rhs_child in &mut rhs_children_clone { - if syntax_element_eq(&lhs_ele, &rhs_child) { - cov_mark::hit!(diff_insertions); - insert = true; - break; - } - look_ahead_scratch.push(rhs_child); - } - let drain = look_ahead_scratch.drain(..); - if insert { - let insert_pos = if let Some(prev) = last_lhs.clone().filter(|_| insert) { - TreeDiffInsertPos::After(prev) - } else { - cov_mark::hit!(insert_first_child); - TreeDiffInsertPos::AsFirstChild(lhs.clone().into()) - }; - - diff.insertions.entry(insert_pos).or_default().extend(drain); - rhs_children = rhs_children_clone; - } else { - go(diff, lhs_ele, rhs_ele); - } - } - } - last_lhs = lhs_child.or(last_lhs); - } - } -} - -#[cfg(test)] -mod tests { - use expect_test::{expect, Expect}; - use itertools::Itertools; - use parser::{Edition, SyntaxKind}; - use text_edit::TextEdit; - - use crate::{AstNode, SyntaxElement}; - - #[test] - fn replace_node_token() { - cov_mark::check!(diff_node_token_replace); - check_diff( - r#"use node;"#, - r#"ident"#, - expect![[r#" - insertions: - - - - replacements: - - Line 0: Token(USE_KW@0..3 "use") -> ident - - deletions: - - Line 1: " " - Line 1: node - Line 1: ; - "#]], - ); - } - - #[test] - fn replace_parent() { - cov_mark::check!(diff_insert_as_first_child); - check_diff( - r#""#, - r#"use foo::bar;"#, - expect![[r#" - insertions: - - Line 0: AsFirstChild(Node(SOURCE_FILE@0..0)) - -> use foo::bar; - - replacements: - - - - deletions: - - - "#]], - ); - } - - #[test] - fn insert_last() { - cov_mark::check!(diff_insert); - check_diff( - r#" -use foo; -use bar;"#, - r#" -use foo; -use bar; -use baz;"#, - expect![[r#" - insertions: - - Line 2: After(Node(USE@10..18)) - -> "\n" - -> use baz; - - replacements: - - - - deletions: - - - "#]], - ); - } - - #[test] - fn insert_middle() { - check_diff( - r#" -use foo; -use baz;"#, - r#" -use foo; -use bar; -use baz;"#, - expect![[r#" - insertions: - - Line 2: After(Token(WHITESPACE@9..10 "\n")) - -> use bar; - -> "\n" - - replacements: - - - - deletions: - - - "#]], - ) - } - - #[test] - fn insert_first() { - check_diff( - r#" -use bar; -use baz;"#, - r#" -use foo; -use bar; -use baz;"#, - expect![[r#" - insertions: - - Line 0: After(Token(WHITESPACE@0..1 "\n")) - -> use foo; - -> "\n" - - replacements: - - - - deletions: - - - "#]], - ) - } - - #[test] - fn first_child_insertion() { - cov_mark::check!(insert_first_child); - check_diff( - r#"fn main() { - stdi - }"#, - r#"use foo::bar; - - fn main() { - stdi - }"#, - expect![[r#" - insertions: - - Line 0: AsFirstChild(Node(SOURCE_FILE@0..30)) - -> use foo::bar; - -> "\n\n " - - replacements: - - - - deletions: - - - "#]], - ); - } - - #[test] - fn delete_last() { - cov_mark::check!(diff_delete); - check_diff( - r#"use foo; - use bar;"#, - r#"use foo;"#, - expect![[r#" - insertions: - - - - replacements: - - - - deletions: - - Line 1: "\n " - Line 2: use bar; - "#]], - ); - } - - #[test] - fn delete_middle() { - cov_mark::check!(diff_insertions); - check_diff( - r#" -use expect_test::{expect, Expect}; -use text_edit::TextEdit; - -use crate::AstNode; -"#, - r#" -use expect_test::{expect, Expect}; - -use crate::AstNode; -"#, - expect![[r#" - insertions: - - Line 1: After(Node(USE@1..35)) - -> "\n\n" - -> use crate::AstNode; - - replacements: - - - - deletions: - - Line 2: use text_edit::TextEdit; - Line 3: "\n\n" - Line 4: use crate::AstNode; - Line 5: "\n" - "#]], - ) - } - - #[test] - fn delete_first() { - check_diff( - r#" -use text_edit::TextEdit; - -use crate::AstNode; -"#, - r#" -use crate::AstNode; -"#, - expect![[r#" - insertions: - - - - replacements: - - Line 2: Token(IDENT@5..14 "text_edit") -> crate - Line 2: Token(IDENT@16..24 "TextEdit") -> AstNode - Line 2: Token(WHITESPACE@25..27 "\n\n") -> "\n" - - deletions: - - Line 3: use crate::AstNode; - Line 4: "\n" - "#]], - ) - } - - #[test] - fn merge_use() { - check_diff( - r#" -use std::{ - fmt, - hash::BuildHasherDefault, - ops::{self, RangeInclusive}, -}; -"#, - r#" -use std::fmt; -use std::hash::BuildHasherDefault; -use std::ops::{self, RangeInclusive}; -"#, - expect![[r#" - insertions: - - Line 2: After(Node(PATH_SEGMENT@5..8)) - -> :: - -> fmt - Line 6: After(Token(WHITESPACE@86..87 "\n")) - -> use std::hash::BuildHasherDefault; - -> "\n" - -> use std::ops::{self, RangeInclusive}; - -> "\n" - - replacements: - - Line 2: Token(IDENT@5..8 "std") -> std - - deletions: - - Line 2: :: - Line 2: { - fmt, - hash::BuildHasherDefault, - ops::{self, RangeInclusive}, - } - "#]], - ) - } - - #[test] - fn early_return_assist() { - check_diff( - r#" -fn main() { - if let Ok(x) = Err(92) { - foo(x); - } -} - "#, - r#" -fn main() { - let x = match Err(92) { - Ok(it) => it, - _ => return, - }; - foo(x); -} - "#, - expect![[r#" - insertions: - - Line 3: After(Node(BLOCK_EXPR@40..63)) - -> " " - -> match Err(92) { - Ok(it) => it, - _ => return, - } - -> ; - Line 3: After(Node(IF_EXPR@17..63)) - -> "\n " - -> foo(x); - - replacements: - - Line 3: Token(IF_KW@17..19 "if") -> let - Line 3: Token(LET_KW@20..23 "let") -> x - Line 3: Node(BLOCK_EXPR@40..63) -> = - - deletions: - - Line 3: " " - Line 3: Ok(x) - Line 3: " " - Line 3: = - Line 3: " " - Line 3: Err(92) - "#]], - ) - } - - fn check_diff(from: &str, to: &str, expected_diff: Expect) { - let from_node = crate::SourceFile::parse(from, Edition::CURRENT).tree().syntax().clone(); - let to_node = crate::SourceFile::parse(to, Edition::CURRENT).tree().syntax().clone(); - let diff = super::diff(&from_node, &to_node); - - let line_number = - |syn: &SyntaxElement| from[..syn.text_range().start().into()].lines().count(); - - let fmt_syntax = |syn: &SyntaxElement| match syn.kind() { - SyntaxKind::WHITESPACE => format!("{:?}", syn.to_string()), - _ => format!("{syn}"), - }; - - let insertions = - diff.insertions.iter().format_with("\n", |(k, v), f| -> Result<(), std::fmt::Error> { - f(&format!( - "Line {}: {:?}\n-> {}", - line_number(match k { - super::TreeDiffInsertPos::After(syn) => syn, - super::TreeDiffInsertPos::AsFirstChild(syn) => syn, - }), - k, - v.iter().format_with("\n-> ", |v, f| f(&fmt_syntax(v))) - )) - }); - - let replacements = diff - .replacements - .iter() - .sorted_by_key(|(syntax, _)| syntax.text_range().start()) - .format_with("\n", |(k, v), f| { - f(&format!("Line {}: {k:?} -> {}", line_number(k), fmt_syntax(v))) - }); - - let deletions = diff - .deletions - .iter() - .format_with("\n", |v, f| f(&format!("Line {}: {}", line_number(v), fmt_syntax(v)))); - - let actual = format!( - "insertions:\n\n{insertions}\n\nreplacements:\n\n{replacements}\n\ndeletions:\n\n{deletions}\n" - ); - expected_diff.assert_eq(&actual); - - let mut from = from.to_owned(); - let mut text_edit = TextEdit::builder(); - diff.into_text_edit(&mut text_edit); - text_edit.finish().apply(&mut from); - assert_eq!(&*from, to, "diff did not turn `from` to `to`"); - } -} diff --git a/src/tools/rust-analyzer/crates/syntax/src/ast/expr_ext.rs b/src/tools/rust-analyzer/crates/syntax/src/ast/expr_ext.rs index 6ed205e2856..f3053f59836 100644 --- a/src/tools/rust-analyzer/crates/syntax/src/ast/expr_ext.rs +++ b/src/tools/rust-analyzer/crates/syntax/src/ast/expr_ext.rs @@ -232,6 +232,10 @@ impl ast::RangeExpr { Some((ix, token, bin_op)) }) } + + pub fn is_range_full(&self) -> bool { + support::children::<Expr>(&self.syntax).next().is_none() + } } impl RangeItem for ast::RangeExpr { diff --git a/src/tools/rust-analyzer/crates/syntax/src/ast/generated/nodes.rs b/src/tools/rust-analyzer/crates/syntax/src/ast/generated/nodes.rs index 4f8bff489cf..23d2b355a94 100644 --- a/src/tools/rust-analyzer/crates/syntax/src/ast/generated/nodes.rs +++ b/src/tools/rust-analyzer/crates/syntax/src/ast/generated/nodes.rs @@ -1283,6 +1283,8 @@ pub struct OrPat { impl OrPat { #[inline] pub fn pats(&self) -> AstChildren<Pat> { support::children(&self.syntax) } + #[inline] + pub fn pipe_token(&self) -> Option<SyntaxToken> { support::token(&self.syntax, T![|]) } } #[derive(Debug, Clone, PartialEq, Eq, Hash)] @@ -1994,12 +1996,14 @@ pub struct TypeBound { } impl TypeBound { #[inline] - pub fn generic_param_list(&self) -> Option<GenericParamList> { support::child(&self.syntax) } - #[inline] pub fn lifetime(&self) -> Option<Lifetime> { support::child(&self.syntax) } #[inline] pub fn ty(&self) -> Option<Type> { support::child(&self.syntax) } #[inline] + pub fn use_bound_generic_args(&self) -> Option<UseBoundGenericArgs> { + support::child(&self.syntax) + } + #[inline] pub fn question_mark_token(&self) -> Option<SyntaxToken> { support::token(&self.syntax, T![?]) } #[inline] pub fn async_token(&self) -> Option<SyntaxToken> { support::token(&self.syntax, T![async]) } @@ -2077,6 +2081,21 @@ impl Use { } #[derive(Debug, Clone, PartialEq, Eq, Hash)] +pub struct UseBoundGenericArgs { + pub(crate) syntax: SyntaxNode, +} +impl UseBoundGenericArgs { + #[inline] + pub fn use_bound_generic_args(&self) -> AstChildren<UseBoundGenericArg> { + support::children(&self.syntax) + } + #[inline] + pub fn l_angle_token(&self) -> Option<SyntaxToken> { support::token(&self.syntax, T![<]) } + #[inline] + pub fn r_angle_token(&self) -> Option<SyntaxToken> { support::token(&self.syntax, T![>]) } +} + +#[derive(Debug, Clone, PartialEq, Eq, Hash)] pub struct UseTree { pub(crate) syntax: SyntaxNode, } @@ -2403,6 +2422,12 @@ pub enum Type { } #[derive(Debug, Clone, PartialEq, Eq, Hash)] +pub enum UseBoundGenericArg { + Lifetime(Lifetime), + NameRef(NameRef), +} + +#[derive(Debug, Clone, PartialEq, Eq, Hash)] pub struct AnyHasArgList { pub(crate) syntax: SyntaxNode, } @@ -4435,6 +4460,20 @@ impl AstNode for Use { #[inline] fn syntax(&self) -> &SyntaxNode { &self.syntax } } +impl AstNode for UseBoundGenericArgs { + #[inline] + fn can_cast(kind: SyntaxKind) -> bool { kind == USE_BOUND_GENERIC_ARGS } + #[inline] + fn cast(syntax: SyntaxNode) -> Option<Self> { + if Self::can_cast(syntax.kind()) { + Some(Self { syntax }) + } else { + None + } + } + #[inline] + fn syntax(&self) -> &SyntaxNode { &self.syntax } +} impl AstNode for UseTree { #[inline] fn can_cast(kind: SyntaxKind) -> bool { kind == USE_TREE } @@ -5560,6 +5599,34 @@ impl AstNode for Type { } } } +impl From<Lifetime> for UseBoundGenericArg { + #[inline] + fn from(node: Lifetime) -> UseBoundGenericArg { UseBoundGenericArg::Lifetime(node) } +} +impl From<NameRef> for UseBoundGenericArg { + #[inline] + fn from(node: NameRef) -> UseBoundGenericArg { UseBoundGenericArg::NameRef(node) } +} +impl AstNode for UseBoundGenericArg { + #[inline] + fn can_cast(kind: SyntaxKind) -> bool { matches!(kind, LIFETIME | NAME_REF) } + #[inline] + fn cast(syntax: SyntaxNode) -> Option<Self> { + let res = match syntax.kind() { + LIFETIME => UseBoundGenericArg::Lifetime(Lifetime { syntax }), + NAME_REF => UseBoundGenericArg::NameRef(NameRef { syntax }), + _ => return None, + }; + Some(res) + } + #[inline] + fn syntax(&self) -> &SyntaxNode { + match self { + UseBoundGenericArg::Lifetime(it) => &it.syntax, + UseBoundGenericArg::NameRef(it) => &it.syntax, + } + } +} impl AnyHasArgList { #[inline] pub fn new<T: ast::HasArgList>(node: T) -> AnyHasArgList { @@ -6570,6 +6637,11 @@ impl std::fmt::Display for Type { std::fmt::Display::fmt(self.syntax(), f) } } +impl std::fmt::Display for UseBoundGenericArg { + fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { + std::fmt::Display::fmt(self.syntax(), f) + } +} impl std::fmt::Display for Abi { fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { std::fmt::Display::fmt(self.syntax(), f) @@ -7275,6 +7347,11 @@ impl std::fmt::Display for Use { std::fmt::Display::fmt(self.syntax(), f) } } +impl std::fmt::Display for UseBoundGenericArgs { + fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { + std::fmt::Display::fmt(self.syntax(), f) + } +} impl std::fmt::Display for UseTree { fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { std::fmt::Display::fmt(self.syntax(), f) diff --git a/src/tools/rust-analyzer/crates/syntax/src/ast/node_ext.rs b/src/tools/rust-analyzer/crates/syntax/src/ast/node_ext.rs index 693bfe330bd..6ec73e76f78 100644 --- a/src/tools/rust-analyzer/crates/syntax/src/ast/node_ext.rs +++ b/src/tools/rust-analyzer/crates/syntax/src/ast/node_ext.rs @@ -795,7 +795,7 @@ pub enum TypeBoundKind { /// for<'a> ... ForType(ast::ForType), /// use - Use(ast::GenericParamList), + Use(ast::UseBoundGenericArgs), /// 'a Lifetime(ast::Lifetime), } @@ -806,8 +806,8 @@ impl ast::TypeBound { TypeBoundKind::PathType(path_type) } else if let Some(for_type) = support::children(self.syntax()).next() { TypeBoundKind::ForType(for_type) - } else if let Some(generic_param_list) = self.generic_param_list() { - TypeBoundKind::Use(generic_param_list) + } else if let Some(args) = self.use_bound_generic_args() { + TypeBoundKind::Use(args) } else if let Some(lifetime) = self.lifetime() { TypeBoundKind::Lifetime(lifetime) } else { @@ -1140,3 +1140,13 @@ impl From<ast::AssocItem> for ast::AnyHasAttrs { Self::new(node) } } + +impl ast::OrPat { + pub fn leading_pipe(&self) -> Option<SyntaxToken> { + self.syntax + .children_with_tokens() + .find(|it| !it.kind().is_trivia()) + .and_then(NodeOrToken::into_token) + .filter(|it| it.kind() == T![|]) + } +} diff --git a/src/tools/rust-analyzer/crates/syntax/src/fuzz.rs b/src/tools/rust-analyzer/crates/syntax/src/fuzz.rs index 682dcd7cc44..fd20e603edc 100644 --- a/src/tools/rust-analyzer/crates/syntax/src/fuzz.rs +++ b/src/tools/rust-analyzer/crates/syntax/src/fuzz.rs @@ -5,7 +5,6 @@ use std::str::{self, FromStr}; use parser::Edition; -use text_edit::Indel; use crate::{validation, AstNode, SourceFile, TextRange}; @@ -22,7 +21,8 @@ pub fn check_parser(text: &str) { #[derive(Debug, Clone)] pub struct CheckReparse { text: String, - edit: Indel, + delete: TextRange, + insert: String, edited_text: String, } @@ -43,14 +43,13 @@ impl CheckReparse { TextRange::at(delete_start.try_into().unwrap(), delete_len.try_into().unwrap()); let edited_text = format!("{}{}{}", &text[..delete_start], &insert, &text[delete_start + delete_len..]); - let edit = Indel { insert, delete }; - Some(CheckReparse { text, edit, edited_text }) + Some(CheckReparse { text, insert, delete, edited_text }) } #[allow(clippy::print_stderr)] pub fn run(&self) { let parse = SourceFile::parse(&self.text, Edition::CURRENT); - let new_parse = parse.reparse(&self.edit, Edition::CURRENT); + let new_parse = parse.reparse(self.delete, &self.insert, Edition::CURRENT); check_file_invariants(&new_parse.tree()); assert_eq!(&new_parse.tree().syntax().text().to_string(), &self.edited_text); let full_reparse = SourceFile::parse(&self.edited_text, Edition::CURRENT); diff --git a/src/tools/rust-analyzer/crates/syntax/src/lib.rs b/src/tools/rust-analyzer/crates/syntax/src/lib.rs index c1554c4b294..c9e9f468dca 100644 --- a/src/tools/rust-analyzer/crates/syntax/src/lib.rs +++ b/src/tools/rust-analyzer/crates/syntax/src/lib.rs @@ -44,10 +44,9 @@ pub mod syntax_editor; pub mod ted; pub mod utils; -use std::marker::PhantomData; +use std::{marker::PhantomData, ops::Range}; use stdx::format_to; -use text_edit::Indel; use triomphe::Arc; pub use crate::{ @@ -150,16 +149,22 @@ impl Parse<SourceFile> { buf } - pub fn reparse(&self, indel: &Indel, edition: Edition) -> Parse<SourceFile> { - self.incremental_reparse(indel, edition) - .unwrap_or_else(|| self.full_reparse(indel, edition)) + pub fn reparse(&self, delete: TextRange, insert: &str, edition: Edition) -> Parse<SourceFile> { + self.incremental_reparse(delete, insert, edition) + .unwrap_or_else(|| self.full_reparse(delete, insert, edition)) } - fn incremental_reparse(&self, indel: &Indel, edition: Edition) -> Option<Parse<SourceFile>> { + fn incremental_reparse( + &self, + delete: TextRange, + insert: &str, + edition: Edition, + ) -> Option<Parse<SourceFile>> { // FIXME: validation errors are not handled here parsing::incremental_reparse( self.tree().syntax(), - indel, + delete, + insert, self.errors.as_deref().unwrap_or_default().iter().cloned(), edition, ) @@ -170,9 +175,9 @@ impl Parse<SourceFile> { }) } - fn full_reparse(&self, indel: &Indel, edition: Edition) -> Parse<SourceFile> { + fn full_reparse(&self, delete: TextRange, insert: &str, edition: Edition) -> Parse<SourceFile> { let mut text = self.tree().syntax().text().to_string(); - indel.apply(&mut text); + text.replace_range(Range::<usize>::from(delete), insert); SourceFile::parse(&text, edition) } } diff --git a/src/tools/rust-analyzer/crates/syntax/src/parsing/reparsing.rs b/src/tools/rust-analyzer/crates/syntax/src/parsing/reparsing.rs index a5cc4e90dfb..f2eab18c279 100644 --- a/src/tools/rust-analyzer/crates/syntax/src/parsing/reparsing.rs +++ b/src/tools/rust-analyzer/crates/syntax/src/parsing/reparsing.rs @@ -6,8 +6,9 @@ //! - otherwise, we search for the nearest `{}` block which contains the edit //! and try to parse only this block. +use std::ops::Range; + use parser::{Edition, Reparser}; -use text_edit::Indel; use crate::{ parsing::build_tree, @@ -19,38 +20,48 @@ use crate::{ pub(crate) fn incremental_reparse( node: &SyntaxNode, - edit: &Indel, + delete: TextRange, + insert: &str, errors: impl IntoIterator<Item = SyntaxError>, edition: Edition, ) -> Option<(GreenNode, Vec<SyntaxError>, TextRange)> { - if let Some((green, new_errors, old_range)) = reparse_token(node, edit, edition) { - return Some((green, merge_errors(errors, new_errors, old_range, edit), old_range)); + if let Some((green, new_errors, old_range)) = reparse_token(node, delete, insert, edition) { + return Some(( + green, + merge_errors(errors, new_errors, old_range, delete, insert), + old_range, + )); } - if let Some((green, new_errors, old_range)) = reparse_block(node, edit, edition) { - return Some((green, merge_errors(errors, new_errors, old_range, edit), old_range)); + if let Some((green, new_errors, old_range)) = reparse_block(node, delete, insert, edition) { + return Some(( + green, + merge_errors(errors, new_errors, old_range, delete, insert), + old_range, + )); } None } fn reparse_token( root: &SyntaxNode, - edit: &Indel, + delete: TextRange, + insert: &str, edition: Edition, ) -> Option<(GreenNode, Vec<SyntaxError>, TextRange)> { - let prev_token = root.covering_element(edit.delete).as_token()?.clone(); + let prev_token = root.covering_element(delete).as_token()?.clone(); let prev_token_kind = prev_token.kind(); match prev_token_kind { WHITESPACE | COMMENT | IDENT | STRING | BYTE_STRING | C_STRING => { if prev_token_kind == WHITESPACE || prev_token_kind == COMMENT { // removing a new line may extends previous token - let deleted_range = edit.delete - prev_token.text_range().start(); + let deleted_range = delete - prev_token.text_range().start(); if prev_token.text()[deleted_range].contains('\n') { return None; } } - let mut new_text = get_text_after_edit(prev_token.clone().into(), edit); + let mut new_text = get_text_after_edit(prev_token.clone().into(), delete, insert); let (new_token_kind, new_err) = parser::LexedStr::single_token(edition, &new_text)?; if new_token_kind != prev_token_kind @@ -85,11 +96,12 @@ fn reparse_token( fn reparse_block( root: &SyntaxNode, - edit: &Indel, + delete: TextRange, + insert: &str, edition: parser::Edition, ) -> Option<(GreenNode, Vec<SyntaxError>, TextRange)> { - let (node, reparser) = find_reparsable_node(root, edit.delete)?; - let text = get_text_after_edit(node.clone().into(), edit); + let (node, reparser) = find_reparsable_node(root, delete)?; + let text = get_text_after_edit(node.clone().into(), delete, insert); let lexed = parser::LexedStr::new(edition, text.as_str()); let parser_input = lexed.to_input(edition); @@ -104,14 +116,14 @@ fn reparse_block( Some((node.replace_with(green), new_parser_errors, node.text_range())) } -fn get_text_after_edit(element: SyntaxElement, edit: &Indel) -> String { - let edit = Indel::replace(edit.delete - element.text_range().start(), edit.insert.clone()); +fn get_text_after_edit(element: SyntaxElement, mut delete: TextRange, insert: &str) -> String { + delete -= element.text_range().start(); let mut text = match element { NodeOrToken::Token(token) => token.text().to_owned(), NodeOrToken::Node(node) => node.text().to_string(), }; - edit.apply(&mut text); + text.replace_range(Range::<usize>::from(delete), insert); text } @@ -153,7 +165,8 @@ fn merge_errors( old_errors: impl IntoIterator<Item = SyntaxError>, new_errors: Vec<SyntaxError>, range_before_reparse: TextRange, - edit: &Indel, + delete: TextRange, + insert: &str, ) -> Vec<SyntaxError> { let mut res = Vec::new(); @@ -162,8 +175,8 @@ fn merge_errors( if old_err_range.end() <= range_before_reparse.start() { res.push(old_err); } else if old_err_range.start() >= range_before_reparse.end() { - let inserted_len = TextSize::of(&edit.insert); - res.push(old_err.with_range((old_err_range + inserted_len) - edit.delete.len())); + let inserted_len = TextSize::of(insert); + res.push(old_err.with_range((old_err_range + inserted_len) - delete.len())); // Note: extra parens are intentional to prevent uint underflow, HWAB (here was a bug) } } @@ -177,6 +190,8 @@ fn merge_errors( #[cfg(test)] mod tests { + use std::ops::Range; + use parser::Edition; use test_utils::{assert_eq_text, extract_range}; @@ -185,10 +200,9 @@ mod tests { fn do_check(before: &str, replace_with: &str, reparsed_len: u32) { let (range, before) = extract_range(before); - let edit = Indel::replace(range, replace_with.to_owned()); let after = { let mut after = before.clone(); - edit.apply(&mut after); + after.replace_range(Range::<usize>::from(range), replace_with); after }; @@ -197,7 +211,8 @@ mod tests { let before = SourceFile::parse(&before, Edition::CURRENT); let (green, new_errors, range) = incremental_reparse( before.tree().syntax(), - &edit, + range, + replace_with, before.errors.as_deref().unwrap_or_default().iter().cloned(), Edition::CURRENT, ) diff --git a/src/tools/rust-analyzer/crates/text-edit/Cargo.toml b/src/tools/rust-analyzer/crates/text-edit/Cargo.toml deleted file mode 100644 index dc6b3d31a09..00000000000 --- a/src/tools/rust-analyzer/crates/text-edit/Cargo.toml +++ /dev/null @@ -1,20 +0,0 @@ -[package] -name = "text-edit" -version = "0.0.0" -repository.workspace = true -description = "Representation of a `TextEdit` for rust-analyzer." - -authors.workspace = true -edition.workspace = true -license.workspace = true -rust-version.workspace = true - -[lib] -doctest = false - -[dependencies] -itertools.workspace = true -text-size.workspace = true - -[lints] -workspace = true \ No newline at end of file diff --git a/src/tools/rust-analyzer/crates/tt/src/buffer.rs b/src/tools/rust-analyzer/crates/tt/src/buffer.rs index 1319739371f..acb7e2d6c51 100644 --- a/src/tools/rust-analyzer/crates/tt/src/buffer.rs +++ b/src/tools/rust-analyzer/crates/tt/src/buffer.rs @@ -134,7 +134,7 @@ pub enum TokenTreeRef<'a, Span> { Leaf(&'a Leaf<Span>, &'a TokenTree<Span>), } -impl<'a, Span: Copy> TokenTreeRef<'a, Span> { +impl<Span: Copy> TokenTreeRef<'_, Span> { pub fn span(&self) -> Span { match self { TokenTreeRef::Subtree(subtree, _) => subtree.delimiter.open, diff --git a/src/tools/rust-analyzer/editors/code/.vscodeignore b/src/tools/rust-analyzer/editors/code/.vscodeignore index 09dc27056b3..1712a1477e6 100644 --- a/src/tools/rust-analyzer/editors/code/.vscodeignore +++ b/src/tools/rust-analyzer/editors/code/.vscodeignore @@ -12,3 +12,4 @@ !ra_syntax_tree.tmGrammar.json !server !README.md +!walkthrough-setup-tips.md diff --git a/src/tools/rust-analyzer/editors/code/package.json b/src/tools/rust-analyzer/editors/code/package.json index e55eceff781..6eebdf9f016 100644 --- a/src/tools/rust-analyzer/editors/code/package.json +++ b/src/tools/rust-analyzer/editors/code/package.json @@ -3224,10 +3224,9 @@ { "id": "setup", "title": "Useful Setup Tips", - "description": "There are a couple of things you might want to configure upfront to your tastes. We'll name a few here but be sure to check out the docs linked below!\n\n**Marking library sources as readonly**\n\nAdding the following to your settings.json will mark all Rust library sources as readonly:\n```json\n\"files.readonlyInclude\": {\n \"**/.cargo/registry/src/**/*.rs\": true,\n \"**/lib/rustlib/src/rust/library/**/*.rs\": true,\n},\n```\n\n**Check on Save**\n\nBy default, rust-analyzer will run `cargo check` on your codebase when you save a file, rendering diagnostics emitted by `cargo check` within your code. This can potentially collide with other `cargo` commands running concurrently, blocking them from running for a certain amount of time. In these cases it is recommended to disable the `rust-analyzer.checkOnSave` configuration and running the `rust-analyzer: Run flycheck` command on-demand instead.", + "description": "There are a couple of things you might want to configure upfront to your tastes. We'll name a few here but be sure to check out the docs linked below!\n\n**Marking library sources as readonly**\n\nAdding the snippet on the right to your settings.json will mark all Rust library sources as readonly.\n\n**Check on Save**\n\nBy default, rust-analyzer will run ``cargo check`` on your codebase when you save a file, rendering diagnostics emitted by ``cargo check`` within your code. This can potentially collide with other ``cargo`` commands running concurrently, blocking them from running for a certain amount of time. In these cases it is recommended to disable the ``rust-analyzer.checkOnSave`` configuration and running the ``rust-analyzer: Run flycheck`` command on-demand instead.", "media": { - "image": "./icon.png", - "altText": "rust-analyzer logo" + "markdown": "./walkthrough-setup-tips.md" } }, { @@ -3245,7 +3244,7 @@ { "id": "faq", "title": "FAQ", - "description": "What are these code hints that are being inserted into my code?\n\nThese hints are called inlay hints which rust-analyzer support and are enabled by default in VSCode. If you wish to disable them you can do so via the `editor.inlayHints.enabled` setting.", + "description": "What are these code hints that are being inserted into my code?\n\nThese hints are called inlay hints which rust-analyzer support and are enabled by default in VSCode. If you wish to disable them you can do so via the ``editor.inlayHints.enabled`` setting.", "media": { "image": "icon.png", "altText": "rust-analyzer logo" diff --git a/src/tools/rust-analyzer/editors/code/src/ctx.ts b/src/tools/rust-analyzer/editors/code/src/ctx.ts index 0f2a758db42..234fe6ab024 100644 --- a/src/tools/rust-analyzer/editors/code/src/ctx.ts +++ b/src/tools/rust-analyzer/editors/code/src/ctx.ts @@ -446,7 +446,7 @@ export class Ctx implements RustAnalyzerExtensionApi { return; } if (status.message) { - statusBar.tooltip.appendText(status.message); + statusBar.tooltip.appendMarkdown(status.message); } if (statusBar.tooltip.value) { statusBar.tooltip.appendMarkdown("\n\n---\n\n"); diff --git a/src/tools/rust-analyzer/editors/code/walkthrough-setup-tips.md b/src/tools/rust-analyzer/editors/code/walkthrough-setup-tips.md new file mode 100644 index 00000000000..fda4ac80023 --- /dev/null +++ b/src/tools/rust-analyzer/editors/code/walkthrough-setup-tips.md @@ -0,0 +1,10 @@ +# Settings Example + +Add the following to settings.json to mark Rust library sources as read-only: + +```json +"files.readonlyInclude": { + "**/.cargo/registry/src/**/*.rs": true, + "**/lib/rustlib/src/rust/library/**/*.rs": true, +}, +``` diff --git a/src/tools/rust-analyzer/rust-bors.toml b/src/tools/rust-analyzer/rust-bors.toml deleted file mode 100644 index c31ba66c50f..00000000000 --- a/src/tools/rust-analyzer/rust-bors.toml +++ /dev/null @@ -1 +0,0 @@ -timeout = 3600 diff --git a/src/tools/rust-analyzer/rust-version b/src/tools/rust-analyzer/rust-version index bc324402a96..ffb312d06e6 100644 --- a/src/tools/rust-analyzer/rust-version +++ b/src/tools/rust-analyzer/rust-version @@ -1 +1 @@ -1de57a5ce952c722f7053aeacfc6c90bc139b678 +a9d17627d241645a54c1134a20f1596127fedb60 diff --git a/src/tools/rust-analyzer/xtask/src/codegen.rs b/src/tools/rust-analyzer/xtask/src/codegen.rs index 4c7b07c5e02..bc04b9474f2 100644 --- a/src/tools/rust-analyzer/xtask/src/codegen.rs +++ b/src/tools/rust-analyzer/xtask/src/codegen.rs @@ -79,7 +79,7 @@ impl CommentBlock { let mut block = dummy_block.clone(); for (line_num, line) in lines.enumerate() { match line.strip_prefix("//") { - Some(mut contents) => { + Some(mut contents) if !contents.starts_with('/') => { if let Some('/' | '!') = contents.chars().next() { contents = &contents[1..]; block.is_doc = true; @@ -89,7 +89,7 @@ impl CommentBlock { } block.contents.push(contents.to_owned()); } - None => { + _ => { if !block.contents.is_empty() { let block = mem::replace(&mut block, dummy_block.clone()); res.push(block); diff --git a/src/tools/rust-analyzer/xtask/src/dist.rs b/src/tools/rust-analyzer/xtask/src/dist.rs index 742cf7f609a..c6a0be8aeb9 100644 --- a/src/tools/rust-analyzer/xtask/src/dist.rs +++ b/src/tools/rust-analyzer/xtask/src/dist.rs @@ -101,9 +101,10 @@ fn dist_server( cmd!(sh, "cargo build --manifest-path ./crates/rust-analyzer/Cargo.toml --bin rust-analyzer --target {target_name} {features...} --release").run()?; let dst = Path::new("dist").join(&target.artifact_name); - gzip(&target.server_path, &dst.with_extension("gz"))?; if target_name.contains("-windows-") { zip(&target.server_path, target.symbols_path.as_ref(), &dst.with_extension("zip"))?; + } else { + gzip(&target.server_path, &dst.with_extension("gz"))?; } Ok(()) diff --git a/src/tools/rust-analyzer/xtask/src/release/changelog.rs b/src/tools/rust-analyzer/xtask/src/release/changelog.rs index 086a4d463ea..343a9efbbc8 100644 --- a/src/tools/rust-analyzer/xtask/src/release/changelog.rs +++ b/src/tools/rust-analyzer/xtask/src/release/changelog.rs @@ -128,9 +128,10 @@ fn unescape(s: &str) -> String { } fn parse_pr_number(s: &str) -> Option<u32> { - const BORS_PREFIX: &str = "Merge #"; + const GITHUB_PREFIX: &str = "Merge pull request #"; const HOMU_PREFIX: &str = "Auto merge of #"; - if let Some(s) = s.strip_prefix(BORS_PREFIX) { + if let Some(s) = s.strip_prefix(GITHUB_PREFIX) { + let s = if let Some(space) = s.find(' ') { &s[..space] } else { s }; s.parse().ok() } else if let Some(s) = s.strip_prefix(HOMU_PREFIX) { if let Some(space) = s.find(' ') { diff --git a/src/tools/rust-analyzer/xtask/src/tidy.rs b/src/tools/rust-analyzer/xtask/src/tidy.rs index 0268e2473c0..c3d531344a1 100644 --- a/src/tools/rust-analyzer/xtask/src/tidy.rs +++ b/src/tools/rust-analyzer/xtask/src/tidy.rs @@ -223,7 +223,7 @@ struct TidyDocs { impl TidyDocs { fn visit(&mut self, path: &Path, text: &str) { // Tests and diagnostic fixes don't need module level comments. - if is_exclude_dir(path, &["tests", "test_data", "fixes", "grammar", "ra-salsa"]) { + if is_exclude_dir(path, &["tests", "test_data", "fixes", "grammar", "ra-salsa", "stdx"]) { return; } diff --git a/src/tools/tidy/src/issues.txt b/src/tools/tidy/src/issues.txt index 94f8d23c158..932a58788e0 100644 --- a/src/tools/tidy/src/issues.txt +++ b/src/tools/tidy/src/issues.txt @@ -4102,7 +4102,6 @@ ui/type-alias-impl-trait/issue-53678-coroutine-and-const-fn.rs ui/type-alias-impl-trait/issue-55099-lifetime-inference.rs ui/type-alias-impl-trait/issue-57188-associate-impl-capture.rs ui/type-alias-impl-trait/issue-57611-trait-alias.rs -ui/type-alias-impl-trait/issue-57700.rs ui/type-alias-impl-trait/issue-57807-associated-type.rs ui/type-alias-impl-trait/issue-57961.rs ui/type-alias-impl-trait/issue-58662-coroutine-with-lifetime.rs diff --git a/tests/assembly/riscv-soft-abi-with-float-features.rs b/tests/assembly/riscv-soft-abi-with-float-features.rs index 733137f5700..6d6001af084 100644 --- a/tests/assembly/riscv-soft-abi-with-float-features.rs +++ b/tests/assembly/riscv-soft-abi-with-float-features.rs @@ -1,6 +1,9 @@ //@ assembly-output: emit-asm //@ compile-flags: --target riscv64imac-unknown-none-elf -Ctarget-feature=+f,+d //@ needs-llvm-components: riscv +//@ revisions: LLVM-PRE-20 LLVM-POST-20 +//@ [LLVM-PRE-20] ignore-llvm-version: 20 - 99 +//@ [LLVM-POST-20] min-llvm-version: 20 #![feature(no_core, lang_items, f16)] #![crate_type = "lib"] @@ -31,9 +34,11 @@ pub extern "C" fn read_f16(x: &f16) -> f16 { // CHECK-LABEL: read_f32 #[no_mangle] pub extern "C" fn read_f32(x: &f32) -> f32 { - // CHECK: flw fa5, 0(a0) - // CHECK-NEXT: fmv.x.w a0, fa5 - // CHECK-NEXT: ret + // LLVM-PRE-20: flw fa5, 0(a0) + // LLVM-PRE-20-NEXT: fmv.x.w a0, fa5 + // LLVM-PRE-20-NEXT: ret + // LLVM-POST-20: lw a0, 0(a0) + // LLVM-POST-20-NEXT: ret *x } diff --git a/tests/crashes/125249.rs b/tests/crashes/125249.rs deleted file mode 100644 index 1cf6338a0d6..00000000000 --- a/tests/crashes/125249.rs +++ /dev/null @@ -1,8 +0,0 @@ -//@ known-bug: rust-lang/rust#125185 -#![feature(return_position_impl_trait_in_trait, return_type_notation)] - -trait IntFactory { - fn stream(&self) -> impl IntFactory<stream(..): IntFactory<stream(..): Send> + Send>; -} - -pub fn main() {} diff --git a/tests/crashes/126725.rs b/tests/crashes/126725.rs deleted file mode 100644 index d7a7d21ae42..00000000000 --- a/tests/crashes/126725.rs +++ /dev/null @@ -1,20 +0,0 @@ -//@ known-bug: rust-lang/rust#126725 -trait Foo { - fn foo<'a>(&'a self) -> <&'a impl Sized as Bar>::Output; -} - -trait Bar { - type Output; -} - -struct X(i32); - -impl<'a> Bar for &'a X { - type Output = &'a i32; -} - -impl Foo for X { - fn foo<'a>(&'a self) -> <&'a Self as Bar>::Output { - &self.0 - } -} diff --git a/tests/crashes/23707.rs b/tests/crashes/23707.rs deleted file mode 100644 index 4105933c60f..00000000000 --- a/tests/crashes/23707.rs +++ /dev/null @@ -1,109 +0,0 @@ -//@ known-bug: #23707 -//@ compile-flags: -Copt-level=0 --edition=2021 -//@ only-x86_64 -#![recursion_limit="2048"] - -use std::marker::PhantomData; -use std::fmt; -use std::fmt::Debug; - -pub struct Z( () ); -pub struct S<T> (PhantomData<T>); - - -pub trait Nat { - fn sing() -> Self; - fn get(&self) -> usize; -} - -impl Nat for Z { - fn sing() -> Z { Z( () ) } - #[inline(always)] - fn get(&self) -> usize { - 0 - } -} - -impl<T : Nat> Nat for S<T> { - fn sing() -> S<T> { S::<T>( PhantomData::<T> ) } - #[inline(always)] - fn get(&self) -> usize { - let prd : T = Nat::sing(); - 1 + prd.get() - } -} - -pub type N0 = Z; -pub type N1 = S<N0>; -pub type N2 = S<N1>; -pub type N3 = S<N2>; -pub type N4 = S<N3>; -pub type N5 = S<N4>; - - -pub struct Node<D : Nat>(usize,PhantomData<D>); - -impl<D:Nat> Node<D> { - pub fn push(&self, c : usize) -> Node<S<D>> { - let Node(i,_) = *self; - Node(10*i+c, PhantomData::<S<D>>) - } -} - -impl<D:Nat> Node<S<D>> { - pub fn pop(&self) -> (Node<D>,usize) { - let Node(i,_) = *self; - (Node(i/10, PhantomData::<D>), i-10*(i/10)) - } -} - -impl<D:Nat> Debug for Node<D> { - fn fmt(&self, f : &mut fmt::Formatter) -> fmt::Result { - let s : D = Nat::sing(); - write!(f, "Node<{}>: i= {}", - s.get(), self.0) - } -} -pub trait Step { - fn step(&self, usize) -> Self; -} - -impl Step for Node<N0> { - #[inline(always)] - fn step(&self, n : usize) -> Node<N0> { - println!("base case"); - Node(n,PhantomData::<N0>) - } -} - -impl<D:Nat> Step for Node<S<D>> - where Node<D> : Step { - #[inline(always)] - fn step(&self, n : usize) -> Node<S<D>> { - println!("rec"); - let (par,c) = self.pop(); - let cnew = c+n; - par.step(c).push(cnew) - } - -} - -fn tst<D:Nat>(ref p : &Node<D>, c : usize) -> usize - where Node<D> : Step { - let Node(i,_) = p.step(c); - i -} - - - -fn main() { - let nd : Node<N3> = Node(555,PhantomData::<N3>); - - // overflow...core::marker::Size - let Node(g,_) = tst(nd,1); - - // ok - //let Node(g,_) = nd.step(1); - - println!("{:?}", g); -} diff --git a/tests/run-make/linkage-attr-framework/main.rs b/tests/run-make/linkage-attr-framework/main.rs new file mode 100644 index 00000000000..8efabc83e62 --- /dev/null +++ b/tests/run-make/linkage-attr-framework/main.rs @@ -0,0 +1,17 @@ +#![cfg_attr(any(weak, both), feature(link_arg_attribute))] + +#[cfg_attr(any(link, both), link(name = "CoreFoundation", kind = "framework"))] +#[cfg_attr( + any(weak, both), + link(name = "-weak_framework", kind = "link-arg", modifiers = "+verbatim"), + link(name = "CoreFoundation", kind = "link-arg", modifiers = "+verbatim") +)] +extern "C" { + fn CFRunLoopGetTypeID() -> core::ffi::c_ulong; +} + +fn main() { + unsafe { + CFRunLoopGetTypeID(); + } +} diff --git a/tests/run-make/linkage-attr-framework/rmake.rs b/tests/run-make/linkage-attr-framework/rmake.rs new file mode 100644 index 00000000000..4450350f96e --- /dev/null +++ b/tests/run-make/linkage-attr-framework/rmake.rs @@ -0,0 +1,26 @@ +//! Check that linking frameworks on Apple platforms works. + +//@ only-apple + +use run_make_support::{Rustc, run, rustc}; + +fn compile(cfg: &str) -> Rustc { + let mut rustc = rustc(); + rustc.cfg(cfg).input("main.rs"); + rustc +} + +fn main() { + for cfg in ["link", "weak", "both"] { + compile(cfg).run(); + run("main"); + } + + let errs = compile("omit").run_fail(); + // The linker's exact error output changes between Xcode versions, depends on + // linker invocation details, and the linker sometimes outputs more warnings. + errs.assert_stderr_contains_regex(r"error: linking with `.*` failed"); + errs.assert_stderr_contains_regex(r"(Undefined symbols|ld: symbol[^\s]* not found)"); + errs.assert_stderr_contains_regex(r".?_CFRunLoopGetTypeID.?, referenced from:"); + errs.assert_stderr_contains("clang: error: linker command failed with exit code 1"); +} diff --git a/tests/rustdoc-gui/check-stab-in-docblock.goml b/tests/rustdoc-gui/check-stab-in-docblock.goml index f25c88690e5..916bea6b069 100644 --- a/tests/rustdoc-gui/check-stab-in-docblock.goml +++ b/tests/rustdoc-gui/check-stab-in-docblock.goml @@ -1,5 +1,5 @@ // This test checks that using `.stab` attributes in `.docblock` elements doesn't -// create scrollable paragraphs. +// create scrollable paragraphs and is correctly displayed (not making weird blocks). go-to: "file://" + |DOC_PATH| + "/test_docs/index.html" // Needs the text to be display to check for scrollable content. show-text: true @@ -31,3 +31,15 @@ assert-property: ( ".top-doc .docblock p:nth-of-type(3)", {"scrollHeight": |clientHeight|, "scrollWidth": |clientWidth|}, ) + +// Ensure that `<code>` elements in code don't make big blocks. +compare-elements-size-near: ( + "#reexport\.TheStdReexport > code", + ".docblock p span[data-span='1']", + {"height": 1}, +) +compare-elements-size-near: ( + "#reexport\.TheStdReexport > code", + ".docblock p span[data-span='2']", + {"height": 1}, +) diff --git a/tests/rustdoc-gui/docblock-big-code-mobile.goml b/tests/rustdoc-gui/docblock-big-code-mobile.goml index 6fc6834768e..71e08e2c7e2 100644 --- a/tests/rustdoc-gui/docblock-big-code-mobile.goml +++ b/tests/rustdoc-gui/docblock-big-code-mobile.goml @@ -1,13 +1,15 @@ // If we have a long `<code>`, we need to ensure that it'll be fully displayed on mobile, meaning // that it'll be on two lines. + emulate: "iPhone 8" // it has the following size: (375, 667) go-to: "file://" + |DOC_PATH| + "/test_docs/long_code_block/index.html" -// We now check that the block is on two lines: show-text: true // We need to enable text draw to be able to have the "real" size + +// We now check that the block is on two lines: // Little explanations for this test: if the text wasn't displayed on two lines, it would take -// around 20px (which is the font size). -assert-property: (".docblock p > code", {"offsetHeight": "44"}) +// around 24px (which is the font size). +assert-size: (".docblock p > code", {"height": 48}) // Same check, but where the long code block is also a link go-to: "file://" + |DOC_PATH| + "/test_docs/long_code_block_link/index.html" -assert-property: (".docblock p > a > code", {"offsetHeight": "44"}) +assert-size: (".docblock p > a > code", {"height": 48}) diff --git a/tests/rustdoc-gui/fields.goml b/tests/rustdoc-gui/fields.goml index b8139a2edac..dce9918c332 100644 --- a/tests/rustdoc-gui/fields.goml +++ b/tests/rustdoc-gui/fields.goml @@ -1,13 +1,37 @@ -// This test checks that fields are displayed as expected (one by line). -go-to: "file://" + |DOC_PATH| + "/test_docs/fields/struct.Struct.html" -store-position: ("#structfield\.a", {"y": a_y}) -store-position: ("#structfield\.b", {"y": b_y}) -assert: |a_y| < |b_y| +// This test checks that fields are displayed as expected (one by line) and they are surrounded +// by margins. -go-to: "file://" + |DOC_PATH| + "/test_docs/fields/union.Union.html" -store-position: ("#structfield\.a", {"y": a_y}) -store-position: ("#structfield\.b", {"y": b_y}) -assert: |a_y| < |b_y| +store-value: (margin, "9.6px") +define-function: ( + "check-fields", + [path, selector_1, selector_2], + block { + go-to: "file://" + |DOC_PATH| + "/test_docs/fields/" + |path| + store-position: (|selector_1|, {"y": a_y}) + store-position: (|selector_2|, {"y": b_y}) + assert: |a_y| < |b_y| + + // Check the margins. + assert-css: (".structfield.section-header", { + "margin-top": |margin|, + "margin-bottom": |margin|, + "margin-left": "0px", + "margin-right": "0px", + }, ALL) + } +) + +call-function: ("check-fields", { + "path": "struct.Struct.html", + "selector_1": "#structfield\.a", + "selector_2": "#structfield\.b", +}) + +call-function: ("check-fields", { + "path": "union.Union.html", + "selector_1": "#structfield\.a", + "selector_2": "#structfield\.b", +}) go-to: "file://" + |DOC_PATH| + "/test_docs/fields/enum.Enum.html" store-position: ("#variant\.A\.field\.a", {"y": a_y}) @@ -16,3 +40,11 @@ assert: |a_y| < |b_y| store-position: ("#variant\.B\.field\.a", {"y": a_y}) store-position: ("#variant\.B\.field\.b", {"y": b_y}) assert: |a_y| < |b_y| + +// Check the margins. +assert-css: (".sub-variant-field", { + "margin-top": |margin|, + "margin-bottom": |margin|, + "margin-left": "24px", + "margin-right": "0px", +}, ALL) diff --git a/tests/rustdoc-gui/struct-fields.goml b/tests/rustdoc-gui/struct-fields.goml index 3c87a4cd654..302a1a0d80b 100644 --- a/tests/rustdoc-gui/struct-fields.goml +++ b/tests/rustdoc-gui/struct-fields.goml @@ -1,4 +1,5 @@ -// This test ensures that each field is on its own line (In other words, they have display: block). +// This test ensures that each field is on its own line (In other words, they have +// `display: block`). go-to: "file://" + |DOC_PATH| + "/test_docs/struct.StructWithPublicUndocumentedFields.html" store-property: ("//*[@id='structfield.first']", {"offsetTop": first_top}) diff --git a/tests/rustdoc-js/extern-func.js b/tests/rustdoc-js/extern-func.js new file mode 100644 index 00000000000..a3fe2d8ea42 --- /dev/null +++ b/tests/rustdoc-js/extern-func.js @@ -0,0 +1,8 @@ +const EXPECTED = [ + { + 'query': 'c_float -> c_float', + 'others': [ + { 'path': 'extern_func', 'name': 'sqrt' } + ], + }, +]; diff --git a/tests/rustdoc-js/extern-func.rs b/tests/rustdoc-js/extern-func.rs new file mode 100644 index 00000000000..ab1e3e75da7 --- /dev/null +++ b/tests/rustdoc-js/extern-func.rs @@ -0,0 +1,5 @@ +use std::ffi::c_float; + +extern "C" { + pub fn sqrt(x: c_float) -> c_float; +} diff --git a/tests/rustdoc-ui/doctest/dead-code-2024.rs b/tests/rustdoc-ui/doctest/dead-code-2024.rs new file mode 100644 index 00000000000..4c77112e61a --- /dev/null +++ b/tests/rustdoc-ui/doctest/dead-code-2024.rs @@ -0,0 +1,15 @@ +// This test ensures that the 2024 edition merged doctest will not use `#[allow(unused)]`. + +//@ compile-flags:--test -Zunstable-options --edition 2024 +//@ normalize-stdout-test: "tests/rustdoc-ui/doctest" -> "$$DIR" +//@ normalize-stdout-test: "finished in \d+\.\d+s" -> "finished in $$TIME" +//@ failure-status: 101 + +#![doc(test(attr(allow(unused_variables), deny(warnings))))] + +/// Example +/// +/// ```rust,no_run +/// trait T { fn f(); } +/// ``` +pub fn f() {} diff --git a/tests/rustdoc-ui/doctest/dead-code-2024.stdout b/tests/rustdoc-ui/doctest/dead-code-2024.stdout new file mode 100644 index 00000000000..69dd4e2ede1 --- /dev/null +++ b/tests/rustdoc-ui/doctest/dead-code-2024.stdout @@ -0,0 +1,29 @@ + +running 1 test +test $DIR/dead-code-2024.rs - f (line 12) - compile ... FAILED + +failures: + +---- $DIR/dead-code-2024.rs - f (line 12) stdout ---- +error: trait `T` is never used + --> $DIR/dead-code-2024.rs:13:7 + | +LL | trait T { fn f(); } + | ^ + | +note: the lint level is defined here + --> $DIR/dead-code-2024.rs:11:9 + | +LL | #![deny(warnings)] + | ^^^^^^^^ + = note: `#[deny(dead_code)]` implied by `#[deny(warnings)]` + +error: aborting due to 1 previous error + +Couldn't compile the test. + +failures: + $DIR/dead-code-2024.rs - f (line 12) + +test result: FAILED. 0 passed; 1 failed; 0 ignored; 0 measured; 0 filtered out; finished in $TIME + diff --git a/tests/rustdoc-ui/doctest/dead-code.rs b/tests/rustdoc-ui/doctest/dead-code.rs new file mode 100644 index 00000000000..cb9b4c28f6c --- /dev/null +++ b/tests/rustdoc-ui/doctest/dead-code.rs @@ -0,0 +1,15 @@ +// This test ensures that the doctest will not use `#[allow(unused)]`. + +//@ compile-flags:--test +//@ normalize-stdout-test: "tests/rustdoc-ui/doctest" -> "$$DIR" +//@ normalize-stdout-test: "finished in \d+\.\d+s" -> "finished in $$TIME" +//@ failure-status: 101 + +#![doc(test(attr(allow(unused_variables), deny(warnings))))] + +/// Example +/// +/// ```rust,no_run +/// trait T { fn f(); } +/// ``` +pub fn f() {} diff --git a/tests/rustdoc-ui/doctest/dead-code.stdout b/tests/rustdoc-ui/doctest/dead-code.stdout new file mode 100644 index 00000000000..38d15d5c1bc --- /dev/null +++ b/tests/rustdoc-ui/doctest/dead-code.stdout @@ -0,0 +1,29 @@ + +running 1 test +test $DIR/dead-code.rs - f (line 12) - compile ... FAILED + +failures: + +---- $DIR/dead-code.rs - f (line 12) stdout ---- +error: trait `T` is never used + --> $DIR/dead-code.rs:13:7 + | +LL | trait T { fn f(); } + | ^ + | +note: the lint level is defined here + --> $DIR/dead-code.rs:11:9 + | +LL | #![deny(warnings)] + | ^^^^^^^^ + = note: `#[deny(dead_code)]` implied by `#[deny(warnings)]` + +error: aborting due to 1 previous error + +Couldn't compile the test. + +failures: + $DIR/dead-code.rs - f (line 12) + +test result: FAILED. 0 passed; 1 failed; 0 ignored; 0 measured; 0 filtered out; finished in $TIME + diff --git a/tests/ui-fulldeps/session-diagnostic/diagnostic-derive.stderr b/tests/ui-fulldeps/session-diagnostic/diagnostic-derive.stderr index ff7af388514..03fca17aa55 100644 --- a/tests/ui-fulldeps/session-diagnostic/diagnostic-derive.stderr +++ b/tests/ui-fulldeps/session-diagnostic/diagnostic-derive.stderr @@ -1,10 +1,10 @@ -error: unsupported type attribute for diagnostic derive enum +error: derive(Diagnostic): unsupported type attribute for diagnostic derive enum --> $DIR/diagnostic-derive.rs:47:1 | LL | #[diag(no_crate_example, code = E0123)] | ^ -error: diagnostic slug not specified +error: derive(Diagnostic): diagnostic slug not specified --> $DIR/diagnostic-derive.rs:50:5 | LL | Foo, @@ -12,7 +12,7 @@ LL | Foo, | = help: specify the slug as the first argument to the `#[diag(...)]` attribute, such as `#[diag(hir_analysis_example_error)]` -error: diagnostic slug not specified +error: derive(Diagnostic): diagnostic slug not specified --> $DIR/diagnostic-derive.rs:52:5 | LL | Bar, @@ -20,13 +20,13 @@ LL | Bar, | = help: specify the slug as the first argument to the `#[diag(...)]` attribute, such as `#[diag(hir_analysis_example_error)]` -error: `#[nonsense(...)]` is not a valid attribute +error: derive(Diagnostic): `#[nonsense(...)]` is not a valid attribute --> $DIR/diagnostic-derive.rs:63:1 | LL | #[nonsense(no_crate_example, code = E0123)] | ^ -error: diagnostic slug not specified +error: derive(Diagnostic): diagnostic slug not specified --> $DIR/diagnostic-derive.rs:63:1 | LL | #[nonsense(no_crate_example, code = E0123)] @@ -34,7 +34,7 @@ LL | #[nonsense(no_crate_example, code = E0123)] | = help: specify the slug as the first argument to the `#[diag(...)]` attribute, such as `#[diag(hir_analysis_example_error)]` -error: diagnostic slug not specified +error: derive(Diagnostic): diagnostic slug not specified --> $DIR/diagnostic-derive.rs:70:1 | LL | #[diag(code = E0123)] @@ -42,13 +42,13 @@ LL | #[diag(code = E0123)] | = help: specify the slug as the first argument to the `#[diag(...)]` attribute, such as `#[diag(hir_analysis_example_error)]` -error: diagnostic slug must be the first argument +error: derive(Diagnostic): diagnostic slug must be the first argument --> $DIR/diagnostic-derive.rs:80:16 | LL | #[diag(nonsense("foo"), code = E0123, slug = "foo")] | ^ -error: diagnostic slug not specified +error: derive(Diagnostic): diagnostic slug not specified --> $DIR/diagnostic-derive.rs:80:1 | LL | #[diag(nonsense("foo"), code = E0123, slug = "foo")] @@ -56,7 +56,7 @@ LL | #[diag(nonsense("foo"), code = E0123, slug = "foo")] | = help: specify the slug as the first argument to the `#[diag(...)]` attribute, such as `#[diag(hir_analysis_example_error)]` -error: unknown argument +error: derive(Diagnostic): unknown argument --> $DIR/diagnostic-derive.rs:86:8 | LL | #[diag(nonsense = "...", code = E0123, slug = "foo")] @@ -64,7 +64,7 @@ LL | #[diag(nonsense = "...", code = E0123, slug = "foo")] | = note: only the `code` parameter is valid after the slug -error: diagnostic slug not specified +error: derive(Diagnostic): diagnostic slug not specified --> $DIR/diagnostic-derive.rs:86:1 | LL | #[diag(nonsense = "...", code = E0123, slug = "foo")] @@ -72,7 +72,7 @@ LL | #[diag(nonsense = "...", code = E0123, slug = "foo")] | = help: specify the slug as the first argument to the `#[diag(...)]` attribute, such as `#[diag(hir_analysis_example_error)]` -error: unknown argument +error: derive(Diagnostic): unknown argument --> $DIR/diagnostic-derive.rs:92:8 | LL | #[diag(nonsense = 4, code = E0123, slug = "foo")] @@ -80,7 +80,7 @@ LL | #[diag(nonsense = 4, code = E0123, slug = "foo")] | = note: only the `code` parameter is valid after the slug -error: diagnostic slug not specified +error: derive(Diagnostic): diagnostic slug not specified --> $DIR/diagnostic-derive.rs:92:1 | LL | #[diag(nonsense = 4, code = E0123, slug = "foo")] @@ -88,7 +88,7 @@ LL | #[diag(nonsense = 4, code = E0123, slug = "foo")] | = help: specify the slug as the first argument to the `#[diag(...)]` attribute, such as `#[diag(hir_analysis_example_error)]` -error: unknown argument +error: derive(Diagnostic): unknown argument --> $DIR/diagnostic-derive.rs:98:40 | LL | #[diag(no_crate_example, code = E0123, slug = "foo")] @@ -96,13 +96,13 @@ LL | #[diag(no_crate_example, code = E0123, slug = "foo")] | = note: only the `code` parameter is valid after the slug -error: `#[suggestion = ...]` is not a valid attribute +error: derive(Diagnostic): `#[suggestion = ...]` is not a valid attribute --> $DIR/diagnostic-derive.rs:105:5 | LL | #[suggestion = "bar"] | ^ -error: specified multiple times +error: derive(Diagnostic): attribute specified multiple times --> $DIR/diagnostic-derive.rs:112:8 | LL | #[diag(no_crate_example, code = E0456)] @@ -114,7 +114,7 @@ note: previously specified here LL | #[diag(no_crate_example, code = E0123)] | ^^^^^^^^^^^^^^^^ -error: specified multiple times +error: derive(Diagnostic): attribute specified multiple times --> $DIR/diagnostic-derive.rs:112:26 | LL | #[diag(no_crate_example, code = E0456)] @@ -126,7 +126,7 @@ note: previously specified here LL | #[diag(no_crate_example, code = E0123)] | ^^^^ -error: specified multiple times +error: derive(Diagnostic): attribute specified multiple times --> $DIR/diagnostic-derive.rs:118:40 | LL | #[diag(no_crate_example, code = E0123, code = E0456)] @@ -138,13 +138,13 @@ note: previously specified here LL | #[diag(no_crate_example, code = E0123, code = E0456)] | ^^^^ -error: diagnostic slug must be the first argument +error: derive(Diagnostic): diagnostic slug must be the first argument --> $DIR/diagnostic-derive.rs:123:43 | LL | #[diag(no_crate_example, no_crate::example, code = E0123)] | ^ -error: diagnostic slug not specified +error: derive(Diagnostic): diagnostic slug not specified --> $DIR/diagnostic-derive.rs:128:1 | LL | struct KindNotProvided {} @@ -152,7 +152,7 @@ LL | struct KindNotProvided {} | = help: specify the slug as the first argument to the `#[diag(...)]` attribute, such as `#[diag(hir_analysis_example_error)]` -error: diagnostic slug not specified +error: derive(Diagnostic): diagnostic slug not specified --> $DIR/diagnostic-derive.rs:131:1 | LL | #[diag(code = E0123)] @@ -160,25 +160,25 @@ LL | #[diag(code = E0123)] | = help: specify the slug as the first argument to the `#[diag(...)]` attribute, such as `#[diag(hir_analysis_example_error)]` -error: the `#[primary_span]` attribute can only be applied to fields of type `Span` or `MultiSpan` +error: derive(Diagnostic): the `#[primary_span]` attribute can only be applied to fields of type `Span` or `MultiSpan` --> $DIR/diagnostic-derive.rs:142:5 | LL | #[primary_span] | ^ -error: `#[nonsense]` is not a valid attribute +error: derive(Diagnostic): `#[nonsense]` is not a valid attribute --> $DIR/diagnostic-derive.rs:150:5 | LL | #[nonsense] | ^ -error: the `#[label(...)]` attribute can only be applied to fields of type `Span` or `MultiSpan` +error: derive(Diagnostic): the `#[label(...)]` attribute can only be applied to fields of type `Span` or `MultiSpan` --> $DIR/diagnostic-derive.rs:167:5 | LL | #[label(no_crate_label)] | ^ -error: `name` doesn't refer to a field on this type +error: derive(Diagnostic): `name` doesn't refer to a field on this type --> $DIR/diagnostic-derive.rs:175:46 | LL | #[suggestion(no_crate_suggestion, code = "{name}")] @@ -202,19 +202,19 @@ LL | #[derive(Diagnostic)] = note: if you intended to print `}`, you can escape it using `}}` = note: this error originates in the derive macro `Diagnostic` (in Nightly builds, run with -Z macro-backtrace for more info) -error: the `#[label(...)]` attribute can only be applied to fields of type `Span` or `MultiSpan` +error: derive(Diagnostic): the `#[label(...)]` attribute can only be applied to fields of type `Span` or `MultiSpan` --> $DIR/diagnostic-derive.rs:210:5 | LL | #[label(no_crate_label)] | ^ -error: suggestion without `code = "..."` +error: derive(Diagnostic): suggestion without `code = "..."` --> $DIR/diagnostic-derive.rs:229:5 | LL | #[suggestion(no_crate_suggestion)] | ^ -error: invalid nested attribute +error: derive(Diagnostic): invalid nested attribute --> $DIR/diagnostic-derive.rs:237:18 | LL | #[suggestion(nonsense = "bar")] @@ -222,13 +222,13 @@ LL | #[suggestion(nonsense = "bar")] | = help: only `no_span`, `style`, `code` and `applicability` are valid nested attributes -error: suggestion without `code = "..."` +error: derive(Diagnostic): suggestion without `code = "..."` --> $DIR/diagnostic-derive.rs:237:5 | LL | #[suggestion(nonsense = "bar")] | ^ -error: invalid nested attribute +error: derive(Diagnostic): invalid nested attribute --> $DIR/diagnostic-derive.rs:246:18 | LL | #[suggestion(msg = "bar")] @@ -236,13 +236,13 @@ LL | #[suggestion(msg = "bar")] | = help: only `no_span`, `style`, `code` and `applicability` are valid nested attributes -error: suggestion without `code = "..."` +error: derive(Diagnostic): suggestion without `code = "..."` --> $DIR/diagnostic-derive.rs:246:5 | LL | #[suggestion(msg = "bar")] | ^ -error: wrong field type for suggestion +error: derive(Diagnostic): wrong field type for suggestion --> $DIR/diagnostic-derive.rs:269:5 | LL | #[suggestion(no_crate_suggestion, code = "This is suggested code")] @@ -250,7 +250,7 @@ LL | #[suggestion(no_crate_suggestion, code = "This is suggested code")] | = help: `#[suggestion(...)]` should be applied to fields of type `Span` or `(Span, Applicability)` -error: specified multiple times +error: derive(Diagnostic): attribute specified multiple times --> $DIR/diagnostic-derive.rs:285:24 | LL | suggestion: (Span, Span, Applicability), @@ -262,7 +262,7 @@ note: previously specified here LL | suggestion: (Span, Span, Applicability), | ^^^^ -error: specified multiple times +error: derive(Diagnostic): attribute specified multiple times --> $DIR/diagnostic-derive.rs:293:33 | LL | suggestion: (Applicability, Applicability, Span), @@ -274,13 +274,13 @@ note: previously specified here LL | suggestion: (Applicability, Applicability, Span), | ^^^^^^^^^^^^^ -error: `#[label = ...]` is not a valid attribute +error: derive(Diagnostic): `#[label = ...]` is not a valid attribute --> $DIR/diagnostic-derive.rs:300:5 | LL | #[label = "bar"] | ^ -error: specified multiple times +error: derive(Diagnostic): attribute specified multiple times --> $DIR/diagnostic-derive.rs:451:5 | LL | #[suggestion(no_crate_suggestion, code = "...", applicability = "maybe-incorrect")] @@ -292,37 +292,37 @@ note: previously specified here LL | suggestion: (Span, Applicability), | ^^^^^^^^^^^^^ -error: invalid applicability +error: derive(Diagnostic): invalid applicability --> $DIR/diagnostic-derive.rs:459:69 | LL | #[suggestion(no_crate_suggestion, code = "...", applicability = "batman")] | ^^^^^^^^ -error: the `#[help(...)]` attribute can only be applied to fields of type `Span`, `MultiSpan`, `bool` or `()` +error: derive(Diagnostic): the `#[help(...)]` attribute can only be applied to fields of type `Span`, `MultiSpan`, `bool` or `()` --> $DIR/diagnostic-derive.rs:526:5 | LL | #[help(no_crate_help)] | ^ -error: a diagnostic slug must be the first argument to the attribute +error: derive(Diagnostic): a diagnostic slug must be the first argument to the attribute --> $DIR/diagnostic-derive.rs:535:32 | LL | #[label(no_crate_label, foo)] | ^ -error: only `no_span` is a valid nested attribute +error: derive(Diagnostic): only `no_span` is a valid nested attribute --> $DIR/diagnostic-derive.rs:543:29 | LL | #[label(no_crate_label, foo = "...")] | ^^^ -error: only `no_span` is a valid nested attribute +error: derive(Diagnostic): only `no_span` is a valid nested attribute --> $DIR/diagnostic-derive.rs:551:29 | LL | #[label(no_crate_label, foo("..."))] | ^^^ -error: `#[primary_span]` is not a valid attribute +error: derive(Diagnostic): `#[primary_span]` is not a valid attribute --> $DIR/diagnostic-derive.rs:563:5 | LL | #[primary_span] @@ -330,13 +330,13 @@ LL | #[primary_span] | = help: the `primary_span` field attribute is not valid for lint diagnostics -error: `#[error(...)]` is not a valid attribute +error: derive(Diagnostic): `#[error(...)]` is not a valid attribute --> $DIR/diagnostic-derive.rs:583:1 | LL | #[error(no_crate_example, code = E0123)] | ^ -error: diagnostic slug not specified +error: derive(Diagnostic): diagnostic slug not specified --> $DIR/diagnostic-derive.rs:583:1 | LL | #[error(no_crate_example, code = E0123)] @@ -344,13 +344,13 @@ LL | #[error(no_crate_example, code = E0123)] | = help: specify the slug as the first argument to the `#[diag(...)]` attribute, such as `#[diag(hir_analysis_example_error)]` -error: `#[warn_(...)]` is not a valid attribute +error: derive(Diagnostic): `#[warn_(...)]` is not a valid attribute --> $DIR/diagnostic-derive.rs:590:1 | LL | #[warn_(no_crate_example, code = E0123)] | ^ -error: diagnostic slug not specified +error: derive(Diagnostic): diagnostic slug not specified --> $DIR/diagnostic-derive.rs:590:1 | LL | #[warn_(no_crate_example, code = E0123)] @@ -358,13 +358,13 @@ LL | #[warn_(no_crate_example, code = E0123)] | = help: specify the slug as the first argument to the `#[diag(...)]` attribute, such as `#[diag(hir_analysis_example_error)]` -error: `#[lint(...)]` is not a valid attribute +error: derive(Diagnostic): `#[lint(...)]` is not a valid attribute --> $DIR/diagnostic-derive.rs:597:1 | LL | #[lint(no_crate_example, code = E0123)] | ^ -error: diagnostic slug not specified +error: derive(Diagnostic): diagnostic slug not specified --> $DIR/diagnostic-derive.rs:597:1 | LL | #[lint(no_crate_example, code = E0123)] @@ -372,13 +372,13 @@ LL | #[lint(no_crate_example, code = E0123)] | = help: specify the slug as the first argument to the `#[diag(...)]` attribute, such as `#[diag(hir_analysis_example_error)]` -error: `#[lint(...)]` is not a valid attribute +error: derive(Diagnostic): `#[lint(...)]` is not a valid attribute --> $DIR/diagnostic-derive.rs:604:1 | LL | #[lint(no_crate_example, code = E0123)] | ^ -error: diagnostic slug not specified +error: derive(Diagnostic): diagnostic slug not specified --> $DIR/diagnostic-derive.rs:604:1 | LL | #[lint(no_crate_example, code = E0123)] @@ -386,7 +386,7 @@ LL | #[lint(no_crate_example, code = E0123)] | = help: specify the slug as the first argument to the attribute, such as `#[diag(compiletest_example)]` -error: specified multiple times +error: derive(Diagnostic): attribute specified multiple times --> $DIR/diagnostic-derive.rs:613:53 | LL | #[suggestion(no_crate_suggestion, code = "...", code = ",,,")] @@ -398,7 +398,7 @@ note: previously specified here LL | #[suggestion(no_crate_suggestion, code = "...", code = ",,,")] | ^^^^ -error: wrong types for suggestion +error: derive(Diagnostic): wrong types for suggestion --> $DIR/diagnostic-derive.rs:622:24 | LL | suggestion: (Span, usize), @@ -406,7 +406,7 @@ LL | suggestion: (Span, usize), | = help: `#[suggestion(...)]` on a tuple field must be applied to fields of type `(Span, Applicability)` -error: wrong types for suggestion +error: derive(Diagnostic): wrong types for suggestion --> $DIR/diagnostic-derive.rs:630:17 | LL | suggestion: (Span,), @@ -414,13 +414,13 @@ LL | suggestion: (Span,), | = help: `#[suggestion(...)]` on a tuple field must be applied to fields of type `(Span, Applicability)` -error: suggestion without `code = "..."` +error: derive(Diagnostic): suggestion without `code = "..."` --> $DIR/diagnostic-derive.rs:637:5 | LL | #[suggestion(no_crate_suggestion)] | ^ -error: `#[multipart_suggestion(...)]` is not a valid attribute +error: derive(Diagnostic): `#[multipart_suggestion(...)]` is not a valid attribute --> $DIR/diagnostic-derive.rs:644:1 | LL | #[multipart_suggestion(no_crate_suggestion)] @@ -428,7 +428,7 @@ LL | #[multipart_suggestion(no_crate_suggestion)] | = help: consider creating a `Subdiagnostic` instead -error: `#[multipart_suggestion(...)]` is not a valid attribute +error: derive(Diagnostic): `#[multipart_suggestion(...)]` is not a valid attribute --> $DIR/diagnostic-derive.rs:647:1 | LL | #[multipart_suggestion()] @@ -436,7 +436,7 @@ LL | #[multipart_suggestion()] | = help: consider creating a `Subdiagnostic` instead -error: `#[multipart_suggestion(...)]` is not a valid attribute +error: derive(Diagnostic): `#[multipart_suggestion(...)]` is not a valid attribute --> $DIR/diagnostic-derive.rs:651:5 | LL | #[multipart_suggestion(no_crate_suggestion)] @@ -444,7 +444,7 @@ LL | #[multipart_suggestion(no_crate_suggestion)] | = help: consider creating a `Subdiagnostic` instead -error: `#[suggestion(...)]` is not a valid attribute +error: derive(Diagnostic): `#[suggestion(...)]` is not a valid attribute --> $DIR/diagnostic-derive.rs:659:1 | LL | #[suggestion(no_crate_suggestion, code = "...")] @@ -452,7 +452,7 @@ LL | #[suggestion(no_crate_suggestion, code = "...")] | = help: `#[label]` and `#[suggestion]` can only be applied to fields -error: `#[label]` is not a valid attribute +error: derive(Diagnostic): `#[label]` is not a valid attribute --> $DIR/diagnostic-derive.rs:668:1 | LL | #[label] @@ -460,61 +460,61 @@ LL | #[label] | = help: `#[label]` and `#[suggestion]` can only be applied to fields -error: `#[subdiagnostic(...)]` is not a valid attribute +error: derive(Diagnostic): `#[subdiagnostic(...)]` is not a valid attribute --> $DIR/diagnostic-derive.rs:702:5 | LL | #[subdiagnostic(bad)] | ^ -error: `#[subdiagnostic = ...]` is not a valid attribute +error: derive(Diagnostic): `#[subdiagnostic = ...]` is not a valid attribute --> $DIR/diagnostic-derive.rs:710:5 | LL | #[subdiagnostic = "bad"] | ^ -error: `#[subdiagnostic(...)]` is not a valid attribute +error: derive(Diagnostic): `#[subdiagnostic(...)]` is not a valid attribute --> $DIR/diagnostic-derive.rs:718:5 | LL | #[subdiagnostic(bad, bad)] | ^ -error: `#[subdiagnostic(...)]` is not a valid attribute +error: derive(Diagnostic): `#[subdiagnostic(...)]` is not a valid attribute --> $DIR/diagnostic-derive.rs:726:5 | LL | #[subdiagnostic("bad")] | ^ -error: `#[subdiagnostic(...)]` is not a valid attribute +error: derive(Diagnostic): `#[subdiagnostic(...)]` is not a valid attribute --> $DIR/diagnostic-derive.rs:734:5 | LL | #[subdiagnostic(eager)] | ^ -error: `#[subdiagnostic(...)]` is not a valid attribute +error: derive(Diagnostic): `#[subdiagnostic(...)]` is not a valid attribute --> $DIR/diagnostic-derive.rs:742:5 | LL | #[subdiagnostic(eager)] | ^ -error: `#[subdiagnostic(...)]` is not a valid attribute +error: derive(Diagnostic): `#[subdiagnostic(...)]` is not a valid attribute --> $DIR/diagnostic-derive.rs:763:5 | LL | #[subdiagnostic(eager)] | ^ -error: expected at least one string literal for `code(...)` +error: derive(Diagnostic): expected at least one string literal for `code(...)` --> $DIR/diagnostic-derive.rs:794:23 | LL | #[suggestion(code())] | ^ -error: `code(...)` must contain only string literals +error: derive(Diagnostic): `code(...)` must contain only string literals --> $DIR/diagnostic-derive.rs:802:23 | LL | #[suggestion(code(foo))] | ^^^ -error: `#[suggestion(...)]` is not a valid attribute +error: derive(Diagnostic): `#[suggestion(...)]` is not a valid attribute --> $DIR/diagnostic-derive.rs:826:5 | LL | #[suggestion(no_crate_suggestion, code = "")] diff --git a/tests/ui-fulldeps/session-diagnostic/enforce_slug_naming.stderr b/tests/ui-fulldeps/session-diagnostic/enforce_slug_naming.stderr index df1bad3cad0..4f54239f0fa 100644 --- a/tests/ui-fulldeps/session-diagnostic/enforce_slug_naming.stderr +++ b/tests/ui-fulldeps/session-diagnostic/enforce_slug_naming.stderr @@ -1,4 +1,4 @@ -error: diagnostic slug and crate name do not match +error: derive(Diagnostic): diagnostic slug and crate name do not match --> $DIR/enforce_slug_naming.rs:22:8 | LL | #[diag(compiletest_example, code = E0123)] diff --git a/tests/ui-fulldeps/session-diagnostic/subdiagnostic-derive.stderr b/tests/ui-fulldeps/session-diagnostic/subdiagnostic-derive.stderr index 96f6ef06d1d..0ae7ba4c497 100644 --- a/tests/ui-fulldeps/session-diagnostic/subdiagnostic-derive.stderr +++ b/tests/ui-fulldeps/session-diagnostic/subdiagnostic-derive.stderr @@ -1,142 +1,142 @@ -error: label without `#[primary_span]` field +error: derive(Diagnostic): label without `#[primary_span]` field --> $DIR/subdiagnostic-derive.rs:51:1 | LL | #[label(no_crate_example)] | ^ -error: diagnostic slug must be first argument of a `#[label(...)]` attribute +error: derive(Diagnostic): diagnostic slug must be first argument of a `#[label(...)]` attribute --> $DIR/subdiagnostic-derive.rs:58:1 | LL | #[label] | ^ -error: `#[foo]` is not a valid attribute +error: derive(Diagnostic): `#[foo]` is not a valid attribute --> $DIR/subdiagnostic-derive.rs:67:1 | LL | #[foo] | ^ -error: `#[label = ...]` is not a valid attribute +error: derive(Diagnostic): `#[label = ...]` is not a valid attribute --> $DIR/subdiagnostic-derive.rs:77:1 | LL | #[label = "..."] | ^ -error: only `no_span` is a valid nested attribute +error: derive(Diagnostic): only `no_span` is a valid nested attribute --> $DIR/subdiagnostic-derive.rs:86:9 | LL | #[label(bug = "...")] | ^^^ -error: diagnostic slug must be first argument of a `#[label(...)]` attribute +error: derive(Diagnostic): diagnostic slug must be first argument of a `#[label(...)]` attribute --> $DIR/subdiagnostic-derive.rs:86:1 | LL | #[label(bug = "...")] | ^ -error: only `no_span` is a valid nested attribute +error: derive(Diagnostic): only `no_span` is a valid nested attribute --> $DIR/subdiagnostic-derive.rs:106:9 | LL | #[label(slug = 4)] | ^^^^ -error: diagnostic slug must be first argument of a `#[label(...)]` attribute +error: derive(Diagnostic): diagnostic slug must be first argument of a `#[label(...)]` attribute --> $DIR/subdiagnostic-derive.rs:106:1 | LL | #[label(slug = 4)] | ^ -error: only `no_span` is a valid nested attribute +error: derive(Diagnostic): only `no_span` is a valid nested attribute --> $DIR/subdiagnostic-derive.rs:116:9 | LL | #[label(slug("..."))] | ^^^^ -error: diagnostic slug must be first argument of a `#[label(...)]` attribute +error: derive(Diagnostic): diagnostic slug must be first argument of a `#[label(...)]` attribute --> $DIR/subdiagnostic-derive.rs:116:1 | LL | #[label(slug("..."))] | ^ -error: diagnostic slug must be first argument of a `#[label(...)]` attribute +error: derive(Diagnostic): diagnostic slug must be first argument of a `#[label(...)]` attribute --> $DIR/subdiagnostic-derive.rs:136:1 | LL | #[label()] | ^ -error: only `no_span` is a valid nested attribute +error: derive(Diagnostic): only `no_span` is a valid nested attribute --> $DIR/subdiagnostic-derive.rs:145:27 | LL | #[label(no_crate_example, code = "...")] | ^^^^ -error: only `no_span` is a valid nested attribute +error: derive(Diagnostic): only `no_span` is a valid nested attribute --> $DIR/subdiagnostic-derive.rs:154:27 | LL | #[label(no_crate_example, applicability = "machine-applicable")] | ^^^^^^^^^^^^^ -error: unsupported type attribute for subdiagnostic enum +error: derive(Diagnostic): unsupported type attribute for subdiagnostic enum --> $DIR/subdiagnostic-derive.rs:163:1 | LL | #[foo] | ^ -error: `#[bar]` is not a valid attribute +error: derive(Diagnostic): `#[bar]` is not a valid attribute --> $DIR/subdiagnostic-derive.rs:177:5 | LL | #[bar] | ^ -error: `#[bar = ...]` is not a valid attribute +error: derive(Diagnostic): `#[bar = ...]` is not a valid attribute --> $DIR/subdiagnostic-derive.rs:189:5 | LL | #[bar = "..."] | ^ -error: `#[bar = ...]` is not a valid attribute +error: derive(Diagnostic): `#[bar = ...]` is not a valid attribute --> $DIR/subdiagnostic-derive.rs:201:5 | LL | #[bar = 4] | ^ -error: `#[bar(...)]` is not a valid attribute +error: derive(Diagnostic): `#[bar(...)]` is not a valid attribute --> $DIR/subdiagnostic-derive.rs:213:5 | LL | #[bar("...")] | ^ -error: only `no_span` is a valid nested attribute +error: derive(Diagnostic): only `no_span` is a valid nested attribute --> $DIR/subdiagnostic-derive.rs:225:13 | LL | #[label(code = "...")] | ^^^^ -error: diagnostic slug must be first argument of a `#[label(...)]` attribute +error: derive(Diagnostic): diagnostic slug must be first argument of a `#[label(...)]` attribute --> $DIR/subdiagnostic-derive.rs:225:5 | LL | #[label(code = "...")] | ^ -error: the `#[primary_span]` attribute can only be applied to fields of type `Span` or `MultiSpan` +error: derive(Diagnostic): the `#[primary_span]` attribute can only be applied to fields of type `Span` or `MultiSpan` --> $DIR/subdiagnostic-derive.rs:254:5 | LL | #[primary_span] | ^ -error: label without `#[primary_span]` field +error: derive(Diagnostic): label without `#[primary_span]` field --> $DIR/subdiagnostic-derive.rs:251:1 | LL | #[label(no_crate_example)] | ^ -error: `#[applicability]` is only valid on suggestions +error: derive(Diagnostic): `#[applicability]` is only valid on suggestions --> $DIR/subdiagnostic-derive.rs:264:5 | LL | #[applicability] | ^ -error: `#[bar]` is not a valid attribute +error: derive(Diagnostic): `#[bar]` is not a valid attribute --> $DIR/subdiagnostic-derive.rs:274:5 | LL | #[bar] @@ -144,13 +144,13 @@ LL | #[bar] | = help: only `primary_span`, `applicability` and `skip_arg` are valid field attributes -error: `#[bar = ...]` is not a valid attribute +error: derive(Diagnostic): `#[bar = ...]` is not a valid attribute --> $DIR/subdiagnostic-derive.rs:285:5 | LL | #[bar = "..."] | ^ -error: `#[bar(...)]` is not a valid attribute +error: derive(Diagnostic): `#[bar(...)]` is not a valid attribute --> $DIR/subdiagnostic-derive.rs:296:5 | LL | #[bar("...")] @@ -158,13 +158,13 @@ LL | #[bar("...")] | = help: only `primary_span`, `applicability` and `skip_arg` are valid field attributes -error: a diagnostic slug must be the first argument to the attribute +error: derive(Diagnostic): a diagnostic slug must be the first argument to the attribute --> $DIR/subdiagnostic-derive.rs:328:44 | LL | #[label(no_crate_example, no_crate::example)] | ^ -error: specified multiple times +error: derive(Diagnostic): attribute specified multiple times --> $DIR/subdiagnostic-derive.rs:341:5 | LL | #[primary_span] @@ -176,13 +176,13 @@ note: previously specified here LL | #[primary_span] | ^ -error: subdiagnostic kind not specified +error: derive(Diagnostic): subdiagnostic kind not specified --> $DIR/subdiagnostic-derive.rs:347:8 | LL | struct AG { | ^^ -error: specified multiple times +error: derive(Diagnostic): attribute specified multiple times --> $DIR/subdiagnostic-derive.rs:384:46 | LL | #[suggestion(no_crate_example, code = "...", code = "...")] @@ -194,7 +194,7 @@ note: previously specified here LL | #[suggestion(no_crate_example, code = "...", code = "...")] | ^^^^ -error: specified multiple times +error: derive(Diagnostic): attribute specified multiple times --> $DIR/subdiagnostic-derive.rs:402:5 | LL | #[applicability] @@ -206,49 +206,49 @@ note: previously specified here LL | #[applicability] | ^ -error: the `#[applicability]` attribute can only be applied to fields of type `Applicability` +error: derive(Diagnostic): the `#[applicability]` attribute can only be applied to fields of type `Applicability` --> $DIR/subdiagnostic-derive.rs:412:5 | LL | #[applicability] | ^ -error: suggestion without `code = "..."` +error: derive(Diagnostic): suggestion without `code = "..."` --> $DIR/subdiagnostic-derive.rs:425:1 | LL | #[suggestion(no_crate_example)] | ^ -error: invalid applicability +error: derive(Diagnostic): invalid applicability --> $DIR/subdiagnostic-derive.rs:435:62 | LL | #[suggestion(no_crate_example, code = "...", applicability = "foo")] | ^^^^^ -error: suggestion without `#[primary_span]` field +error: derive(Diagnostic): suggestion without `#[primary_span]` field --> $DIR/subdiagnostic-derive.rs:453:1 | LL | #[suggestion(no_crate_example, code = "...")] | ^ -error: unsupported type attribute for subdiagnostic enum +error: derive(Diagnostic): unsupported type attribute for subdiagnostic enum --> $DIR/subdiagnostic-derive.rs:467:1 | LL | #[label] | ^ -error: `var` doesn't refer to a field on this type +error: derive(Diagnostic): `var` doesn't refer to a field on this type --> $DIR/subdiagnostic-derive.rs:487:39 | LL | #[suggestion(no_crate_example, code = "{var}", applicability = "machine-applicable")] | ^^^^^^^ -error: `var` doesn't refer to a field on this type +error: derive(Diagnostic): `var` doesn't refer to a field on this type --> $DIR/subdiagnostic-derive.rs:506:43 | LL | #[suggestion(no_crate_example, code = "{var}", applicability = "machine-applicable")] | ^^^^^^^ -error: `#[suggestion_part]` is not a valid attribute +error: derive(Diagnostic): `#[suggestion_part]` is not a valid attribute --> $DIR/subdiagnostic-derive.rs:529:5 | LL | #[suggestion_part] @@ -256,7 +256,7 @@ LL | #[suggestion_part] | = help: `#[suggestion_part(...)]` is only valid in multipart suggestions, use `#[primary_span]` instead -error: `#[suggestion_part(...)]` is not a valid attribute +error: derive(Diagnostic): `#[suggestion_part(...)]` is not a valid attribute --> $DIR/subdiagnostic-derive.rs:532:5 | LL | #[suggestion_part(code = "...")] @@ -264,13 +264,13 @@ LL | #[suggestion_part(code = "...")] | = help: `#[suggestion_part(...)]` is only valid in multipart suggestions -error: suggestion without `#[primary_span]` field +error: derive(Diagnostic): suggestion without `#[primary_span]` field --> $DIR/subdiagnostic-derive.rs:526:1 | LL | #[suggestion(no_crate_example, code = "...")] | ^ -error: invalid nested attribute +error: derive(Diagnostic): invalid nested attribute --> $DIR/subdiagnostic-derive.rs:541:42 | LL | #[multipart_suggestion(no_crate_example, code = "...", applicability = "machine-applicable")] @@ -278,25 +278,25 @@ LL | #[multipart_suggestion(no_crate_example, code = "...", applicability = "mac | = help: only `no_span`, `style` and `applicability` are valid nested attributes -error: multipart suggestion without any `#[suggestion_part(...)]` fields +error: derive(Diagnostic): multipart suggestion without any `#[suggestion_part(...)]` fields --> $DIR/subdiagnostic-derive.rs:541:1 | LL | #[multipart_suggestion(no_crate_example, code = "...", applicability = "machine-applicable")] | ^ -error: `#[suggestion_part(...)]` attribute without `code = "..."` +error: derive(Diagnostic): `#[suggestion_part(...)]` attribute without `code = "..."` --> $DIR/subdiagnostic-derive.rs:551:5 | LL | #[suggestion_part] | ^ -error: `#[suggestion_part(...)]` attribute without `code = "..."` +error: derive(Diagnostic): `#[suggestion_part(...)]` attribute without `code = "..."` --> $DIR/subdiagnostic-derive.rs:559:5 | LL | #[suggestion_part()] | ^ -error: `#[primary_span]` is not a valid attribute +error: derive(Diagnostic): `#[primary_span]` is not a valid attribute --> $DIR/subdiagnostic-derive.rs:568:5 | LL | #[primary_span] @@ -304,43 +304,43 @@ LL | #[primary_span] | = help: multipart suggestions use one or more `#[suggestion_part]`s rather than one `#[primary_span]` -error: multipart suggestion without any `#[suggestion_part(...)]` fields +error: derive(Diagnostic): multipart suggestion without any `#[suggestion_part(...)]` fields --> $DIR/subdiagnostic-derive.rs:565:1 | LL | #[multipart_suggestion(no_crate_example)] | ^ -error: `#[suggestion_part(...)]` attribute without `code = "..."` +error: derive(Diagnostic): `#[suggestion_part(...)]` attribute without `code = "..."` --> $DIR/subdiagnostic-derive.rs:576:5 | LL | #[suggestion_part] | ^ -error: `#[suggestion_part(...)]` attribute without `code = "..."` +error: derive(Diagnostic): `#[suggestion_part(...)]` attribute without `code = "..."` --> $DIR/subdiagnostic-derive.rs:579:5 | LL | #[suggestion_part()] | ^ -error: `code` is the only valid nested attribute +error: derive(Diagnostic): `code` is the only valid nested attribute --> $DIR/subdiagnostic-derive.rs:582:23 | LL | #[suggestion_part(foo = "bar")] | ^^^ -error: the `#[suggestion_part(...)]` attribute can only be applied to fields of type `Span` or `MultiSpan` +error: derive(Diagnostic): the `#[suggestion_part(...)]` attribute can only be applied to fields of type `Span` or `MultiSpan` --> $DIR/subdiagnostic-derive.rs:587:5 | LL | #[suggestion_part(code = "...")] | ^ -error: the `#[suggestion_part(...)]` attribute can only be applied to fields of type `Span` or `MultiSpan` +error: derive(Diagnostic): the `#[suggestion_part(...)]` attribute can only be applied to fields of type `Span` or `MultiSpan` --> $DIR/subdiagnostic-derive.rs:590:5 | LL | #[suggestion_part()] | ^ -error: specified multiple times +error: derive(Diagnostic): attribute specified multiple times --> $DIR/subdiagnostic-derive.rs:598:37 | LL | #[suggestion_part(code = "...", code = ",,,")] @@ -352,37 +352,37 @@ note: previously specified here LL | #[suggestion_part(code = "...", code = ",,,")] | ^^^^ -error: `#[applicability]` has no effect if all `#[suggestion]`/`#[multipart_suggestion]` attributes have a static `applicability = "..."` +error: derive(Diagnostic): `#[applicability]` has no effect if all `#[suggestion]`/`#[multipart_suggestion]` attributes have a static `applicability = "..."` --> $DIR/subdiagnostic-derive.rs:627:5 | LL | #[applicability] | ^ -error: expected exactly one string literal for `code = ...` +error: derive(Diagnostic): expected exactly one string literal for `code = ...` --> $DIR/subdiagnostic-derive.rs:675:34 | LL | #[suggestion_part(code("foo"))] | ^ -error: expected exactly one string literal for `code = ...` +error: derive(Diagnostic): expected exactly one string literal for `code = ...` --> $DIR/subdiagnostic-derive.rs:686:41 | LL | #[suggestion_part(code("foo", "bar"))] | ^ -error: expected exactly one string literal for `code = ...` +error: derive(Diagnostic): expected exactly one string literal for `code = ...` --> $DIR/subdiagnostic-derive.rs:697:30 | LL | #[suggestion_part(code(3))] | ^ -error: expected exactly one string literal for `code = ...` +error: derive(Diagnostic): expected exactly one string literal for `code = ...` --> $DIR/subdiagnostic-derive.rs:708:29 | LL | #[suggestion_part(code())] | ^ -error: specified multiple times +error: derive(Diagnostic): attribute specified multiple times --> $DIR/subdiagnostic-derive.rs:763:1 | LL | #[suggestion(no_crate_example, code = "", style = "hidden", style = "normal")] @@ -394,7 +394,7 @@ note: previously specified here LL | #[suggestion(no_crate_example, code = "", style = "hidden", style = "normal")] | ^ -error: `#[suggestion_hidden(...)]` is not a valid attribute +error: derive(Diagnostic): `#[suggestion_hidden(...)]` is not a valid attribute --> $DIR/subdiagnostic-derive.rs:772:1 | LL | #[suggestion_hidden(no_crate_example, code = "")] @@ -402,7 +402,7 @@ LL | #[suggestion_hidden(no_crate_example, code = "")] | = help: Use `#[suggestion(..., style = "hidden")]` instead -error: `#[suggestion_hidden(...)]` is not a valid attribute +error: derive(Diagnostic): `#[suggestion_hidden(...)]` is not a valid attribute --> $DIR/subdiagnostic-derive.rs:780:1 | LL | #[suggestion_hidden(no_crate_example, code = "", style = "normal")] @@ -410,7 +410,7 @@ LL | #[suggestion_hidden(no_crate_example, code = "", style = "normal")] | = help: Use `#[suggestion(..., style = "hidden")]` instead -error: invalid suggestion style +error: derive(Diagnostic): invalid suggestion style --> $DIR/subdiagnostic-derive.rs:788:51 | LL | #[suggestion(no_crate_example, code = "", style = "foo")] @@ -418,25 +418,25 @@ LL | #[suggestion(no_crate_example, code = "", style = "foo")] | = help: valid styles are `normal`, `short`, `hidden`, `verbose` and `tool-only` -error: expected `= "xxx"` +error: derive(Diagnostic): expected `= "xxx"` --> $DIR/subdiagnostic-derive.rs:796:49 | LL | #[suggestion(no_crate_example, code = "", style = 42)] | ^ -error: a diagnostic slug must be the first argument to the attribute +error: derive(Diagnostic): a diagnostic slug must be the first argument to the attribute --> $DIR/subdiagnostic-derive.rs:804:48 | LL | #[suggestion(no_crate_example, code = "", style)] | ^ -error: expected `= "xxx"` +error: derive(Diagnostic): expected `= "xxx"` --> $DIR/subdiagnostic-derive.rs:812:48 | LL | #[suggestion(no_crate_example, code = "", style("foo"))] | ^ -error: `#[primary_span]` is not a valid attribute +error: derive(Diagnostic): `#[primary_span]` is not a valid attribute --> $DIR/subdiagnostic-derive.rs:825:5 | LL | #[primary_span] @@ -445,7 +445,7 @@ LL | #[primary_span] = note: there must be exactly one primary span = help: to create a suggestion with multiple spans, use `#[multipart_suggestion]` instead -error: suggestion without `#[primary_span]` field +error: derive(Diagnostic): suggestion without `#[primary_span]` field --> $DIR/subdiagnostic-derive.rs:822:1 | LL | #[suggestion(no_crate_example, code = "")] diff --git a/tests/ui-fulldeps/try-from-u32/errors.rs b/tests/ui-fulldeps/try-from-u32/errors.rs new file mode 100644 index 00000000000..0470063312c --- /dev/null +++ b/tests/ui-fulldeps/try-from-u32/errors.rs @@ -0,0 +1,24 @@ +#![feature(rustc_private)] +//@ edition: 2021 + +// Checks the error messages produced by `#[derive(TryFromU32)]`. + +extern crate rustc_macros; + +use rustc_macros::TryFromU32; + +#[derive(TryFromU32)] +struct MyStruct {} //~ type is not an enum + +#[derive(TryFromU32)] +enum NonTrivial { + A, + B(), + C {}, + D(bool), //~ enum variant cannot have fields + E(bool, bool), //~ enum variant cannot have fields + F { x: bool }, //~ enum variant cannot have fields + G { x: bool, y: bool }, //~ enum variant cannot have fields +} + +fn main() {} diff --git a/tests/ui-fulldeps/try-from-u32/errors.stderr b/tests/ui-fulldeps/try-from-u32/errors.stderr new file mode 100644 index 00000000000..d20567061d7 --- /dev/null +++ b/tests/ui-fulldeps/try-from-u32/errors.stderr @@ -0,0 +1,32 @@ +error: type is not an enum (TryFromU32) + --> $DIR/errors.rs:11:1 + | +LL | struct MyStruct {} + | ^^^^^^ + +error: enum variant cannot have fields (TryFromU32) + --> $DIR/errors.rs:18:7 + | +LL | D(bool), + | ^^^^ + +error: enum variant cannot have fields (TryFromU32) + --> $DIR/errors.rs:19:7 + | +LL | E(bool, bool), + | ^^^^ + +error: enum variant cannot have fields (TryFromU32) + --> $DIR/errors.rs:20:9 + | +LL | F { x: bool }, + | ^ + +error: enum variant cannot have fields (TryFromU32) + --> $DIR/errors.rs:21:9 + | +LL | G { x: bool, y: bool }, + | ^ + +error: aborting due to 5 previous errors + diff --git a/tests/ui-fulldeps/try-from-u32/hygiene.rs b/tests/ui-fulldeps/try-from-u32/hygiene.rs new file mode 100644 index 00000000000..e0655a64a64 --- /dev/null +++ b/tests/ui-fulldeps/try-from-u32/hygiene.rs @@ -0,0 +1,32 @@ +#![feature(rustc_private)] +//@ edition: 2021 +//@ check-pass + +// Checks that the derive macro still works even if the surrounding code has +// shadowed the relevant library types. + +extern crate rustc_macros; + +mod submod { + use rustc_macros::TryFromU32; + + struct Result; + trait TryFrom {} + #[allow(non_camel_case_types)] + struct u32; + struct Ok; + struct Err; + mod core {} + mod std {} + + #[derive(TryFromU32)] + pub(crate) enum MyEnum { + Zero, + One, + } +} + +fn main() { + use submod::MyEnum; + let _: Result<MyEnum, u32> = MyEnum::try_from(1u32); +} diff --git a/tests/ui-fulldeps/try-from-u32/values.rs b/tests/ui-fulldeps/try-from-u32/values.rs new file mode 100644 index 00000000000..180a8f2beb7 --- /dev/null +++ b/tests/ui-fulldeps/try-from-u32/values.rs @@ -0,0 +1,36 @@ +#![feature(assert_matches)] +#![feature(rustc_private)] +//@ edition: 2021 +//@ run-pass + +// Checks the values accepted by the `TryFrom<u32>` impl produced by `#[derive(TryFromU32)]`. + +extern crate rustc_macros; + +use core::assert_matches::assert_matches; +use rustc_macros::TryFromU32; + +#[derive(TryFromU32, Debug, PartialEq)] +#[repr(u32)] +enum Repr { + Zero, + One(), + Seven = 7, +} + +#[derive(TryFromU32, Debug)] +enum NoRepr { + Zero, + One, +} + +fn main() { + assert_eq!(Repr::try_from(0u32), Ok(Repr::Zero)); + assert_eq!(Repr::try_from(1u32), Ok(Repr::One())); + assert_eq!(Repr::try_from(2u32), Err(2)); + assert_eq!(Repr::try_from(7u32), Ok(Repr::Seven)); + + assert_matches!(NoRepr::try_from(0u32), Ok(NoRepr::Zero)); + assert_matches!(NoRepr::try_from(1u32), Ok(NoRepr::One)); + assert_matches!(NoRepr::try_from(2u32), Err(2)); +} diff --git a/tests/ui/array-slice-vec/vec-macro-with-comma-only.rs b/tests/ui/array-slice-vec/vec-macro-with-comma-only.rs index 574a53c58fe..0f99f6b1b1e 100644 --- a/tests/ui/array-slice-vec/vec-macro-with-comma-only.rs +++ b/tests/ui/array-slice-vec/vec-macro-with-comma-only.rs @@ -1,3 +1,3 @@ pub fn main() { - vec![,]; //~ ERROR no rules expected the token `,` + vec![,]; //~ ERROR no rules expected `,` } diff --git a/tests/ui/array-slice-vec/vec-macro-with-comma-only.stderr b/tests/ui/array-slice-vec/vec-macro-with-comma-only.stderr index b3f953af6d2..d76d493eca8 100644 --- a/tests/ui/array-slice-vec/vec-macro-with-comma-only.stderr +++ b/tests/ui/array-slice-vec/vec-macro-with-comma-only.stderr @@ -1,4 +1,4 @@ -error: no rules expected the token `,` +error: no rules expected `,` --> $DIR/vec-macro-with-comma-only.rs:2:10 | LL | vec![,]; diff --git a/tests/ui/associated-consts/issue-58022.stderr b/tests/ui/associated-consts/issue-58022.stderr index 6ce995eaab7..82cbc9ed3b0 100644 --- a/tests/ui/associated-consts/issue-58022.stderr +++ b/tests/ui/associated-consts/issue-58022.stderr @@ -13,7 +13,7 @@ error[E0277]: the size for values of type `[u8]` cannot be known at compilation LL | fn new(slice: &[u8; Self::SIZE]) -> Self { | ^^^^ doesn't have a size known at compile-time | - = help: within `Bar<[u8]>`, the trait `Sized` is not implemented for `[u8]`, which is required by `Bar<[u8]>: Sized` + = help: within `Bar<[u8]>`, the trait `Sized` is not implemented for `[u8]` note: required because it appears within the type `Bar<[u8]>` --> $DIR/issue-58022.rs:8:12 | diff --git a/tests/ui/associated-type-bounds/implied-from-self-where-clause.rs b/tests/ui/associated-type-bounds/implied-from-self-where-clause.rs new file mode 100644 index 00000000000..38f55696914 --- /dev/null +++ b/tests/ui/associated-type-bounds/implied-from-self-where-clause.rs @@ -0,0 +1,21 @@ +// Make sure that, like associated type where clauses on traits, we gather item +// bounds for RPITITs from RTN where clauses. + +//@ check-pass + +#![feature(return_type_notation)] + +trait Foo +where + Self::method(..): Send, +{ + fn method() -> impl Sized; +} + +fn is_send(_: impl Send) {} + +fn test<T: Foo>() { + is_send(T::method()); +} + +fn main() {} diff --git a/tests/ui/associated-type-bounds/return-type-notation/basic.without.stderr b/tests/ui/associated-type-bounds/return-type-notation/basic.without.stderr index 110d2a00583..0a31cc67533 100644 --- a/tests/ui/associated-type-bounds/return-type-notation/basic.without.stderr +++ b/tests/ui/associated-type-bounds/return-type-notation/basic.without.stderr @@ -4,7 +4,7 @@ error: future cannot be sent between threads safely LL | is_send(foo::<T>()); | ^^^^^^^^^^ future returned by `foo` is not `Send` | - = help: within `impl Future<Output = Result<(), ()>>`, the trait `Send` is not implemented for `impl Future<Output = Result<(), ()>> { <T as Foo>::method(..) }`, which is required by `impl Future<Output = Result<(), ()>>: Send` + = help: within `impl Future<Output = Result<(), ()>>`, the trait `Send` is not implemented for `impl Future<Output = Result<(), ()>> { <T as Foo>::method(..) }` note: future is not `Send` as it awaits another future which is not `Send` --> $DIR/basic.rs:12:5 | diff --git a/tests/crashes/131648.rs b/tests/ui/associated-type-bounds/return-type-notation/impl-trait-in-trait.rs index 68046ce2a1f..0d3e6f9c8e3 100644 --- a/tests/crashes/131648.rs +++ b/tests/ui/associated-type-bounds/return-type-notation/impl-trait-in-trait.rs @@ -1,7 +1,8 @@ -//@ known-bug: #131648 #![feature(return_type_notation)] trait IntFactory { fn stream(self) -> impl IntFactory<stream(..): Send>; + //~^ ERROR cycle detected when resolving lifetimes for `IntFactory::stream` } + fn main() {} diff --git a/tests/ui/associated-type-bounds/return-type-notation/impl-trait-in-trait.stderr b/tests/ui/associated-type-bounds/return-type-notation/impl-trait-in-trait.stderr new file mode 100644 index 00000000000..0ed54415b9e --- /dev/null +++ b/tests/ui/associated-type-bounds/return-type-notation/impl-trait-in-trait.stderr @@ -0,0 +1,27 @@ +error[E0391]: cycle detected when resolving lifetimes for `IntFactory::stream` + --> $DIR/impl-trait-in-trait.rs:4:5 + | +LL | fn stream(self) -> impl IntFactory<stream(..): Send>; + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + | +note: ...which requires computing function signature of `IntFactory::stream`... + --> $DIR/impl-trait-in-trait.rs:4:5 + | +LL | fn stream(self) -> impl IntFactory<stream(..): Send>; + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ +note: ...which requires looking up late bound vars inside `IntFactory::stream`... + --> $DIR/impl-trait-in-trait.rs:4:5 + | +LL | fn stream(self) -> impl IntFactory<stream(..): Send>; + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + = note: ...which again requires resolving lifetimes for `IntFactory::stream`, completing the cycle +note: cycle used when listing captured lifetimes for opaque `IntFactory::stream::{opaque#0}` + --> $DIR/impl-trait-in-trait.rs:4:24 + | +LL | fn stream(self) -> impl IntFactory<stream(..): Send>; + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + = note: see https://rustc-dev-guide.rust-lang.org/overview.html#queries and https://rustc-dev-guide.rust-lang.org/query.html for more information + +error: aborting due to 1 previous error + +For more information about this error, try `rustc --explain E0391`. diff --git a/tests/ui/associated-type-bounds/return-type-notation/path-unsatisfied.stderr b/tests/ui/associated-type-bounds/return-type-notation/path-unsatisfied.stderr index 95810342d5a..90d0feb5217 100644 --- a/tests/ui/associated-type-bounds/return-type-notation/path-unsatisfied.stderr +++ b/tests/ui/associated-type-bounds/return-type-notation/path-unsatisfied.stderr @@ -7,7 +7,7 @@ LL | fn method() -> impl Sized { LL | test::<DoesntWork>(); | ^^^^^^^^^^ `*mut ()` cannot be sent between threads safely | - = help: within `impl Sized`, the trait `Send` is not implemented for `*mut ()`, which is required by `impl Sized: Send` + = help: within `impl Sized`, the trait `Send` is not implemented for `*mut ()` note: required because it appears within the type `impl Sized` --> $DIR/path-unsatisfied.rs:9:20 | diff --git a/tests/ui/associated-types/defaults-suitability.current.stderr b/tests/ui/associated-types/defaults-suitability.current.stderr index 3cdeaa93a34..9c0ae59ae43 100644 --- a/tests/ui/associated-types/defaults-suitability.current.stderr +++ b/tests/ui/associated-types/defaults-suitability.current.stderr @@ -39,7 +39,7 @@ error[E0277]: the trait bound `T: Clone` is not satisfied --> $DIR/defaults-suitability.rs:31:23 | LL | type Bar: Clone = Vec<T>; - | ^^^^^^ the trait `Clone` is not implemented for `T`, which is required by `Vec<T>: Clone` + | ^^^^^^ the trait `Clone` is not implemented for `T` | = note: required for `Vec<T>` to implement `Clone` note: required by a bound in `Foo::Bar` @@ -88,7 +88,7 @@ error[E0277]: the trait bound `<Self as Foo2<T>>::Baz: Clone` is not satisfied --> $DIR/defaults-suitability.rs:68:23 | LL | type Bar: Clone = Vec<Self::Baz>; - | ^^^^^^^^^^^^^^ the trait `Clone` is not implemented for `<Self as Foo2<T>>::Baz`, which is required by `Vec<<Self as Foo2<T>>::Baz>: Clone` + | ^^^^^^^^^^^^^^ the trait `Clone` is not implemented for `<Self as Foo2<T>>::Baz` | = note: required for `Vec<<Self as Foo2<T>>::Baz>` to implement `Clone` note: required by a bound in `Foo2::Bar` @@ -105,7 +105,7 @@ error[E0277]: the trait bound `<Self as Foo25<T>>::Baz: Clone` is not satisfied --> $DIR/defaults-suitability.rs:77:23 | LL | type Bar: Clone = Vec<Self::Baz>; - | ^^^^^^^^^^^^^^ the trait `Clone` is not implemented for `<Self as Foo25<T>>::Baz`, which is required by `Vec<<Self as Foo25<T>>::Baz>: Clone` + | ^^^^^^^^^^^^^^ the trait `Clone` is not implemented for `<Self as Foo25<T>>::Baz` | = note: required for `Vec<<Self as Foo25<T>>::Baz>` to implement `Clone` note: required by a bound in `Foo25::Bar` diff --git a/tests/ui/associated-types/defaults-suitability.next.stderr b/tests/ui/associated-types/defaults-suitability.next.stderr index 3cdeaa93a34..9c0ae59ae43 100644 --- a/tests/ui/associated-types/defaults-suitability.next.stderr +++ b/tests/ui/associated-types/defaults-suitability.next.stderr @@ -39,7 +39,7 @@ error[E0277]: the trait bound `T: Clone` is not satisfied --> $DIR/defaults-suitability.rs:31:23 | LL | type Bar: Clone = Vec<T>; - | ^^^^^^ the trait `Clone` is not implemented for `T`, which is required by `Vec<T>: Clone` + | ^^^^^^ the trait `Clone` is not implemented for `T` | = note: required for `Vec<T>` to implement `Clone` note: required by a bound in `Foo::Bar` @@ -88,7 +88,7 @@ error[E0277]: the trait bound `<Self as Foo2<T>>::Baz: Clone` is not satisfied --> $DIR/defaults-suitability.rs:68:23 | LL | type Bar: Clone = Vec<Self::Baz>; - | ^^^^^^^^^^^^^^ the trait `Clone` is not implemented for `<Self as Foo2<T>>::Baz`, which is required by `Vec<<Self as Foo2<T>>::Baz>: Clone` + | ^^^^^^^^^^^^^^ the trait `Clone` is not implemented for `<Self as Foo2<T>>::Baz` | = note: required for `Vec<<Self as Foo2<T>>::Baz>` to implement `Clone` note: required by a bound in `Foo2::Bar` @@ -105,7 +105,7 @@ error[E0277]: the trait bound `<Self as Foo25<T>>::Baz: Clone` is not satisfied --> $DIR/defaults-suitability.rs:77:23 | LL | type Bar: Clone = Vec<Self::Baz>; - | ^^^^^^^^^^^^^^ the trait `Clone` is not implemented for `<Self as Foo25<T>>::Baz`, which is required by `Vec<<Self as Foo25<T>>::Baz>: Clone` + | ^^^^^^^^^^^^^^ the trait `Clone` is not implemented for `<Self as Foo25<T>>::Baz` | = note: required for `Vec<<Self as Foo25<T>>::Baz>` to implement `Clone` note: required by a bound in `Foo25::Bar` diff --git a/tests/ui/associated-types/hr-associated-type-bound-1.stderr b/tests/ui/associated-types/hr-associated-type-bound-1.stderr index 8830048ed4e..5b00e714194 100644 --- a/tests/ui/associated-types/hr-associated-type-bound-1.stderr +++ b/tests/ui/associated-types/hr-associated-type-bound-1.stderr @@ -2,7 +2,7 @@ error[E0277]: the trait bound `str: Clone` is not satisfied --> $DIR/hr-associated-type-bound-1.rs:12:14 | LL | type U = str; - | ^^^ the trait `Clone` is not implemented for `str`, which is required by `for<'b> <i32 as X<'b>>::U: Clone` + | ^^^ the trait `Clone` is not implemented for `str` | = help: the trait `Clone` is implemented for `String` note: required by a bound in `X` diff --git a/tests/ui/associated-types/hr-associated-type-bound-param-1.stderr b/tests/ui/associated-types/hr-associated-type-bound-param-1.stderr index ad6d3e17684..07d3afb74e4 100644 --- a/tests/ui/associated-types/hr-associated-type-bound-param-1.stderr +++ b/tests/ui/associated-types/hr-associated-type-bound-param-1.stderr @@ -2,7 +2,7 @@ error[E0277]: the trait bound `str: Clone` is not satisfied --> $DIR/hr-associated-type-bound-param-1.rs:14:14 | LL | type V = str; - | ^^^ the trait `Clone` is not implemented for `str`, which is required by `for<'b> <u8 as Y<'b, u8>>::V: Clone` + | ^^^ the trait `Clone` is not implemented for `str` | = help: the trait `Clone` is implemented for `String` note: required by a bound in `Y` diff --git a/tests/ui/associated-types/hr-associated-type-bound-param-2.stderr b/tests/ui/associated-types/hr-associated-type-bound-param-2.stderr index 6a5729e7784..74cc2083d26 100644 --- a/tests/ui/associated-types/hr-associated-type-bound-param-2.stderr +++ b/tests/ui/associated-types/hr-associated-type-bound-param-2.stderr @@ -18,7 +18,7 @@ error[E0277]: the trait bound `str: Clone` is not satisfied --> $DIR/hr-associated-type-bound-param-2.rs:17:14 | LL | type W = str; - | ^^^ the trait `Clone` is not implemented for `str`, which is required by `for<'b> <u16 as Z<'b, u16>>::W: Clone` + | ^^^ the trait `Clone` is not implemented for `str` | = help: the trait `Clone` is implemented for `String` note: required by a bound in `Z` diff --git a/tests/ui/associated-types/hr-associated-type-bound-param-3.stderr b/tests/ui/associated-types/hr-associated-type-bound-param-3.stderr index 70e030f2d1c..58b82fc9306 100644 --- a/tests/ui/associated-types/hr-associated-type-bound-param-3.stderr +++ b/tests/ui/associated-types/hr-associated-type-bound-param-3.stderr @@ -2,7 +2,7 @@ error[E0277]: the trait bound `str: Clone` is not satisfied --> $DIR/hr-associated-type-bound-param-3.rs:13:14 | LL | type U = str; - | ^^^ the trait `Clone` is not implemented for `str`, which is required by `for<'b> <(T,) as X<'b, (T,)>>::U: Clone` + | ^^^ the trait `Clone` is not implemented for `str` | = help: the trait `Clone` is implemented for `String` note: required by a bound in `X` diff --git a/tests/ui/associated-types/hr-associated-type-bound-param-4.stderr b/tests/ui/associated-types/hr-associated-type-bound-param-4.stderr index cba12afd674..6d6373a1918 100644 --- a/tests/ui/associated-types/hr-associated-type-bound-param-4.stderr +++ b/tests/ui/associated-types/hr-associated-type-bound-param-4.stderr @@ -2,7 +2,7 @@ error[E0277]: the trait bound `str: Clone` is not satisfied --> $DIR/hr-associated-type-bound-param-4.rs:13:14 | LL | type U = str; - | ^^^ the trait `Clone` is not implemented for `str`, which is required by `for<'b> <(T,) as X<'b, T>>::U: Clone` + | ^^^ the trait `Clone` is not implemented for `str` | = help: the trait `Clone` is implemented for `String` note: required by a bound in `X` diff --git a/tests/ui/associated-types/hr-associated-type-bound-param-5.stderr b/tests/ui/associated-types/hr-associated-type-bound-param-5.stderr index ac96187749a..44c446c599f 100644 --- a/tests/ui/associated-types/hr-associated-type-bound-param-5.stderr +++ b/tests/ui/associated-types/hr-associated-type-bound-param-5.stderr @@ -2,7 +2,7 @@ error[E0277]: the trait bound `str: Clone` is not satisfied --> $DIR/hr-associated-type-bound-param-5.rs:26:14 | LL | type U = str; - | ^^^ the trait `Clone` is not implemented for `str`, which is required by `for<'b> <<Vec<T> as Cycle>::Next as X<'b, <Vec<T> as Cycle>::Next>>::U: Clone` + | ^^^ the trait `Clone` is not implemented for `str` | = help: the trait `Clone` is implemented for `String` note: required by a bound in `X` @@ -18,7 +18,7 @@ error[E0277]: the trait bound `str: Clone` is not satisfied --> $DIR/hr-associated-type-bound-param-5.rs:31:14 | LL | type U = str; - | ^^^ the trait `Clone` is not implemented for `str`, which is required by `for<'b> <<Box<T> as Cycle>::Next as X<'b, <Box<T> as Cycle>::Next>>::U: Clone` + | ^^^ the trait `Clone` is not implemented for `str` | = help: the trait `Clone` is implemented for `String` note: required by a bound in `X` diff --git a/tests/ui/associated-types/issue-38821.stderr b/tests/ui/associated-types/issue-38821.stderr index f1c8f83e30c..58f019704e7 100644 --- a/tests/ui/associated-types/issue-38821.stderr +++ b/tests/ui/associated-types/issue-38821.stderr @@ -2,7 +2,7 @@ error[E0277]: the trait bound `<Col as Expression>::SqlType: NotNull` is not sat --> $DIR/issue-38821.rs:40:1 | LL | pub enum ColumnInsertValue<Col, Expr> where - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ the trait `NotNull` is not implemented for `<Col as Expression>::SqlType`, which is required by `<Col as Expression>::SqlType: IntoNullable` + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ the trait `NotNull` is not implemented for `<Col as Expression>::SqlType` | note: required for `<Col as Expression>::SqlType` to implement `IntoNullable` --> $DIR/issue-38821.rs:9:18 @@ -26,7 +26,7 @@ LL | | Col: Column, ... | LL | | Default(Col), LL | | } - | |_^ the trait `NotNull` is not implemented for `<Col as Expression>::SqlType`, which is required by `<Col as Expression>::SqlType: IntoNullable` + | |_^ the trait `NotNull` is not implemented for `<Col as Expression>::SqlType` | note: required for `<Col as Expression>::SqlType` to implement `IntoNullable` --> $DIR/issue-38821.rs:9:18 @@ -44,7 +44,7 @@ error[E0277]: the trait bound `<Col as Expression>::SqlType: NotNull` is not sat --> $DIR/issue-38821.rs:23:10 | LL | #[derive(Debug, Copy, Clone)] - | ^^^^^ the trait `NotNull` is not implemented for `<Col as Expression>::SqlType`, which is required by `<Col as Expression>::SqlType: IntoNullable` + | ^^^^^ the trait `NotNull` is not implemented for `<Col as Expression>::SqlType` | note: required for `<Col as Expression>::SqlType` to implement `IntoNullable` --> $DIR/issue-38821.rs:9:18 @@ -63,7 +63,7 @@ error[E0277]: the trait bound `<Col as Expression>::SqlType: NotNull` is not sat --> $DIR/issue-38821.rs:23:10 | LL | #[derive(Debug, Copy, Clone)] - | ^^^^^ the trait `NotNull` is not implemented for `<Col as Expression>::SqlType`, which is required by `<Col as Expression>::SqlType: IntoNullable` + | ^^^^^ the trait `NotNull` is not implemented for `<Col as Expression>::SqlType` | note: required for `<Col as Expression>::SqlType` to implement `IntoNullable` --> $DIR/issue-38821.rs:9:18 @@ -83,7 +83,7 @@ error[E0277]: the trait bound `<Col as Expression>::SqlType: NotNull` is not sat --> $DIR/issue-38821.rs:23:10 | LL | #[derive(Debug, Copy, Clone)] - | ^^^^^ the trait `NotNull` is not implemented for `<Col as Expression>::SqlType`, which is required by `<Col as Expression>::SqlType: IntoNullable` + | ^^^^^ the trait `NotNull` is not implemented for `<Col as Expression>::SqlType` | note: required for `<Col as Expression>::SqlType` to implement `IntoNullable` --> $DIR/issue-38821.rs:9:18 @@ -98,7 +98,7 @@ error[E0277]: the trait bound `<Col as Expression>::SqlType: NotNull` is not sat --> $DIR/issue-38821.rs:23:10 | LL | #[derive(Debug, Copy, Clone)] - | ^^^^^ the trait `NotNull` is not implemented for `<Col as Expression>::SqlType`, which is required by `<Col as Expression>::SqlType: IntoNullable` + | ^^^^^ the trait `NotNull` is not implemented for `<Col as Expression>::SqlType` | note: required for `<Col as Expression>::SqlType` to implement `IntoNullable` --> $DIR/issue-38821.rs:9:18 @@ -114,7 +114,7 @@ error[E0277]: the trait bound `<Col as Expression>::SqlType: NotNull` is not sat --> $DIR/issue-38821.rs:23:17 | LL | #[derive(Debug, Copy, Clone)] - | ^^^^ the trait `NotNull` is not implemented for `<Col as Expression>::SqlType`, which is required by `<Col as Expression>::SqlType: IntoNullable` + | ^^^^ the trait `NotNull` is not implemented for `<Col as Expression>::SqlType` | note: required for `<Col as Expression>::SqlType` to implement `IntoNullable` --> $DIR/issue-38821.rs:9:18 @@ -133,7 +133,7 @@ error[E0277]: the trait bound `<Col as Expression>::SqlType: NotNull` is not sat --> $DIR/issue-38821.rs:23:17 | LL | #[derive(Debug, Copy, Clone)] - | ^^^^ the trait `NotNull` is not implemented for `<Col as Expression>::SqlType`, which is required by `<Col as Expression>::SqlType: IntoNullable` + | ^^^^ the trait `NotNull` is not implemented for `<Col as Expression>::SqlType` | note: required for `<Col as Expression>::SqlType` to implement `IntoNullable` --> $DIR/issue-38821.rs:9:18 @@ -153,7 +153,7 @@ error[E0277]: the trait bound `<Col as Expression>::SqlType: NotNull` is not sat --> $DIR/issue-38821.rs:23:23 | LL | #[derive(Debug, Copy, Clone)] - | ^^^^^ the trait `NotNull` is not implemented for `<Col as Expression>::SqlType`, which is required by `<Col as Expression>::SqlType: IntoNullable` + | ^^^^^ the trait `NotNull` is not implemented for `<Col as Expression>::SqlType` | note: required for `<Col as Expression>::SqlType` to implement `IntoNullable` --> $DIR/issue-38821.rs:9:18 @@ -172,7 +172,7 @@ error[E0277]: the trait bound `<Col as Expression>::SqlType: NotNull` is not sat --> $DIR/issue-38821.rs:23:23 | LL | #[derive(Debug, Copy, Clone)] - | ^^^^^ the trait `NotNull` is not implemented for `<Col as Expression>::SqlType`, which is required by `<Col as Expression>::SqlType: IntoNullable` + | ^^^^^ the trait `NotNull` is not implemented for `<Col as Expression>::SqlType` | note: required for `<Col as Expression>::SqlType` to implement `IntoNullable` --> $DIR/issue-38821.rs:9:18 @@ -192,7 +192,7 @@ error[E0277]: the trait bound `<Col as Expression>::SqlType: NotNull` is not sat --> $DIR/issue-38821.rs:23:23 | LL | #[derive(Debug, Copy, Clone)] - | ^^^^^ the trait `NotNull` is not implemented for `<Col as Expression>::SqlType`, which is required by `<Col as Expression>::SqlType: IntoNullable` + | ^^^^^ the trait `NotNull` is not implemented for `<Col as Expression>::SqlType` | note: required for `<Col as Expression>::SqlType` to implement `IntoNullable` --> $DIR/issue-38821.rs:9:18 @@ -207,7 +207,7 @@ error[E0277]: the trait bound `<Col as Expression>::SqlType: NotNull` is not sat --> $DIR/issue-38821.rs:23:23 | LL | #[derive(Debug, Copy, Clone)] - | ^^^^^ the trait `NotNull` is not implemented for `<Col as Expression>::SqlType`, which is required by `<Col as Expression>::SqlType: IntoNullable` + | ^^^^^ the trait `NotNull` is not implemented for `<Col as Expression>::SqlType` | note: required for `<Col as Expression>::SqlType` to implement `IntoNullable` --> $DIR/issue-38821.rs:9:18 @@ -223,7 +223,7 @@ error[E0277]: the trait bound `<Col as Expression>::SqlType: NotNull` is not sat --> $DIR/issue-38821.rs:23:10 | LL | #[derive(Debug, Copy, Clone)] - | ^^^^^ the trait `NotNull` is not implemented for `<Col as Expression>::SqlType`, which is required by `<Col as Expression>::SqlType: IntoNullable` + | ^^^^^ the trait `NotNull` is not implemented for `<Col as Expression>::SqlType` | note: required for `<Col as Expression>::SqlType` to implement `IntoNullable` --> $DIR/issue-38821.rs:9:18 @@ -239,7 +239,7 @@ error[E0277]: the trait bound `<Col as Expression>::SqlType: NotNull` is not sat --> $DIR/issue-38821.rs:23:10 | LL | #[derive(Debug, Copy, Clone)] - | ^^^^^ the trait `NotNull` is not implemented for `<Col as Expression>::SqlType`, which is required by `<Col as Expression>::SqlType: IntoNullable` + | ^^^^^ the trait `NotNull` is not implemented for `<Col as Expression>::SqlType` | note: required for `<Col as Expression>::SqlType` to implement `IntoNullable` --> $DIR/issue-38821.rs:9:18 @@ -255,7 +255,7 @@ error[E0277]: the trait bound `<Col as Expression>::SqlType: NotNull` is not sat --> $DIR/issue-38821.rs:23:23 | LL | #[derive(Debug, Copy, Clone)] - | ^^^^^ the trait `NotNull` is not implemented for `<Col as Expression>::SqlType`, which is required by `<Col as Expression>::SqlType: IntoNullable` + | ^^^^^ the trait `NotNull` is not implemented for `<Col as Expression>::SqlType` | note: required for `<Col as Expression>::SqlType` to implement `IntoNullable` --> $DIR/issue-38821.rs:9:18 @@ -271,7 +271,7 @@ error[E0277]: the trait bound `<Col as Expression>::SqlType: NotNull` is not sat --> $DIR/issue-38821.rs:23:23 | LL | #[derive(Debug, Copy, Clone)] - | ^^^^^ the trait `NotNull` is not implemented for `<Col as Expression>::SqlType`, which is required by `<Col as Expression>::SqlType: IntoNullable` + | ^^^^^ the trait `NotNull` is not implemented for `<Col as Expression>::SqlType` | note: required for `<Col as Expression>::SqlType` to implement `IntoNullable` --> $DIR/issue-38821.rs:9:18 @@ -287,7 +287,7 @@ error[E0277]: the trait bound `<Col as Expression>::SqlType: NotNull` is not sat --> $DIR/issue-38821.rs:23:10 | LL | #[derive(Debug, Copy, Clone)] - | ^^^^^ the trait `NotNull` is not implemented for `<Col as Expression>::SqlType`, which is required by `<Col as Expression>::SqlType: IntoNullable` + | ^^^^^ the trait `NotNull` is not implemented for `<Col as Expression>::SqlType` | note: required for `<Col as Expression>::SqlType` to implement `IntoNullable` --> $DIR/issue-38821.rs:9:18 @@ -303,7 +303,7 @@ error[E0277]: the trait bound `<Col as Expression>::SqlType: NotNull` is not sat --> $DIR/issue-38821.rs:23:23 | LL | #[derive(Debug, Copy, Clone)] - | ^^^^^ the trait `NotNull` is not implemented for `<Col as Expression>::SqlType`, which is required by `<Col as Expression>::SqlType: IntoNullable` + | ^^^^^ the trait `NotNull` is not implemented for `<Col as Expression>::SqlType` | note: required for `<Col as Expression>::SqlType` to implement `IntoNullable` --> $DIR/issue-38821.rs:9:18 diff --git a/tests/ui/associated-types/issue-43784-associated-type.stderr b/tests/ui/associated-types/issue-43784-associated-type.stderr index b2cbe8ee86e..529fc1f119a 100644 --- a/tests/ui/associated-types/issue-43784-associated-type.stderr +++ b/tests/ui/associated-types/issue-43784-associated-type.stderr @@ -2,7 +2,7 @@ error[E0277]: the trait bound `T: Copy` is not satisfied --> $DIR/issue-43784-associated-type.rs:14:18 | LL | type Assoc = T; - | ^ the trait `Copy` is not implemented for `T`, which is required by `<T as Complete>::Assoc: Partial<T>` + | ^ the trait `Copy` is not implemented for `T` | note: required for `<T as Complete>::Assoc` to implement `Partial<T>` --> $DIR/issue-43784-associated-type.rs:1:11 diff --git a/tests/ui/associated-types/issue-65774-1.stderr b/tests/ui/associated-types/issue-65774-1.stderr index 9748a8fbbf4..9c77a25c432 100644 --- a/tests/ui/associated-types/issue-65774-1.stderr +++ b/tests/ui/associated-types/issue-65774-1.stderr @@ -15,7 +15,7 @@ error[E0277]: the trait bound `T: MyDisplay` is not satisfied --> $DIR/issue-65774-1.rs:44:76 | LL | let closure = |config: &mut <S as MPU>::MpuConfig| writer.my_write(&config); - | ^^^^^^^ the trait `MyDisplay` is not implemented for `T`, which is required by `&mut T: MyDisplay` + | ^^^^^^^ the trait `MyDisplay` is not implemented for `T` | = help: the trait `MyDisplay` is implemented for `&'a mut T` note: required for `&mut T` to implement `MyDisplay` diff --git a/tests/ui/associated-types/substs-ppaux.normal.stderr b/tests/ui/associated-types/substs-ppaux.normal.stderr index 8d3146be560..1ea8ab23556 100644 --- a/tests/ui/associated-types/substs-ppaux.normal.stderr +++ b/tests/ui/associated-types/substs-ppaux.normal.stderr @@ -80,7 +80,7 @@ error[E0277]: the trait bound `str: Foo<'_, '_, u8>` is not satisfied --> $DIR/substs-ppaux.rs:55:6 | LL | <str as Foo<u8>>::bar; - | ^^^ the trait `Sized` is not implemented for `str`, which is required by `str: Foo<'_, '_, u8>` + | ^^^ the trait `Sized` is not implemented for `str` | note: required for `str` to implement `Foo<'_, '_, u8>` --> $DIR/substs-ppaux.rs:15:20 diff --git a/tests/ui/associated-types/substs-ppaux.verbose.stderr b/tests/ui/associated-types/substs-ppaux.verbose.stderr index 0b5f449e576..05cd971c882 100644 --- a/tests/ui/associated-types/substs-ppaux.verbose.stderr +++ b/tests/ui/associated-types/substs-ppaux.verbose.stderr @@ -80,7 +80,7 @@ error[E0277]: the trait bound `str: Foo<'?0, '?1, u8>` is not satisfied --> $DIR/substs-ppaux.rs:55:6 | LL | <str as Foo<u8>>::bar; - | ^^^ the trait `Sized` is not implemented for `str`, which is required by `str: Foo<'?0, '?1, u8>` + | ^^^ the trait `Sized` is not implemented for `str` | note: required for `str` to implement `Foo<'?0, '?1, u8>` --> $DIR/substs-ppaux.rs:15:20 diff --git a/tests/ui/async-await/async-await-let-else.stderr b/tests/ui/async-await/async-await-let-else.stderr index 0952be2abe5..5883f34f87d 100644 --- a/tests/ui/async-await/async-await-let-else.stderr +++ b/tests/ui/async-await/async-await-let-else.stderr @@ -4,7 +4,7 @@ error: future cannot be sent between threads safely LL | is_send(foo(Some(true))); | ^^^^^^^^^^^^^^^ future returned by `foo` is not `Send` | - = help: within `impl Future<Output = ()>`, the trait `Send` is not implemented for `Rc<()>`, which is required by `impl Future<Output = ()>: Send` + = help: within `impl Future<Output = ()>`, the trait `Send` is not implemented for `Rc<()>` note: future is not `Send` as this value is used across an await --> $DIR/async-await-let-else.rs:8:15 | @@ -29,7 +29,7 @@ LL | is_send(foo2(Some(true))); | | | required by a bound introduced by this call | - = help: within `impl Future<Output = ()>`, the trait `Send` is not implemented for `Rc<()>`, which is required by `impl Future<Output = ()>: Send` + = help: within `impl Future<Output = ()>`, the trait `Send` is not implemented for `Rc<()>` note: required because it's used within this `async` fn body --> $DIR/async-await-let-else.rs:24:29 | @@ -60,7 +60,7 @@ error: future cannot be sent between threads safely LL | is_send(foo3(Some(true))); | ^^^^^^^^^^^^^^^^ future returned by `foo3` is not `Send` | - = help: within `impl Future<Output = ()>`, the trait `Send` is not implemented for `Rc<()>`, which is required by `impl Future<Output = ()>: Send` + = help: within `impl Future<Output = ()>`, the trait `Send` is not implemented for `Rc<()>` note: future is not `Send` as this value is used across an await --> $DIR/async-await-let-else.rs:30:29 | @@ -80,7 +80,7 @@ error: future cannot be sent between threads safely LL | is_send(foo4(Some(true))); | ^^^^^^^^^^^^^^^^ future returned by `foo4` is not `Send` | - = help: within `impl Future<Output = ()>`, the trait `Send` is not implemented for `Rc<()>`, which is required by `impl Future<Output = ()>: Send` + = help: within `impl Future<Output = ()>`, the trait `Send` is not implemented for `Rc<()>` note: future is not `Send` as this value is used across an await --> $DIR/async-await-let-else.rs:38:15 | diff --git a/tests/ui/async-await/async-closures/not-clone-closure.stderr b/tests/ui/async-await/async-closures/not-clone-closure.stderr index aea48a455c2..8d5612687db 100644 --- a/tests/ui/async-await/async-closures/not-clone-closure.stderr +++ b/tests/ui/async-await/async-closures/not-clone-closure.stderr @@ -2,7 +2,7 @@ error[E0277]: the trait bound `NotClonableUpvar: Clone` is not satisfied in `{as --> $DIR/not-clone-closure.rs:32:15 | LL | not_clone.clone(); - | ^^^^^ within `{async closure@$DIR/not-clone-closure.rs:29:21: 29:34}`, the trait `Clone` is not implemented for `NotClonableUpvar`, which is required by `{async closure@$DIR/not-clone-closure.rs:29:21: 29:34}: Clone` + | ^^^^^ within `{async closure@$DIR/not-clone-closure.rs:29:21: 29:34}`, the trait `Clone` is not implemented for `NotClonableUpvar` | note: required because it's used within this closure --> $DIR/not-clone-closure.rs:29:21 diff --git a/tests/ui/async-await/async-fn-nonsend.stderr b/tests/ui/async-await/async-fn-nonsend.stderr index 8b245281da9..0ced6c36f47 100644 --- a/tests/ui/async-await/async-fn-nonsend.stderr +++ b/tests/ui/async-await/async-fn-nonsend.stderr @@ -4,7 +4,7 @@ error: future cannot be sent between threads safely LL | assert_send(non_send_temporary_in_match()); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ future returned by `non_send_temporary_in_match` is not `Send` | - = help: within `impl Future<Output = ()>`, the trait `Send` is not implemented for `Rc<()>`, which is required by `impl Future<Output = ()>: Send` + = help: within `impl Future<Output = ()>`, the trait `Send` is not implemented for `Rc<()>` note: future is not `Send` as this value is used across an await --> $DIR/async-fn-nonsend.rs:33:26 | @@ -24,7 +24,7 @@ error: future cannot be sent between threads safely LL | assert_send(non_sync_with_method_call()); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^ future returned by `non_sync_with_method_call` is not `Send` | - = help: within `impl Future<Output = ()>`, the trait `Send` is not implemented for `dyn std::fmt::Write`, which is required by `impl Future<Output = ()>: Send` + = help: within `impl Future<Output = ()>`, the trait `Send` is not implemented for `dyn std::fmt::Write` note: future is not `Send` as this value is used across an await --> $DIR/async-fn-nonsend.rs:46:15 | diff --git a/tests/ui/async-await/async-is-unwindsafe.stderr b/tests/ui/async-await/async-is-unwindsafe.stderr index 9c5e8f0252c..9323ce25b77 100644 --- a/tests/ui/async-await/async-is-unwindsafe.stderr +++ b/tests/ui/async-await/async-is-unwindsafe.stderr @@ -13,7 +13,7 @@ LL | | drop(cx_ref); LL | | }); | |______^ `&mut Context<'_>` may not be safely transferred across an unwind boundary | - = help: within `{async block@$DIR/async-is-unwindsafe.rs:12:19: 12:24}`, the trait `UnwindSafe` is not implemented for `&mut Context<'_>`, which is required by `{async block@$DIR/async-is-unwindsafe.rs:12:19: 12:24}: UnwindSafe` + = help: within `{async block@$DIR/async-is-unwindsafe.rs:12:19: 12:24}`, the trait `UnwindSafe` is not implemented for `&mut Context<'_>` = note: `UnwindSafe` is implemented for `&Context<'_>`, but not for `&mut Context<'_>` note: future does not implement `UnwindSafe` as this value is used across an await --> $DIR/async-is-unwindsafe.rs:25:18 diff --git a/tests/ui/async-await/debug-ice-attempted-to-add-with-overflow.stderr b/tests/ui/async-await/debug-ice-attempted-to-add-with-overflow.stderr index eab5bea681c..8c9d06c79ca 100644 --- a/tests/ui/async-await/debug-ice-attempted-to-add-with-overflow.stderr +++ b/tests/ui/async-await/debug-ice-attempted-to-add-with-overflow.stderr @@ -7,7 +7,7 @@ LL | [0usize; 0xffff_ffff_ffff_ffff].await; | |`[usize; usize::MAX]` is not a future | help: remove the `.await` | - = help: the trait `Future` is not implemented for `[usize; usize::MAX]`, which is required by `[usize; usize::MAX]: IntoFuture` + = help: the trait `Future` is not implemented for `[usize; usize::MAX]` = note: [usize; usize::MAX] must be a future or must implement `IntoFuture` to be awaited = note: required for `[usize; usize::MAX]` to implement `IntoFuture` diff --git a/tests/ui/async-await/drop-track-bad-field-in-fru.stderr b/tests/ui/async-await/drop-track-bad-field-in-fru.stderr index 53cdc9b61d3..721e0106293 100644 --- a/tests/ui/async-await/drop-track-bad-field-in-fru.stderr +++ b/tests/ui/async-await/drop-track-bad-field-in-fru.stderr @@ -15,7 +15,7 @@ LL | None { value: (), ..Default::default() }.await; | |`Option<_>` is not a future | help: remove the `.await` | - = help: the trait `Future` is not implemented for `Option<_>`, which is required by `Option<_>: IntoFuture` + = help: the trait `Future` is not implemented for `Option<_>` = note: Option<_> must be a future or must implement `IntoFuture` to be awaited = note: required for `Option<_>` to implement `IntoFuture` diff --git a/tests/ui/async-await/drop-track-field-assign-nonsend.stderr b/tests/ui/async-await/drop-track-field-assign-nonsend.stderr index ce2cee6ed47..9fce4d61b3b 100644 --- a/tests/ui/async-await/drop-track-field-assign-nonsend.stderr +++ b/tests/ui/async-await/drop-track-field-assign-nonsend.stderr @@ -4,7 +4,7 @@ error: future cannot be sent between threads safely LL | assert_send(agent.handle()); | ^^^^^^^^^^^^^^ future returned by `handle` is not `Send` | - = help: within `impl Future<Output = ()>`, the trait `Send` is not implemented for `Rc<String>`, which is required by `impl Future<Output = ()>: Send` + = help: within `impl Future<Output = ()>`, the trait `Send` is not implemented for `Rc<String>` note: future is not `Send` as this value is used across an await --> $DIR/drop-track-field-assign-nonsend.rs:20:39 | diff --git a/tests/ui/async-await/field-assign-nonsend.stderr b/tests/ui/async-await/field-assign-nonsend.stderr index 525a2cc78b4..418a0829c65 100644 --- a/tests/ui/async-await/field-assign-nonsend.stderr +++ b/tests/ui/async-await/field-assign-nonsend.stderr @@ -4,7 +4,7 @@ error: future cannot be sent between threads safely LL | assert_send(agent.handle()); | ^^^^^^^^^^^^^^ future returned by `handle` is not `Send` | - = help: within `impl Future<Output = ()>`, the trait `Send` is not implemented for `Rc<String>`, which is required by `impl Future<Output = ()>: Send` + = help: within `impl Future<Output = ()>`, the trait `Send` is not implemented for `Rc<String>` note: future is not `Send` as this value is used across an await --> $DIR/field-assign-nonsend.rs:20:39 | diff --git a/tests/ui/async-await/in-trait/missing-send-bound.stderr b/tests/ui/async-await/in-trait/missing-send-bound.stderr index 93f37a9a8e9..aeabb5931df 100644 --- a/tests/ui/async-await/in-trait/missing-send-bound.stderr +++ b/tests/ui/async-await/in-trait/missing-send-bound.stderr @@ -4,7 +4,7 @@ error: future cannot be sent between threads safely LL | assert_is_send(test::<T>()); | ^^^^^^^^^^^ future returned by `test` is not `Send` | - = help: within `impl Future<Output = ()>`, the trait `Send` is not implemented for `impl Future<Output = ()>`, which is required by `impl Future<Output = ()>: Send` + = help: within `impl Future<Output = ()>`, the trait `Send` is not implemented for `impl Future<Output = ()>` note: future is not `Send` as it awaits another future which is not `Send` --> $DIR/missing-send-bound.rs:9:5 | diff --git a/tests/ui/async-await/issue-101715.stderr b/tests/ui/async-await/issue-101715.stderr index 3b429793b78..f6af15c00d6 100644 --- a/tests/ui/async-await/issue-101715.stderr +++ b/tests/ui/async-await/issue-101715.stderr @@ -7,7 +7,7 @@ LL | .await | |`()` is not a future | help: remove the `.await` | - = help: the trait `Future` is not implemented for `()`, which is required by `(): IntoFuture` + = help: the trait `Future` is not implemented for `()` = note: () must be a future or must implement `IntoFuture` to be awaited = note: required for `()` to implement `IntoFuture` diff --git a/tests/ui/async-await/issue-64130-1-sync.stderr b/tests/ui/async-await/issue-64130-1-sync.stderr index 15f49124f6f..5428d7ef71b 100644 --- a/tests/ui/async-await/issue-64130-1-sync.stderr +++ b/tests/ui/async-await/issue-64130-1-sync.stderr @@ -4,7 +4,7 @@ error: future cannot be shared between threads safely LL | is_sync(bar()); | ^^^^^ future returned by `bar` is not `Sync` | - = help: within `impl Future<Output = ()>`, the trait `Sync` is not implemented for `Foo`, which is required by `impl Future<Output = ()>: Sync` + = help: within `impl Future<Output = ()>`, the trait `Sync` is not implemented for `Foo` note: future is not `Sync` as this value is used across an await --> $DIR/issue-64130-1-sync.rs:15:11 | diff --git a/tests/ui/async-await/issue-64130-2-send.stderr b/tests/ui/async-await/issue-64130-2-send.stderr index 67368314b1b..f05e954d2d7 100644 --- a/tests/ui/async-await/issue-64130-2-send.stderr +++ b/tests/ui/async-await/issue-64130-2-send.stderr @@ -4,7 +4,7 @@ error: future cannot be sent between threads safely LL | is_send(bar()); | ^^^^^ future returned by `bar` is not `Send` | - = help: within `impl Future<Output = ()>`, the trait `Send` is not implemented for `Foo`, which is required by `impl Future<Output = ()>: Send` + = help: within `impl Future<Output = ()>`, the trait `Send` is not implemented for `Foo` note: future is not `Send` as this value is used across an await --> $DIR/issue-64130-2-send.rs:15:11 | diff --git a/tests/ui/async-await/issue-64130-3-other.stderr b/tests/ui/async-await/issue-64130-3-other.stderr index e3a73920c92..3ac30bdc23e 100644 --- a/tests/ui/async-await/issue-64130-3-other.stderr +++ b/tests/ui/async-await/issue-64130-3-other.stderr @@ -5,7 +5,7 @@ LL | async fn bar() { | -------------- within this `impl Future<Output = ()>` ... LL | is_qux(bar()); - | ^^^^^ within `impl Future<Output = ()>`, the trait `Qux` is not implemented for `Foo`, which is required by `impl Future<Output = ()>: Qux` + | ^^^^^ within `impl Future<Output = ()>`, the trait `Qux` is not implemented for `Foo` | note: future does not implement `Qux` as this value is used across an await --> $DIR/issue-64130-3-other.rs:18:11 diff --git a/tests/ui/async-await/issue-64130-non-send-future-diags.stderr b/tests/ui/async-await/issue-64130-non-send-future-diags.stderr index bd890c83817..d28807e223b 100644 --- a/tests/ui/async-await/issue-64130-non-send-future-diags.stderr +++ b/tests/ui/async-await/issue-64130-non-send-future-diags.stderr @@ -4,7 +4,7 @@ error: future cannot be sent between threads safely LL | is_send(foo()); | ^^^^^ future returned by `foo` is not `Send` | - = help: within `impl Future<Output = ()>`, the trait `Send` is not implemented for `MutexGuard<'_, u32>`, which is required by `impl Future<Output = ()>: Send` + = help: within `impl Future<Output = ()>`, the trait `Send` is not implemented for `MutexGuard<'_, u32>` note: future is not `Send` as this value is used across an await --> $DIR/issue-64130-non-send-future-diags.rs:17:11 | diff --git a/tests/ui/async-await/issue-67252-unnamed-future.stderr b/tests/ui/async-await/issue-67252-unnamed-future.stderr index 2ed40284702..4ec6779dda8 100644 --- a/tests/ui/async-await/issue-67252-unnamed-future.stderr +++ b/tests/ui/async-await/issue-67252-unnamed-future.stderr @@ -8,7 +8,7 @@ LL | | let _a = a; LL | | }); | |______^ future created by async block is not `Send` | - = help: within `{async block@$DIR/issue-67252-unnamed-future.rs:18:11: 18:16}`, the trait `Send` is not implemented for `*mut ()`, which is required by `{async block@$DIR/issue-67252-unnamed-future.rs:18:11: 18:16}: Send` + = help: within `{async block@$DIR/issue-67252-unnamed-future.rs:18:11: 18:16}`, the trait `Send` is not implemented for `*mut ()` note: future is not `Send` as this value is used across an await --> $DIR/issue-67252-unnamed-future.rs:20:17 | diff --git a/tests/ui/async-await/issue-68112.stderr b/tests/ui/async-await/issue-68112.stderr index ca60079f3ef..f8889ebcca1 100644 --- a/tests/ui/async-await/issue-68112.stderr +++ b/tests/ui/async-await/issue-68112.stderr @@ -4,7 +4,7 @@ error: future cannot be sent between threads safely LL | require_send(send_fut); | ^^^^^^^^^^^^^^^^^^^^^^ future created by async block is not `Send` | - = help: the trait `Sync` is not implemented for `RefCell<i32>`, which is required by `{async block@$DIR/issue-68112.rs:29:20: 29:25}: Send` + = help: the trait `Sync` is not implemented for `RefCell<i32>` = note: if you want to do aliasing and mutation between multiple threads, use `std::sync::RwLock` instead note: future is not `Send` as it awaits another future which is not `Send` --> $DIR/issue-68112.rs:31:17 @@ -23,7 +23,7 @@ error: future cannot be sent between threads safely LL | require_send(send_fut); | ^^^^^^^^^^^^^^^^^^^^^^ future created by async block is not `Send` | - = help: the trait `Sync` is not implemented for `RefCell<i32>`, which is required by `{async block@$DIR/issue-68112.rs:39:20: 39:25}: Send` + = help: the trait `Sync` is not implemented for `RefCell<i32>` = note: if you want to do aliasing and mutation between multiple threads, use `std::sync::RwLock` instead note: future is not `Send` as it awaits another future which is not `Send` --> $DIR/issue-68112.rs:40:17 @@ -42,7 +42,7 @@ error[E0277]: `RefCell<i32>` cannot be shared between threads safely LL | require_send(send_fut); | ^^^^^^^^^^^^^^^^^^^^^^ `RefCell<i32>` cannot be shared between threads safely | - = help: the trait `Sync` is not implemented for `RefCell<i32>`, which is required by `{async block@$DIR/issue-68112.rs:57:20: 57:25}: Send` + = help: the trait `Sync` is not implemented for `RefCell<i32>` = note: if you want to do aliasing and mutation between multiple threads, use `std::sync::RwLock` instead = note: required for `Arc<RefCell<i32>>` to implement `Send` note: required because it's used within this `async` fn body diff --git a/tests/ui/async-await/issue-70935-complex-spans.stderr b/tests/ui/async-await/issue-70935-complex-spans.stderr index 1ca0b339c16..c6b7e21b9dd 100644 --- a/tests/ui/async-await/issue-70935-complex-spans.stderr +++ b/tests/ui/async-await/issue-70935-complex-spans.stderr @@ -4,7 +4,7 @@ error[E0277]: `*mut ()` cannot be shared between threads safely LL | fn foo(x: NotSync) -> impl Future + Send { | ^^^^^^^^^^^^^^^^^^ `*mut ()` cannot be shared between threads safely | - = help: within `NotSync`, the trait `Sync` is not implemented for `*mut ()`, which is required by `{async block@$DIR/issue-70935-complex-spans.rs:18:5: 18:15}: Send` + = help: within `NotSync`, the trait `Sync` is not implemented for `*mut ()` note: required because it appears within the type `PhantomData<*mut ()>` --> $SRC_DIR/core/src/marker.rs:LL:COL note: required because it appears within the type `NotSync` @@ -37,7 +37,7 @@ error[E0277]: `*mut ()` cannot be shared between threads safely LL | fn foo(x: NotSync) -> impl Future + Send { | ^^^^^^^^^^^^^^^^^^ `*mut ()` cannot be shared between threads safely | - = help: within `NotSync`, the trait `Sync` is not implemented for `*mut ()`, which is required by `{async block@$DIR/issue-70935-complex-spans.rs:18:5: 18:15}: Send` + = help: within `NotSync`, the trait `Sync` is not implemented for `*mut ()` note: required because it appears within the type `PhantomData<*mut ()>` --> $SRC_DIR/core/src/marker.rs:LL:COL note: required because it appears within the type `NotSync` diff --git a/tests/ui/async-await/issue-71137.stderr b/tests/ui/async-await/issue-71137.stderr index 75d72e425f5..8739c22a310 100644 --- a/tests/ui/async-await/issue-71137.stderr +++ b/tests/ui/async-await/issue-71137.stderr @@ -4,7 +4,7 @@ error: future cannot be sent between threads safely LL | fake_spawn(wrong_mutex()); | ^^^^^^^^^^^^^ future returned by `wrong_mutex` is not `Send` | - = help: within `impl Future<Output = ()>`, the trait `Send` is not implemented for `MutexGuard<'_, i32>`, which is required by `impl Future<Output = ()>: Send` + = help: within `impl Future<Output = ()>`, the trait `Send` is not implemented for `MutexGuard<'_, i32>` note: future is not `Send` as this value is used across an await --> $DIR/issue-71137.rs:14:26 | diff --git a/tests/ui/async-await/issue-72590-type-error-sized.stderr b/tests/ui/async-await/issue-72590-type-error-sized.stderr index 1b822234d80..778423578e1 100644 --- a/tests/ui/async-await/issue-72590-type-error-sized.stderr +++ b/tests/ui/async-await/issue-72590-type-error-sized.stderr @@ -16,7 +16,7 @@ error[E0277]: the size for values of type `str` cannot be known at compilation t LL | async fn frob(self) {} | ^^^^ doesn't have a size known at compile-time | - = help: within `Foo`, the trait `Sized` is not implemented for `str`, which is required by `Foo: Sized` + = help: within `Foo`, the trait `Sized` is not implemented for `str` note: required because it appears within the type `Foo` --> $DIR/issue-72590-type-error-sized.rs:5:8 | diff --git a/tests/ui/async-await/issues/issue-67893.stderr b/tests/ui/async-await/issues/issue-67893.stderr index 0c28aea44bb..c01237255b8 100644 --- a/tests/ui/async-await/issues/issue-67893.stderr +++ b/tests/ui/async-await/issues/issue-67893.stderr @@ -11,7 +11,7 @@ LL | g(issue_67893::run()) LL | pub async fn run() { | ------------------ within this `impl Future<Output = ()>` | - = help: within `impl Future<Output = ()>`, the trait `Send` is not implemented for `MutexGuard<'_, ()>`, which is required by `impl Future<Output = ()>: Send` + = help: within `impl Future<Output = ()>`, the trait `Send` is not implemented for `MutexGuard<'_, ()>` note: required because it's used within this `async` fn body --> $DIR/auxiliary/issue_67893.rs:9:20 | diff --git a/tests/ui/async-await/partial-drop-partial-reinit.stderr b/tests/ui/async-await/partial-drop-partial-reinit.stderr index 0bd7d50b941..042ed18984e 100644 --- a/tests/ui/async-await/partial-drop-partial-reinit.stderr +++ b/tests/ui/async-await/partial-drop-partial-reinit.stderr @@ -9,7 +9,7 @@ LL | gimme_send(foo()); LL | async fn foo() { | -------------- within this `impl Future<Output = ()>` | - = help: within `impl Future<Output = ()>`, the trait `Send` is not implemented for `NotSend`, which is required by `impl Future<Output = ()>: Send` + = help: within `impl Future<Output = ()>`, the trait `Send` is not implemented for `NotSend` = note: required because it appears within the type `(NotSend,)` note: required because it's used within this `async` fn body --> $DIR/partial-drop-partial-reinit.rs:27:16 diff --git a/tests/ui/async-await/pin-needed-to-poll-2.stderr b/tests/ui/async-await/pin-needed-to-poll-2.stderr index e22baabc25b..8eb671531e7 100644 --- a/tests/ui/async-await/pin-needed-to-poll-2.stderr +++ b/tests/ui/async-await/pin-needed-to-poll-2.stderr @@ -2,7 +2,7 @@ error[E0277]: `PhantomPinned` cannot be unpinned --> $DIR/pin-needed-to-poll-2.rs:43:18 | LL | Pin::new(&mut self.sleep).poll(cx) - | -------- ^^^^^^^^^^^^^^^ within `Sleep`, the trait `Unpin` is not implemented for `PhantomPinned`, which is required by `Sleep: Unpin` + | -------- ^^^^^^^^^^^^^^^ within `Sleep`, the trait `Unpin` is not implemented for `PhantomPinned` | | | required by a bound introduced by this call | diff --git a/tests/ui/async-await/unnecessary-await.stderr b/tests/ui/async-await/unnecessary-await.stderr index 8d819576532..620370a6113 100644 --- a/tests/ui/async-await/unnecessary-await.stderr +++ b/tests/ui/async-await/unnecessary-await.stderr @@ -6,7 +6,7 @@ LL | boo().await; | | | this call returns `()` | - = help: the trait `Future` is not implemented for `()`, which is required by `(): IntoFuture` + = help: the trait `Future` is not implemented for `()` = note: () must be a future or must implement `IntoFuture` to be awaited = note: required for `()` to implement `IntoFuture` help: remove the `.await` @@ -28,7 +28,7 @@ LL | e!().await; | |`()` is not a future | help: remove the `.await` | - = help: the trait `Future` is not implemented for `()`, which is required by `(): IntoFuture` + = help: the trait `Future` is not implemented for `()` = note: () must be a future or must implement `IntoFuture` to be awaited = note: required for `()` to implement `IntoFuture` @@ -44,7 +44,7 @@ LL | $expr.await LL | f!(()); | ------ in this macro invocation | - = help: the trait `Future` is not implemented for `()`, which is required by `(): IntoFuture` + = help: the trait `Future` is not implemented for `()` = note: () must be a future or must implement `IntoFuture` to be awaited = note: required for `()` to implement `IntoFuture` = note: this error originates in the macro `f` (in Nightly builds, run with -Z macro-backtrace for more info) @@ -58,7 +58,7 @@ LL | for x in [] {}.await | |`()` is not a future | help: remove the `.await` | - = help: the trait `Future` is not implemented for `()`, which is required by `(): IntoFuture` + = help: the trait `Future` is not implemented for `()` = note: () must be a future or must implement `IntoFuture` to be awaited = note: required for `()` to implement `IntoFuture` diff --git a/tests/ui/auto-traits/issue-83857-ub.stderr b/tests/ui/auto-traits/issue-83857-ub.stderr index 20bfe7e36ca..7c437b7e6c8 100644 --- a/tests/ui/auto-traits/issue-83857-ub.stderr +++ b/tests/ui/auto-traits/issue-83857-ub.stderr @@ -4,7 +4,7 @@ error[E0277]: `Foo<T, U>` cannot be sent between threads safely LL | fn generic<T, U>(v: Foo<T, U>, f: fn(<Foo<T, U> as WithAssoc>::Output) -> i32) { | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ `Foo<T, U>` cannot be sent between threads safely | - = help: the trait `Send` is not implemented for `Foo<T, U>`, which is required by `Foo<T, U>: WithAssoc` + = help: the trait `Send` is not implemented for `Foo<T, U>` note: required for `Foo<T, U>` to implement `WithAssoc` --> $DIR/issue-83857-ub.rs:14:15 | @@ -29,7 +29,7 @@ LL | | LL | | } | |_^ `Foo<T, U>` cannot be sent between threads safely | - = help: the trait `Send` is not implemented for `Foo<T, U>`, which is required by `Foo<T, U>: WithAssoc` + = help: the trait `Send` is not implemented for `Foo<T, U>` note: required for `Foo<T, U>` to implement `WithAssoc` --> $DIR/issue-83857-ub.rs:14:15 | diff --git a/tests/ui/auto-traits/str-contains-slice-conceptually.stderr b/tests/ui/auto-traits/str-contains-slice-conceptually.stderr index ebd3a556e75..e1dae35be00 100644 --- a/tests/ui/auto-traits/str-contains-slice-conceptually.stderr +++ b/tests/ui/auto-traits/str-contains-slice-conceptually.stderr @@ -2,7 +2,7 @@ error[E0277]: the trait bound `[u8]: AutoTrait` is not satisfied in `str` --> $DIR/str-contains-slice-conceptually.rs:11:22 | LL | needs_auto_trait::<str>(); - | ^^^ within `str`, the trait `AutoTrait` is not implemented for `[u8]`, which is required by `str: AutoTrait` + | ^^^ within `str`, the trait `AutoTrait` is not implemented for `[u8]` | = note: `str` is considered to contain a `[u8]` slice for auto trait purposes note: required by a bound in `needs_auto_trait` diff --git a/tests/ui/auto-traits/typeck-default-trait-impl-constituent-types-2.stderr b/tests/ui/auto-traits/typeck-default-trait-impl-constituent-types-2.stderr index b7c97389912..aa5585a5371 100644 --- a/tests/ui/auto-traits/typeck-default-trait-impl-constituent-types-2.stderr +++ b/tests/ui/auto-traits/typeck-default-trait-impl-constituent-types-2.stderr @@ -2,7 +2,7 @@ error[E0277]: the trait bound `MyS2: MyTrait` is not satisfied in `(MyS2, MyS)` --> $DIR/typeck-default-trait-impl-constituent-types-2.rs:17:18 | LL | is_mytrait::<(MyS2, MyS)>(); - | ^^^^^^^^^^^ within `(MyS2, MyS)`, the trait `MyTrait` is not implemented for `MyS2`, which is required by `(MyS2, MyS): MyTrait` + | ^^^^^^^^^^^ within `(MyS2, MyS)`, the trait `MyTrait` is not implemented for `MyS2` | = note: required because it appears within the type `(MyS2, MyS)` note: required by a bound in `is_mytrait` diff --git a/tests/ui/auto-traits/typeck-default-trait-impl-precedence.stderr b/tests/ui/auto-traits/typeck-default-trait-impl-precedence.stderr index 4773ac4ccf7..fca01b3f48d 100644 --- a/tests/ui/auto-traits/typeck-default-trait-impl-precedence.stderr +++ b/tests/ui/auto-traits/typeck-default-trait-impl-precedence.stderr @@ -2,7 +2,7 @@ error[E0277]: the trait bound `&'static u32: Defaulted` is not satisfied --> $DIR/typeck-default-trait-impl-precedence.rs:19:20 | LL | is_defaulted::<&'static u32>(); - | ^^^^^^^^^^^^ the trait `Signed` is not implemented for `u32`, which is required by `&'static u32: Defaulted` + | ^^^^^^^^^^^^ the trait `Signed` is not implemented for `u32` | note: required for `&'static u32` to implement `Defaulted` --> $DIR/typeck-default-trait-impl-precedence.rs:10:19 diff --git a/tests/ui/binop/binary-op-suggest-deref.stderr b/tests/ui/binop/binary-op-suggest-deref.stderr index 01852fbc633..440625d8ccb 100644 --- a/tests/ui/binop/binary-op-suggest-deref.stderr +++ b/tests/ui/binop/binary-op-suggest-deref.stderr @@ -27,7 +27,7 @@ error[E0277]: can't compare `&{integer}` with `{integer}` LL | _ = foo == &0; | ^^ no implementation for `&{integer} == {integer}` | - = help: the trait `PartialEq<{integer}>` is not implemented for `&{integer}`, which is required by `&&{integer}: PartialEq<&{integer}>` + = help: the trait `PartialEq<{integer}>` is not implemented for `&{integer}` = note: required for `&&{integer}` to implement `PartialEq<&{integer}>` help: consider dereferencing here | @@ -65,7 +65,7 @@ error[E0277]: can't compare `&&{integer}` with `{integer}` LL | _ = &&foo == &&0; | ^^ no implementation for `&&{integer} == {integer}` | - = help: the trait `PartialEq<{integer}>` is not implemented for `&&{integer}`, which is required by `&&&&{integer}: PartialEq<&&{integer}>` + = help: the trait `PartialEq<{integer}>` is not implemented for `&&{integer}` = note: required for `&&&{integer}` to implement `PartialEq<&{integer}>` = note: 1 redundant requirement hidden = note: required for `&&&&{integer}` to implement `PartialEq<&&{integer}>` @@ -119,7 +119,7 @@ error[E0277]: can't compare `{integer}` with `&{integer}` LL | _ = &0 == foo; | ^^ no implementation for `{integer} == &{integer}` | - = help: the trait `PartialEq<&{integer}>` is not implemented for `{integer}`, which is required by `&{integer}: PartialEq<&&{integer}>` + = help: the trait `PartialEq<&{integer}>` is not implemented for `{integer}` = note: required for `&{integer}` to implement `PartialEq<&&{integer}>` help: consider dereferencing here | @@ -157,7 +157,7 @@ error[E0277]: can't compare `{integer}` with `&&{integer}` LL | _ = &&0 == &&foo; | ^^ no implementation for `{integer} == &&{integer}` | - = help: the trait `PartialEq<&&{integer}>` is not implemented for `{integer}`, which is required by `&&{integer}: PartialEq<&&&&{integer}>` + = help: the trait `PartialEq<&&{integer}>` is not implemented for `{integer}` = note: required for `&{integer}` to implement `PartialEq<&&&{integer}>` = note: 1 redundant requirement hidden = note: required for `&&{integer}` to implement `PartialEq<&&&&{integer}>` @@ -173,7 +173,7 @@ error[E0277]: can't compare `Box<Box<{integer}>>` with `&&{integer}` LL | _ = &Box::new(Box::new(42)) == &foo; | ^^ no implementation for `Box<Box<{integer}>> == &&{integer}` | - = help: the trait `PartialEq<&&{integer}>` is not implemented for `Box<Box<{integer}>>`, which is required by `&Box<Box<{integer}>>: PartialEq<&&&{integer}>` + = help: the trait `PartialEq<&&{integer}>` is not implemented for `Box<Box<{integer}>>` = note: required for `&Box<Box<{integer}>>` to implement `PartialEq<&&&{integer}>` help: consider dereferencing both sides of the expression | @@ -187,7 +187,7 @@ error[E0277]: can't compare `Box<{integer}>` with `&&{integer}` LL | _ = &Box::new(42) == &foo; | ^^ no implementation for `Box<{integer}> == &&{integer}` | - = help: the trait `PartialEq<&&{integer}>` is not implemented for `Box<{integer}>`, which is required by `&Box<{integer}>: PartialEq<&&&{integer}>` + = help: the trait `PartialEq<&&{integer}>` is not implemented for `Box<{integer}>` = note: required for `&Box<{integer}>` to implement `PartialEq<&&&{integer}>` help: consider dereferencing both sides of the expression | @@ -201,7 +201,7 @@ error[E0277]: can't compare `Box<Box<Box<Box<{integer}>>>>` with `&&{integer}` LL | _ = &Box::new(Box::new(Box::new(Box::new(42)))) == &foo; | ^^ no implementation for `Box<Box<Box<Box<{integer}>>>> == &&{integer}` | - = help: the trait `PartialEq<&&{integer}>` is not implemented for `Box<Box<Box<Box<{integer}>>>>`, which is required by `&Box<Box<Box<Box<{integer}>>>>: PartialEq<&&&{integer}>` + = help: the trait `PartialEq<&&{integer}>` is not implemented for `Box<Box<Box<Box<{integer}>>>>` = note: required for `&Box<Box<Box<Box<{integer}>>>>` to implement `PartialEq<&&&{integer}>` help: consider dereferencing both sides of the expression | @@ -215,7 +215,7 @@ error[E0277]: can't compare `&&{integer}` with `Box<Box<Box<Box<{integer}>>>>` LL | _ = &foo == &Box::new(Box::new(Box::new(Box::new(42)))); | ^^ no implementation for `&&{integer} == Box<Box<Box<Box<{integer}>>>>` | - = help: the trait `PartialEq<Box<Box<Box<Box<{integer}>>>>>` is not implemented for `&&{integer}`, which is required by `&&&{integer}: PartialEq<&Box<Box<Box<Box<{integer}>>>>>` + = help: the trait `PartialEq<Box<Box<Box<Box<{integer}>>>>>` is not implemented for `&&{integer}` = note: required for `&&&{integer}` to implement `PartialEq<&Box<Box<Box<Box<{integer}>>>>>` help: consider dereferencing both sides of the expression | diff --git a/tests/ui/block-result/issue-22645.stderr b/tests/ui/block-result/issue-22645.stderr index 2a267ce792f..1064848f513 100644 --- a/tests/ui/block-result/issue-22645.stderr +++ b/tests/ui/block-result/issue-22645.stderr @@ -2,7 +2,7 @@ error[E0277]: the trait bound `{integer}: Scalar` is not satisfied --> $DIR/issue-22645.rs:15:5 | LL | b + 3 - | ^ the trait `Scalar` is not implemented for `{integer}`, which is required by `Bob: Add<_>` + | ^ the trait `Scalar` is not implemented for `{integer}` | = help: the trait `Scalar` is implemented for `f64` note: required for `Bob` to implement `Add<{integer}>` diff --git a/tests/ui/cast/unsized-union-ice.stderr b/tests/ui/cast/unsized-union-ice.stderr index 05f86457829..1c9450b8e18 100644 --- a/tests/ui/cast/unsized-union-ice.stderr +++ b/tests/ui/cast/unsized-union-ice.stderr @@ -4,7 +4,7 @@ error[E0277]: the size for values of type `[u8]` cannot be known at compilation LL | val: std::mem::ManuallyDrop<[u8]>, | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^ doesn't have a size known at compile-time | - = help: within `ManuallyDrop<[u8]>`, the trait `Sized` is not implemented for `[u8]`, which is required by `ManuallyDrop<[u8]>: Sized` + = help: within `ManuallyDrop<[u8]>`, the trait `Sized` is not implemented for `[u8]` note: required because it appears within the type `ManuallyDrop<[u8]>` --> $SRC_DIR/core/src/mem/manually_drop.rs:LL:COL = note: no field of a union may have a dynamically sized type diff --git a/tests/ui/check-cfg/mix.stderr b/tests/ui/check-cfg/mix.stderr index c21016e9290..7589551a87c 100644 --- a/tests/ui/check-cfg/mix.stderr +++ b/tests/ui/check-cfg/mix.stderr @@ -251,7 +251,7 @@ warning: unexpected `cfg` condition value: `zebra` LL | cfg!(target_feature = "zebra"); | ^^^^^^^^^^^^^^^^^^^^^^^^ | - = note: expected values for `target_feature` are: `10e60`, `2e3`, `3e3r1`, `3e3r2`, `3e3r3`, `3e7`, `7e10`, `a`, `aclass`, `adx`, `aes`, `altivec`, `alu32`, `amx-bf16`, `amx-complex`, `amx-fp16`, `amx-int8`, `amx-tile`, `atomics`, `avx`, `avx2`, `avx512bf16`, `avx512bitalg`, `avx512bw`, `avx512cd`, `avx512dq`, `avx512f`, `avx512fp16`, `avx512ifma`, `avx512vbmi`, `avx512vbmi2`, `avx512vl`, `avx512vnni`, `avx512vp2intersect`, and `avx512vpopcntdq` and 245 more + = note: expected values for `target_feature` are: `10e60`, `2e3`, `3e3r1`, `3e3r2`, `3e3r3`, `3e7`, `7e10`, `a`, `aclass`, `adx`, `aes`, `altivec`, `alu32`, `amx-bf16`, `amx-complex`, `amx-fp16`, `amx-int8`, `amx-tile`, `atomics`, `avx`, `avx2`, `avx512bf16`, `avx512bitalg`, `avx512bw`, `avx512cd`, `avx512dq`, `avx512f`, `avx512fp16`, `avx512ifma`, `avx512vbmi`, `avx512vbmi2`, `avx512vl`, `avx512vnni`, `avx512vp2intersect`, and `avx512vpopcntdq` and 246 more = note: see <https://doc.rust-lang.org/nightly/rustc/check-cfg.html> for more information about checking conditional configuration warning: 27 warnings emitted diff --git a/tests/ui/check-cfg/well-known-values.stderr b/tests/ui/check-cfg/well-known-values.stderr index da790bbd528..b0ca09a59ed 100644 --- a/tests/ui/check-cfg/well-known-values.stderr +++ b/tests/ui/check-cfg/well-known-values.stderr @@ -174,7 +174,7 @@ warning: unexpected `cfg` condition value: `_UNEXPECTED_VALUE` LL | target_feature = "_UNEXPECTED_VALUE", | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ | - = note: expected values for `target_feature` are: `10e60`, `2e3`, `3e3r1`, `3e3r2`, `3e3r3`, `3e7`, `7e10`, `a`, `aclass`, `adx`, `aes`, `altivec`, `alu32`, `amx-bf16`, `amx-complex`, `amx-fp16`, `amx-int8`, `amx-tile`, `atomics`, `avx`, `avx2`, `avx512bf16`, `avx512bitalg`, `avx512bw`, `avx512cd`, `avx512dq`, `avx512f`, `avx512fp16`, `avx512ifma`, `avx512vbmi`, `avx512vbmi2`, `avx512vl`, `avx512vnni`, `avx512vp2intersect`, `avx512vpopcntdq`, `avxifma`, `avxneconvert`, `avxvnni`, `avxvnniint16`, `avxvnniint8`, `backchain`, `bf16`, `bmi1`, `bmi2`, `bti`, `bulk-memory`, `c`, `cache`, `cmpxchg16b`, `crc`, `crt-static`, `cssc`, `d`, `d32`, `dit`, `doloop`, `dotprod`, `dpb`, `dpb2`, `dsp`, `dsp1e2`, `dspe60`, `e`, `e1`, `e2`, `ecv`, `edsp`, `elrw`, `ermsb`, `exception-handling`, `extended-const`, `f`, `f16c`, `f32mm`, `f64mm`, `faminmax`, `fcma`, `fdivdu`, `fhm`, `flagm`, `flagm2`, `float1e2`, `float1e3`, `float3e4`, `float7e60`, `floate1`, `fma`, `fp-armv8`, `fp16`, `fp64`, `fp8`, `fp8dot2`, `fp8dot4`, `fp8fma`, `fpuv2_df`, `fpuv2_sf`, `fpuv3_df`, `fpuv3_hf`, `fpuv3_hi`, `fpuv3_sf`, `frecipe`, `frintts`, `fxsr`, `gfni`, `hard-float`, `hard-float-abi`, `hard-tp`, `hbc`, `high-registers`, `hvx`, `hvx-length128b`, `hwdiv`, `i8mm`, `jsconv`, `lahfsahf`, `lasx`, `lbt`, `lor`, `lse`, `lse128`, `lse2`, `lsx`, `lut`, `lvz`, `lzcnt`, `m`, `mclass`, `mops`, `movbe`, `mp`, `mp1e2`, `msa`, `mte`, `multivalue`, `mutable-globals`, `neon`, `nontrapping-fptoint`, `nvic`, `paca`, `pacg`, `pan`, `partword-atomics`, `pclmulqdq`, `pmuv3`, `popcnt`, `power10-vector`, `power8-altivec`, `power8-vector`, `power9-altivec`, `power9-vector`, `prfchw`, `quadword-atomics`, `rand`, `ras`, `rclass`, `rcpc`, `rcpc2`, `rcpc3`, `rdm`, `rdrand`, `rdseed`, `reference-types`, `relax`, `relaxed-simd`, `rtm`, `sb`, `sha`, `sha2`, `sha3`, `sha512`, `sign-ext`, `simd128`, `sm3`, `sm4`, `sme`, `sme-b16b16`, `sme-f16f16`, `sme-f64f64`, `sme-f8f16`, `sme-f8f32`, `sme-fa64`, `sme-i16i64`, `sme-lutv2`, `sme2`, `sme2p1`, `spe`, `ssbs`, `sse`, `sse2`, `sse3`, `sse4.1`, `sse4.2`, `sse4a`, `ssse3`, `ssve-fp8dot2`, `ssve-fp8dot4`, `ssve-fp8fma`, `sve`, `sve-b16b16`, `sve2`, `sve2-aes`, `sve2-bitperm`, `sve2-sha3`, `sve2-sm4`, `sve2p1`, `tbm`, `thumb-mode`, `thumb2`, `tme`, `trust`, `trustzone`, `ual`, `unaligned-scalar-mem`, `v`, `v5te`, `v6`, `v6k`, `v6t2`, `v7`, `v8`, `v8.1a`, `v8.2a`, `v8.3a`, `v8.4a`, `v8.5a`, `v8.6a`, `v8.7a`, `v8.8a`, `v8.9a`, `v9.1a`, `v9.2a`, `v9.3a`, `v9.4a`, `v9.5a`, `v9a`, `vaes`, `vdsp2e60f`, `vdspv1`, `vdspv2`, `vector`, `vfp2`, `vfp3`, `vfp4`, `vh`, `virt`, `virtualization`, `vpclmulqdq`, `vsx`, `wfxt`, `xop`, `xsave`, `xsavec`, `xsaveopt`, `xsaves`, `zaamo`, `zabha`, `zalrsc`, `zba`, `zbb`, `zbc`, `zbkb`, `zbkc`, `zbkx`, `zbs`, `zdinx`, `zfh`, `zfhmin`, `zfinx`, `zhinx`, `zhinxmin`, `zk`, `zkn`, `zknd`, `zkne`, `zknh`, `zkr`, `zks`, `zksed`, `zksh`, and `zkt` + = note: expected values for `target_feature` are: `10e60`, `2e3`, `3e3r1`, `3e3r2`, `3e3r3`, `3e7`, `7e10`, `a`, `aclass`, `adx`, `aes`, `altivec`, `alu32`, `amx-bf16`, `amx-complex`, `amx-fp16`, `amx-int8`, `amx-tile`, `atomics`, `avx`, `avx2`, `avx512bf16`, `avx512bitalg`, `avx512bw`, `avx512cd`, `avx512dq`, `avx512f`, `avx512fp16`, `avx512ifma`, `avx512vbmi`, `avx512vbmi2`, `avx512vl`, `avx512vnni`, `avx512vp2intersect`, `avx512vpopcntdq`, `avxifma`, `avxneconvert`, `avxvnni`, `avxvnniint16`, `avxvnniint8`, `backchain`, `bf16`, `bmi1`, `bmi2`, `bti`, `bulk-memory`, `c`, `cache`, `cmpxchg16b`, `crc`, `crt-static`, `cssc`, `d`, `d32`, `dit`, `doloop`, `dotprod`, `dpb`, `dpb2`, `dsp`, `dsp1e2`, `dspe60`, `e`, `e1`, `e2`, `ecv`, `edsp`, `elrw`, `ermsb`, `exception-handling`, `extended-const`, `f`, `f16c`, `f32mm`, `f64mm`, `faminmax`, `fcma`, `fdivdu`, `fhm`, `flagm`, `flagm2`, `float1e2`, `float1e3`, `float3e4`, `float7e60`, `floate1`, `fma`, `fp-armv8`, `fp16`, `fp64`, `fp8`, `fp8dot2`, `fp8dot4`, `fp8fma`, `fpuv2_df`, `fpuv2_sf`, `fpuv3_df`, `fpuv3_hf`, `fpuv3_hi`, `fpuv3_sf`, `frecipe`, `frintts`, `fxsr`, `gfni`, `hard-float`, `hard-float-abi`, `hard-tp`, `hbc`, `high-registers`, `hvx`, `hvx-length128b`, `hwdiv`, `i8mm`, `jsconv`, `lahfsahf`, `lasx`, `lbt`, `lor`, `lse`, `lse128`, `lse2`, `lsx`, `lut`, `lvz`, `lzcnt`, `m`, `mclass`, `mops`, `movbe`, `mp`, `mp1e2`, `msa`, `mte`, `multivalue`, `mutable-globals`, `neon`, `nontrapping-fptoint`, `nvic`, `paca`, `pacg`, `pan`, `partword-atomics`, `pauth-lr`, `pclmulqdq`, `pmuv3`, `popcnt`, `power10-vector`, `power8-altivec`, `power8-vector`, `power9-altivec`, `power9-vector`, `prfchw`, `quadword-atomics`, `rand`, `ras`, `rclass`, `rcpc`, `rcpc2`, `rcpc3`, `rdm`, `rdrand`, `rdseed`, `reference-types`, `relax`, `relaxed-simd`, `rtm`, `sb`, `sha`, `sha2`, `sha3`, `sha512`, `sign-ext`, `simd128`, `sm3`, `sm4`, `sme`, `sme-b16b16`, `sme-f16f16`, `sme-f64f64`, `sme-f8f16`, `sme-f8f32`, `sme-fa64`, `sme-i16i64`, `sme-lutv2`, `sme2`, `sme2p1`, `spe`, `ssbs`, `sse`, `sse2`, `sse3`, `sse4.1`, `sse4.2`, `sse4a`, `ssse3`, `ssve-fp8dot2`, `ssve-fp8dot4`, `ssve-fp8fma`, `sve`, `sve-b16b16`, `sve2`, `sve2-aes`, `sve2-bitperm`, `sve2-sha3`, `sve2-sm4`, `sve2p1`, `tbm`, `thumb-mode`, `thumb2`, `tme`, `trust`, `trustzone`, `ual`, `unaligned-scalar-mem`, `v`, `v5te`, `v6`, `v6k`, `v6t2`, `v7`, `v8`, `v8.1a`, `v8.2a`, `v8.3a`, `v8.4a`, `v8.5a`, `v8.6a`, `v8.7a`, `v8.8a`, `v8.9a`, `v9.1a`, `v9.2a`, `v9.3a`, `v9.4a`, `v9.5a`, `v9a`, `vaes`, `vdsp2e60f`, `vdspv1`, `vdspv2`, `vector`, `vfp2`, `vfp3`, `vfp4`, `vh`, `virt`, `virtualization`, `vpclmulqdq`, `vsx`, `wfxt`, `xop`, `xsave`, `xsavec`, `xsaveopt`, `xsaves`, `zaamo`, `zabha`, `zalrsc`, `zba`, `zbb`, `zbc`, `zbkb`, `zbkc`, `zbkx`, `zbs`, `zdinx`, `zfh`, `zfhmin`, `zfinx`, `zhinx`, `zhinxmin`, `zk`, `zkn`, `zknd`, `zkne`, `zknh`, `zkr`, `zks`, `zksed`, `zksh`, and `zkt` = note: see <https://doc.rust-lang.org/nightly/rustc/check-cfg.html> for more information about checking conditional configuration warning: unexpected `cfg` condition value: `_UNEXPECTED_VALUE` diff --git a/tests/ui/closures/closure-move-sync.stderr b/tests/ui/closures/closure-move-sync.stderr index 6cade0c09dd..2bb26b0c0b7 100644 --- a/tests/ui/closures/closure-move-sync.stderr +++ b/tests/ui/closures/closure-move-sync.stderr @@ -10,7 +10,7 @@ LL | | LL | | }); | |_____^ `std::sync::mpsc::Receiver<()>` cannot be shared between threads safely | - = help: the trait `Sync` is not implemented for `std::sync::mpsc::Receiver<()>`, which is required by `{closure@$DIR/closure-move-sync.rs:6:27: 6:29}: Send` + = help: the trait `Sync` is not implemented for `std::sync::mpsc::Receiver<()>` = note: required for `&std::sync::mpsc::Receiver<()>` to implement `Send` note: required because it's used within this closure --> $DIR/closure-move-sync.rs:6:27 diff --git a/tests/ui/closures/closure-return-type-must-be-sized.stderr b/tests/ui/closures/closure-return-type-must-be-sized.stderr index 167d326e26e..04ae7343bbe 100644 --- a/tests/ui/closures/closure-return-type-must-be-sized.stderr +++ b/tests/ui/closures/closure-return-type-must-be-sized.stderr @@ -4,7 +4,7 @@ error[E0277]: the size for values of type `dyn A` cannot be known at compilation LL | a::foo::<fn() -> dyn A>(); | ^^^^^^^^^^^^^^^^^^^^^^^^^ doesn't have a size known at compile-time | - = help: within `fn() -> dyn A`, the trait `Sized` is not implemented for `dyn A`, which is required by `fn() -> dyn A: FnOnce()` + = help: within `fn() -> dyn A`, the trait `Sized` is not implemented for `dyn A` = note: required because it appears within the type `fn() -> dyn A` error[E0277]: the size for values of type `dyn A` cannot be known at compilation time @@ -13,7 +13,7 @@ error[E0277]: the size for values of type `dyn A` cannot be known at compilation LL | a::bar::<fn() -> dyn A, _>(); | ^^^^^^^^^^^^^ doesn't have a size known at compile-time | - = help: within `fn() -> dyn A`, the trait `Sized` is not implemented for `dyn A`, which is required by `fn() -> dyn A: FnOnce()` + = help: within `fn() -> dyn A`, the trait `Sized` is not implemented for `dyn A` = note: required because it appears within the type `fn() -> dyn A` note: required by a bound in `a::bar` --> $DIR/closure-return-type-must-be-sized.rs:14:19 @@ -27,7 +27,7 @@ error[E0277]: the size for values of type `dyn A` cannot be known at compilation LL | a::baz::<fn() -> dyn A>(); | ^^^^^^^^^^^^^^^^^^^^^^^^^ doesn't have a size known at compile-time | - = help: within `fn() -> dyn A`, the trait `Sized` is not implemented for `dyn A`, which is required by `fn() -> dyn A: FnOnce()` + = help: within `fn() -> dyn A`, the trait `Sized` is not implemented for `dyn A` = note: required because it appears within the type `fn() -> dyn A` error[E0277]: the size for values of type `dyn A` cannot be known at compilation time @@ -36,7 +36,7 @@ error[E0277]: the size for values of type `dyn A` cannot be known at compilation LL | b::foo::<fn() -> dyn A>(); | ^^^^^^^^^^^^^^^^^^^^^^^^^ doesn't have a size known at compile-time | - = help: within `fn() -> dyn A`, the trait `Sized` is not implemented for `dyn A`, which is required by `fn() -> dyn A: FnOnce()` + = help: within `fn() -> dyn A`, the trait `Sized` is not implemented for `dyn A` = note: required because it appears within the type `fn() -> dyn A` error[E0277]: the size for values of type `dyn A` cannot be known at compilation time @@ -45,7 +45,7 @@ error[E0277]: the size for values of type `dyn A` cannot be known at compilation LL | b::bar::<fn() -> dyn A, _>(); | ^^^^^^^^^^^^^ doesn't have a size known at compile-time | - = help: within `fn() -> dyn A`, the trait `Sized` is not implemented for `dyn A`, which is required by `fn() -> dyn A: Fn()` + = help: within `fn() -> dyn A`, the trait `Sized` is not implemented for `dyn A` = note: required because it appears within the type `fn() -> dyn A` note: required by a bound in `b::bar` --> $DIR/closure-return-type-must-be-sized.rs:28:19 @@ -59,7 +59,7 @@ error[E0277]: the size for values of type `dyn A` cannot be known at compilation LL | b::baz::<fn() -> dyn A>(); | ^^^^^^^^^^^^^^^^^^^^^^^^^ doesn't have a size known at compile-time | - = help: within `fn() -> dyn A`, the trait `Sized` is not implemented for `dyn A`, which is required by `fn() -> dyn A: FnOnce()` + = help: within `fn() -> dyn A`, the trait `Sized` is not implemented for `dyn A` = note: required because it appears within the type `fn() -> dyn A` error[E0277]: the size for values of type `dyn A` cannot be known at compilation time @@ -68,7 +68,7 @@ error[E0277]: the size for values of type `dyn A` cannot be known at compilation LL | c::foo::<fn() -> dyn A>(); | ^^^^^^^^^^^^^^^^^^^^^^^^^ doesn't have a size known at compile-time | - = help: within `fn() -> dyn A`, the trait `Sized` is not implemented for `dyn A`, which is required by `fn() -> dyn A: FnOnce()` + = help: within `fn() -> dyn A`, the trait `Sized` is not implemented for `dyn A` = note: required because it appears within the type `fn() -> dyn A` error[E0277]: the size for values of type `dyn A` cannot be known at compilation time @@ -77,7 +77,7 @@ error[E0277]: the size for values of type `dyn A` cannot be known at compilation LL | c::bar::<fn() -> dyn A, _>(); | ^^^^^^^^^^^^^ doesn't have a size known at compile-time | - = help: within `fn() -> dyn A`, the trait `Sized` is not implemented for `dyn A`, which is required by `fn() -> dyn A: FnMut()` + = help: within `fn() -> dyn A`, the trait `Sized` is not implemented for `dyn A` = note: required because it appears within the type `fn() -> dyn A` note: required by a bound in `c::bar` --> $DIR/closure-return-type-must-be-sized.rs:42:19 @@ -91,7 +91,7 @@ error[E0277]: the size for values of type `dyn A` cannot be known at compilation LL | c::baz::<fn() -> dyn A>(); | ^^^^^^^^^^^^^^^^^^^^^^^^^ doesn't have a size known at compile-time | - = help: within `fn() -> dyn A`, the trait `Sized` is not implemented for `dyn A`, which is required by `fn() -> dyn A: FnOnce()` + = help: within `fn() -> dyn A`, the trait `Sized` is not implemented for `dyn A` = note: required because it appears within the type `fn() -> dyn A` error: aborting due to 9 previous errors diff --git a/tests/ui/coherence/deep-bad-copy-reason.stderr b/tests/ui/coherence/deep-bad-copy-reason.stderr index fe5ae9b08b4..534f26c39c2 100644 --- a/tests/ui/coherence/deep-bad-copy-reason.stderr +++ b/tests/ui/coherence/deep-bad-copy-reason.stderr @@ -19,7 +19,7 @@ error[E0277]: the size for values of type `OpaqueListContents` cannot be known a LL | pub struct List<'tcx, T>(Interned<'tcx, ListS<T>>); | ^^^^^^^^^^^^^^^^^^^^^^^^ doesn't have a size known at compile-time | - = help: within `ListS<T>`, the trait `Sized` is not implemented for `OpaqueListContents`, which is required by `ListS<T>: Sized` + = help: within `ListS<T>`, the trait `Sized` is not implemented for `OpaqueListContents` note: required because it appears within the type `ListS<T>` --> $DIR/deep-bad-copy-reason.rs:7:12 | diff --git a/tests/ui/const-generics/adt_const_params/const_param_ty_bad_empty_array.stderr b/tests/ui/const-generics/adt_const_params/const_param_ty_bad_empty_array.stderr index 9852e181b9a..9220cd1f94e 100644 --- a/tests/ui/const-generics/adt_const_params/const_param_ty_bad_empty_array.stderr +++ b/tests/ui/const-generics/adt_const_params/const_param_ty_bad_empty_array.stderr @@ -2,7 +2,7 @@ error[E0277]: `NotParam` can't be used as a const parameter type --> $DIR/const_param_ty_bad_empty_array.rs:10:13 | LL | check::<[NotParam; 0]>(); - | ^^^^^^^^^^^^^ the trait `ConstParamTy_` is not implemented for `NotParam`, which is required by `[NotParam; 0]: ConstParamTy_` + | ^^^^^^^^^^^^^ the trait `ConstParamTy_` is not implemented for `NotParam` | = note: required for `[NotParam; 0]` to implement `ConstParamTy_` note: required by a bound in `check` diff --git a/tests/ui/const-generics/adt_const_params/const_param_ty_generic_bounds_do_not_hold.stderr b/tests/ui/const-generics/adt_const_params/const_param_ty_generic_bounds_do_not_hold.stderr index e63ae582fd5..d01aaffe8ae 100644 --- a/tests/ui/const-generics/adt_const_params/const_param_ty_generic_bounds_do_not_hold.stderr +++ b/tests/ui/const-generics/adt_const_params/const_param_ty_generic_bounds_do_not_hold.stderr @@ -2,7 +2,7 @@ error[E0277]: `NotParam` can't be used as a const parameter type --> $DIR/const_param_ty_generic_bounds_do_not_hold.rs:10:13 | LL | check::<&NotParam>(); - | ^^^^^^^^^ the trait `UnsizedConstParamTy` is not implemented for `NotParam`, which is required by `&NotParam: UnsizedConstParamTy` + | ^^^^^^^^^ the trait `UnsizedConstParamTy` is not implemented for `NotParam` | = note: required for `&NotParam` to implement `UnsizedConstParamTy` note: required by a bound in `check` @@ -15,7 +15,7 @@ error[E0277]: `NotParam` can't be used as a const parameter type --> $DIR/const_param_ty_generic_bounds_do_not_hold.rs:11:13 | LL | check::<[NotParam]>(); - | ^^^^^^^^^^ the trait `UnsizedConstParamTy` is not implemented for `NotParam`, which is required by `[NotParam]: UnsizedConstParamTy` + | ^^^^^^^^^^ the trait `UnsizedConstParamTy` is not implemented for `NotParam` | = note: required for `[NotParam]` to implement `UnsizedConstParamTy` note: required by a bound in `check` @@ -28,7 +28,7 @@ error[E0277]: `NotParam` can't be used as a const parameter type --> $DIR/const_param_ty_generic_bounds_do_not_hold.rs:12:13 | LL | check::<[NotParam; 17]>(); - | ^^^^^^^^^^^^^^ the trait `UnsizedConstParamTy` is not implemented for `NotParam`, which is required by `[NotParam; 17]: UnsizedConstParamTy` + | ^^^^^^^^^^^^^^ the trait `UnsizedConstParamTy` is not implemented for `NotParam` | = note: required for `[NotParam; 17]` to implement `UnsizedConstParamTy` note: required by a bound in `check` diff --git a/tests/ui/const-generics/adt_const_params/unsizing-wfcheck-issue-126272.stderr b/tests/ui/const-generics/adt_const_params/unsizing-wfcheck-issue-126272.stderr index 1c30aa68e85..72f3fd9de90 100644 --- a/tests/ui/const-generics/adt_const_params/unsizing-wfcheck-issue-126272.stderr +++ b/tests/ui/const-generics/adt_const_params/unsizing-wfcheck-issue-126272.stderr @@ -64,7 +64,7 @@ LL | #[derive(Debug, PartialEq, Eq, ConstParamTy)] LL | nested: &'static Bar<dyn std::fmt::Debug>, | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ doesn't have a size known at compile-time | - = help: the trait `Sized` is not implemented for `(dyn Debug + 'static)`, which is required by `&&'static Bar<(dyn Debug + 'static)>: Debug` + = help: the trait `Sized` is not implemented for `(dyn Debug + 'static)` = help: the trait `Debug` is implemented for `Bar<T>` note: required for `Bar<(dyn Debug + 'static)>` to implement `Debug` --> $DIR/unsizing-wfcheck-issue-126272.rs:20:10 @@ -96,7 +96,7 @@ LL | #[derive(Debug, PartialEq, Eq, ConstParamTy)] | -- in this derive macro expansion ... LL | nested: &'static Bar<dyn std::fmt::Debug>, - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ the trait `Eq` is not implemented for `dyn Debug`, which is required by `&'static Bar<dyn Debug>: Eq` + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ the trait `Eq` is not implemented for `dyn Debug` | = help: the trait `Eq` is implemented for `Bar<T>` note: required for `Bar<dyn Debug>` to implement `Eq` diff --git a/tests/ui/const-generics/generic_const_exprs/issue-85848.stderr b/tests/ui/const-generics/generic_const_exprs/issue-85848.stderr index 4abe39eb598..6ff22ffa847 100644 --- a/tests/ui/const-generics/generic_const_exprs/issue-85848.stderr +++ b/tests/ui/const-generics/generic_const_exprs/issue-85848.stderr @@ -2,7 +2,7 @@ error[E0277]: the trait bound `(): _Contains<&C>` is not satisfied --> $DIR/issue-85848.rs:24:29 | LL | writes_to_specific_path(&cap); - | ----------------------- ^^^^ the trait `_Contains<&C>` is not implemented for `()`, which is required by `&C: Delegates<()>` + | ----------------------- ^^^^ the trait `_Contains<&C>` is not implemented for `()` | | | required by a bound introduced by this call | diff --git a/tests/ui/const-generics/issues/issue-67185-2.stderr b/tests/ui/const-generics/issues/issue-67185-2.stderr index 5cc3bb673bc..82813a24f99 100644 --- a/tests/ui/const-generics/issues/issue-67185-2.stderr +++ b/tests/ui/const-generics/issues/issue-67185-2.stderr @@ -32,7 +32,7 @@ error[E0277]: the trait bound `[u16; 3]: Bar` is not satisfied --> $DIR/issue-67185-2.rs:21:6 | LL | impl Foo for FooImpl {} - | ^^^ the trait `Bar` is not implemented for `[u16; 3]`, which is required by `<u8 as Baz>::Quaks: Bar` + | ^^^ the trait `Bar` is not implemented for `[u16; 3]` | = help: the following other types implement trait `Bar`: [[u16; 3]; 3] @@ -50,7 +50,7 @@ error[E0277]: the trait bound `[[u16; 3]; 2]: Bar` is not satisfied --> $DIR/issue-67185-2.rs:21:6 | LL | impl Foo for FooImpl {} - | ^^^ the trait `Bar` is not implemented for `[[u16; 3]; 2]`, which is required by `[<u8 as Baz>::Quaks; 2]: Bar` + | ^^^ the trait `Bar` is not implemented for `[[u16; 3]; 2]` | = help: the following other types implement trait `Bar`: [[u16; 3]; 3] diff --git a/tests/ui/const-generics/kind_mismatch.stderr b/tests/ui/const-generics/kind_mismatch.stderr index 80968ebea68..e13bc6ee058 100644 --- a/tests/ui/const-generics/kind_mismatch.stderr +++ b/tests/ui/const-generics/kind_mismatch.stderr @@ -18,7 +18,7 @@ error[E0277]: the trait bound `KeyHolder<0>: SubsetExcept<_>` is not satisfied --> $DIR/kind_mismatch.rs:22:45 | LL | let map: KeyHolder<0> = remove_key::<_, _>(); - | ^ the trait `ContainsKey<0>` is not implemented for `KeyHolder<0>`, which is required by `KeyHolder<0>: SubsetExcept<_>` + | ^ the trait `ContainsKey<0>` is not implemented for `KeyHolder<0>` | note: required for `KeyHolder<0>` to implement `SubsetExcept<_>` --> $DIR/kind_mismatch.rs:15:28 diff --git a/tests/ui/consts/const-block-const-bound.stderr b/tests/ui/consts/const-block-const-bound.stderr index 8cb91d78f6c..5e24959146b 100644 --- a/tests/ui/consts/const-block-const-bound.stderr +++ b/tests/ui/consts/const-block-const-bound.stderr @@ -1,14 +1,14 @@ error: `~const` can only be applied to `#[const_trait]` traits - --> $DIR/const-block-const-bound.rs:8:22 + --> $DIR/const-block-const-bound.rs:8:15 | LL | const fn f<T: ~const Destruct>(x: T) {} - | ^^^^^^^^ + | ^^^^^^ error: `~const` can only be applied to `#[const_trait]` traits - --> $DIR/const-block-const-bound.rs:8:22 + --> $DIR/const-block-const-bound.rs:8:15 | LL | const fn f<T: ~const Destruct>(x: T) {} - | ^^^^^^^^ + | ^^^^^^ | = note: duplicate diagnostic emitted due to `-Z deduplicate-diagnostics=no` diff --git a/tests/ui/consts/const-blocks/fn-call-in-non-const.stderr b/tests/ui/consts/const-blocks/fn-call-in-non-const.stderr index 9dce29732ac..272c2f045e1 100644 --- a/tests/ui/consts/const-blocks/fn-call-in-non-const.stderr +++ b/tests/ui/consts/const-blocks/fn-call-in-non-const.stderr @@ -2,7 +2,7 @@ error[E0277]: the trait bound `Bar: Copy` is not satisfied --> $DIR/fn-call-in-non-const.rs:14:32 | LL | let _: [Option<Bar>; 2] = [no_copy(); 2]; - | ^^^^^^^^^ the trait `Copy` is not implemented for `Bar`, which is required by `Option<Bar>: Copy` + | ^^^^^^^^^ the trait `Copy` is not implemented for `Bar` | = note: required for `Option<Bar>` to implement `Copy` = note: the `Copy` trait is required because this value will be copied for each element of the array diff --git a/tests/ui/consts/const-blocks/migrate-fail.stderr b/tests/ui/consts/const-blocks/migrate-fail.stderr index 3887658f748..3c116026e58 100644 --- a/tests/ui/consts/const-blocks/migrate-fail.stderr +++ b/tests/ui/consts/const-blocks/migrate-fail.stderr @@ -2,7 +2,7 @@ error[E0277]: the trait bound `Bar: Copy` is not satisfied --> $DIR/migrate-fail.rs:11:38 | LL | let arr: [Option<Bar>; 2] = [x; 2]; - | ^ the trait `Copy` is not implemented for `Bar`, which is required by `Option<Bar>: Copy` + | ^ the trait `Copy` is not implemented for `Bar` | = note: required for `Option<Bar>` to implement `Copy` = note: the `Copy` trait is required because this value will be copied for each element of the array @@ -18,7 +18,7 @@ error[E0277]: the trait bound `Bar: Copy` is not satisfied --> $DIR/migrate-fail.rs:17:38 | LL | let arr: [Option<Bar>; 2] = [x; 2]; - | ^ the trait `Copy` is not implemented for `Bar`, which is required by `Option<Bar>: Copy` + | ^ the trait `Copy` is not implemented for `Bar` | = note: required for `Option<Bar>` to implement `Copy` = note: the `Copy` trait is required because this value will be copied for each element of the array diff --git a/tests/ui/consts/const-blocks/nll-fail.stderr b/tests/ui/consts/const-blocks/nll-fail.stderr index a2ea833f650..ff2b62da668 100644 --- a/tests/ui/consts/const-blocks/nll-fail.stderr +++ b/tests/ui/consts/const-blocks/nll-fail.stderr @@ -2,7 +2,7 @@ error[E0277]: the trait bound `Bar: Copy` is not satisfied --> $DIR/nll-fail.rs:11:38 | LL | let arr: [Option<Bar>; 2] = [x; 2]; - | ^ the trait `Copy` is not implemented for `Bar`, which is required by `Option<Bar>: Copy` + | ^ the trait `Copy` is not implemented for `Bar` | = note: required for `Option<Bar>` to implement `Copy` = note: the `Copy` trait is required because this value will be copied for each element of the array @@ -18,7 +18,7 @@ error[E0277]: the trait bound `Bar: Copy` is not satisfied --> $DIR/nll-fail.rs:17:38 | LL | let arr: [Option<Bar>; 2] = [x; 2]; - | ^ the trait `Copy` is not implemented for `Bar`, which is required by `Option<Bar>: Copy` + | ^ the trait `Copy` is not implemented for `Bar` | = note: required for `Option<Bar>` to implement `Copy` = note: the `Copy` trait is required because this value will be copied for each element of the array diff --git a/tests/ui/consts/const-blocks/trait-error.stderr b/tests/ui/consts/const-blocks/trait-error.stderr index 8f00f14dfb9..068720a53f6 100644 --- a/tests/ui/consts/const-blocks/trait-error.stderr +++ b/tests/ui/consts/const-blocks/trait-error.stderr @@ -4,7 +4,7 @@ error[E0277]: the trait bound `String: Copy` is not satisfied LL | [Foo(String::new()); 4]; | ^^^^^^^^^^^^^^^^^^ | | - | the trait `Copy` is not implemented for `String`, which is required by `Foo<String>: Copy` + | the trait `Copy` is not implemented for `String` | help: create an inline `const` block: `const { Foo(String::new()) }` | note: required for `Foo<String>` to implement `Copy` diff --git a/tests/ui/consts/const-fn-in-vec.stderr b/tests/ui/consts/const-fn-in-vec.stderr index 7c6b3bee940..b31e180fea2 100644 --- a/tests/ui/consts/const-fn-in-vec.stderr +++ b/tests/ui/consts/const-fn-in-vec.stderr @@ -4,7 +4,7 @@ error[E0277]: the trait bound `String: Copy` is not satisfied LL | static _MAYBE_STRINGS: [Option<String>; 5] = [None; 5]; | ^^^^ | | - | the trait `Copy` is not implemented for `String`, which is required by `Option<String>: Copy` + | the trait `Copy` is not implemented for `String` | help: create an inline `const` block: `const { None }` | = note: required for `Option<String>` to implement `Copy` @@ -27,7 +27,7 @@ error[E0277]: the trait bound `String: Copy` is not satisfied LL | let _maybe_strings: [Option<String>; 5] = [None; 5]; | ^^^^ | | - | the trait `Copy` is not implemented for `String`, which is required by `Option<String>: Copy` + | the trait `Copy` is not implemented for `String` | help: create an inline `const` block: `const { None }` | = note: required for `Option<String>` to implement `Copy` diff --git a/tests/ui/consts/constifconst-call-in-const-position.stderr b/tests/ui/consts/constifconst-call-in-const-position.stderr index 2195cab3f4d..6add83dc52c 100644 --- a/tests/ui/consts/constifconst-call-in-const-position.stderr +++ b/tests/ui/consts/constifconst-call-in-const-position.stderr @@ -1,14 +1,15 @@ -error: using `#![feature(effects)]` without enabling next trait solver globally - | - = note: the next trait solver must be enabled globally for the effects feature to work correctly - = help: use `-Znext-solver` to enable - -error[E0080]: evaluation of `foo::<()>::{constant#0}` failed +error[E0277]: the trait bound `T: const Tr` is not satisfied --> $DIR/constifconst-call-in-const-position.rs:17:38 | LL | const fn foo<T: ~const Tr>() -> [u8; T::a()] { - | ^^^^^^ calling non-const function `<() as Tr>::a` + | ^^^^^^ + +error[E0277]: the trait bound `T: const Tr` is not satisfied + --> $DIR/constifconst-call-in-const-position.rs:18:9 + | +LL | [0; T::a()] + | ^^^^^^ error: aborting due to 2 previous errors -For more information about this error, try `rustc --explain E0080`. +For more information about this error, try `rustc --explain E0277`. diff --git a/tests/ui/consts/fn_trait_refs.stderr b/tests/ui/consts/fn_trait_refs.stderr index 82b2b87c4a5..a686bc23c0f 100644 --- a/tests/ui/consts/fn_trait_refs.stderr +++ b/tests/ui/consts/fn_trait_refs.stderr @@ -11,168 +11,168 @@ LL | #![feature(const_cmp)] | ^^^^^^^^^ error: `~const` can only be applied to `#[const_trait]` traits - --> $DIR/fn_trait_refs.rs:13:15 + --> $DIR/fn_trait_refs.rs:13:8 | LL | T: ~const Fn<()> + ~const Destruct, - | ^^^^^^ + | ^^^^^^ error: `~const` can only be applied to `#[const_trait]` traits - --> $DIR/fn_trait_refs.rs:13:31 + --> $DIR/fn_trait_refs.rs:13:24 | LL | T: ~const Fn<()> + ~const Destruct, - | ^^^^^^^^ + | ^^^^^^ error: `~const` can only be applied to `#[const_trait]` traits - --> $DIR/fn_trait_refs.rs:13:15 + --> $DIR/fn_trait_refs.rs:13:8 | LL | T: ~const Fn<()> + ~const Destruct, - | ^^^^^^ + | ^^^^^^ | = note: duplicate diagnostic emitted due to `-Z deduplicate-diagnostics=no` error: `~const` can only be applied to `#[const_trait]` traits - --> $DIR/fn_trait_refs.rs:13:15 + --> $DIR/fn_trait_refs.rs:13:8 | LL | T: ~const Fn<()> + ~const Destruct, - | ^^^^^^ + | ^^^^^^ | = note: duplicate diagnostic emitted due to `-Z deduplicate-diagnostics=no` error: `~const` can only be applied to `#[const_trait]` traits - --> $DIR/fn_trait_refs.rs:13:31 + --> $DIR/fn_trait_refs.rs:13:24 | LL | T: ~const Fn<()> + ~const Destruct, - | ^^^^^^^^ + | ^^^^^^ | = note: duplicate diagnostic emitted due to `-Z deduplicate-diagnostics=no` error: `~const` can only be applied to `#[const_trait]` traits - --> $DIR/fn_trait_refs.rs:20:15 + --> $DIR/fn_trait_refs.rs:20:8 | LL | T: ~const FnMut<()> + ~const Destruct, - | ^^^^^^^^^ + | ^^^^^^ error: `~const` can only be applied to `#[const_trait]` traits - --> $DIR/fn_trait_refs.rs:20:34 + --> $DIR/fn_trait_refs.rs:20:27 | LL | T: ~const FnMut<()> + ~const Destruct, - | ^^^^^^^^ + | ^^^^^^ error: `~const` can only be applied to `#[const_trait]` traits - --> $DIR/fn_trait_refs.rs:20:15 + --> $DIR/fn_trait_refs.rs:20:8 | LL | T: ~const FnMut<()> + ~const Destruct, - | ^^^^^^^^^ + | ^^^^^^ | = note: duplicate diagnostic emitted due to `-Z deduplicate-diagnostics=no` error: `~const` can only be applied to `#[const_trait]` traits - --> $DIR/fn_trait_refs.rs:20:15 + --> $DIR/fn_trait_refs.rs:20:8 | LL | T: ~const FnMut<()> + ~const Destruct, - | ^^^^^^^^^ + | ^^^^^^ | = note: duplicate diagnostic emitted due to `-Z deduplicate-diagnostics=no` error: `~const` can only be applied to `#[const_trait]` traits - --> $DIR/fn_trait_refs.rs:20:34 + --> $DIR/fn_trait_refs.rs:20:27 | LL | T: ~const FnMut<()> + ~const Destruct, - | ^^^^^^^^ + | ^^^^^^ | = note: duplicate diagnostic emitted due to `-Z deduplicate-diagnostics=no` error: `~const` can only be applied to `#[const_trait]` traits - --> $DIR/fn_trait_refs.rs:27:15 + --> $DIR/fn_trait_refs.rs:27:8 | LL | T: ~const FnOnce<()>, - | ^^^^^^^^^^ + | ^^^^^^ error: `~const` can only be applied to `#[const_trait]` traits - --> $DIR/fn_trait_refs.rs:27:15 + --> $DIR/fn_trait_refs.rs:27:8 | LL | T: ~const FnOnce<()>, - | ^^^^^^^^^^ + | ^^^^^^ | = note: duplicate diagnostic emitted due to `-Z deduplicate-diagnostics=no` error: `~const` can only be applied to `#[const_trait]` traits - --> $DIR/fn_trait_refs.rs:27:15 + --> $DIR/fn_trait_refs.rs:27:8 | LL | T: ~const FnOnce<()>, - | ^^^^^^^^^^ + | ^^^^^^ | = note: duplicate diagnostic emitted due to `-Z deduplicate-diagnostics=no` error: `~const` can only be applied to `#[const_trait]` traits - --> $DIR/fn_trait_refs.rs:34:15 + --> $DIR/fn_trait_refs.rs:34:8 | LL | T: ~const Fn<()> + ~const Destruct, - | ^^^^^^ + | ^^^^^^ error: `~const` can only be applied to `#[const_trait]` traits - --> $DIR/fn_trait_refs.rs:34:31 + --> $DIR/fn_trait_refs.rs:34:24 | LL | T: ~const Fn<()> + ~const Destruct, - | ^^^^^^^^ + | ^^^^^^ error: `~const` can only be applied to `#[const_trait]` traits - --> $DIR/fn_trait_refs.rs:34:15 + --> $DIR/fn_trait_refs.rs:34:8 | LL | T: ~const Fn<()> + ~const Destruct, - | ^^^^^^ + | ^^^^^^ | = note: duplicate diagnostic emitted due to `-Z deduplicate-diagnostics=no` error: `~const` can only be applied to `#[const_trait]` traits - --> $DIR/fn_trait_refs.rs:34:15 + --> $DIR/fn_trait_refs.rs:34:8 | LL | T: ~const Fn<()> + ~const Destruct, - | ^^^^^^ + | ^^^^^^ | = note: duplicate diagnostic emitted due to `-Z deduplicate-diagnostics=no` error: `~const` can only be applied to `#[const_trait]` traits - --> $DIR/fn_trait_refs.rs:34:31 + --> $DIR/fn_trait_refs.rs:34:24 | LL | T: ~const Fn<()> + ~const Destruct, - | ^^^^^^^^ + | ^^^^^^ | = note: duplicate diagnostic emitted due to `-Z deduplicate-diagnostics=no` error: `~const` can only be applied to `#[const_trait]` traits - --> $DIR/fn_trait_refs.rs:48:15 + --> $DIR/fn_trait_refs.rs:48:8 | LL | T: ~const FnMut<()> + ~const Destruct, - | ^^^^^^^^^ + | ^^^^^^ error: `~const` can only be applied to `#[const_trait]` traits - --> $DIR/fn_trait_refs.rs:48:34 + --> $DIR/fn_trait_refs.rs:48:27 | LL | T: ~const FnMut<()> + ~const Destruct, - | ^^^^^^^^ + | ^^^^^^ error: `~const` can only be applied to `#[const_trait]` traits - --> $DIR/fn_trait_refs.rs:48:15 + --> $DIR/fn_trait_refs.rs:48:8 | LL | T: ~const FnMut<()> + ~const Destruct, - | ^^^^^^^^^ + | ^^^^^^ | = note: duplicate diagnostic emitted due to `-Z deduplicate-diagnostics=no` error: `~const` can only be applied to `#[const_trait]` traits - --> $DIR/fn_trait_refs.rs:48:15 + --> $DIR/fn_trait_refs.rs:48:8 | LL | T: ~const FnMut<()> + ~const Destruct, - | ^^^^^^^^^ + | ^^^^^^ | = note: duplicate diagnostic emitted due to `-Z deduplicate-diagnostics=no` error: `~const` can only be applied to `#[const_trait]` traits - --> $DIR/fn_trait_refs.rs:48:34 + --> $DIR/fn_trait_refs.rs:48:27 | LL | T: ~const FnMut<()> + ~const Destruct, - | ^^^^^^^^ + | ^^^^^^ | = note: duplicate diagnostic emitted due to `-Z deduplicate-diagnostics=no` diff --git a/tests/ui/consts/rustc-const-stability-require-const.rs b/tests/ui/consts/rustc-const-stability-require-const.rs index 1c66f6e2aa5..6cc3f0f0da1 100644 --- a/tests/ui/consts/rustc-const-stability-require-const.rs +++ b/tests/ui/consts/rustc-const-stability-require-const.rs @@ -47,16 +47,15 @@ pub const fn foobar() {} pub const fn barfoo() {} // `rustc_const_stable` also requires the function to be stable. -// FIXME: these are disabled until <https://github.com/rust-lang/stdarch/pull/1654> propagates. #[rustc_const_stable(feature = "barfoo_const", since = "1.0.0")] const fn barfoo_unmarked() {} -// FIXME disabled ERROR can only be applied to functions that are declared `#[stable]` +//~^ ERROR can only be applied to functions that are declared `#[stable]` #[unstable(feature = "unstable", issue = "none")] #[rustc_const_stable(feature = "barfoo_const", since = "1.0.0")] pub const fn barfoo_unstable() {} -// FIXME disabled ERROR can only be applied to functions that are declared `#[stable]` +//~^ ERROR can only be applied to functions that are declared `#[stable]` // `#[rustc_const_stable_indirect]` also requires a const fn #[rustc_const_stable_indirect] diff --git a/tests/ui/consts/rustc-const-stability-require-const.stderr b/tests/ui/consts/rustc-const-stability-require-const.stderr index 09b96ce6f83..d9a7d37cbcd 100644 --- a/tests/ui/consts/rustc-const-stability-require-const.stderr +++ b/tests/ui/consts/rustc-const-stability-require-const.stderr @@ -70,17 +70,33 @@ help: make the function or method const LL | pub extern "C" fn foo_c() {} | ^^^^^^^^^^^^^^^^^^^^^^^^^ +error: attribute `#[rustc_const_stable]` can only be applied to functions that are declared `#[stable]` + --> $DIR/rustc-const-stability-require-const.rs:52:1 + | +LL | #[rustc_const_stable(feature = "barfoo_const", since = "1.0.0")] + | ---------------------------------------------------------------- attribute specified here +LL | const fn barfoo_unmarked() {} + | ^^^^^^^^^^^^^^^^^^^^^^^^^^ + +error: attribute `#[rustc_const_stable]` can only be applied to functions that are declared `#[stable]` + --> $DIR/rustc-const-stability-require-const.rs:57:1 + | +LL | #[rustc_const_stable(feature = "barfoo_const", since = "1.0.0")] + | ---------------------------------------------------------------- attribute specified here +LL | pub const fn barfoo_unstable() {} + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + error: attributes `#[rustc_const_unstable]`, `#[rustc_const_stable]` and `#[rustc_const_stable_indirect]` require the function or method to be `const` - --> $DIR/rustc-const-stability-require-const.rs:64:1 + --> $DIR/rustc-const-stability-require-const.rs:63:1 | LL | pub fn not_a_const_fn() {} | ^^^^^^^^^^^^^^^^^^^^^^^ | help: make the function or method const - --> $DIR/rustc-const-stability-require-const.rs:64:1 + --> $DIR/rustc-const-stability-require-const.rs:63:1 | LL | pub fn not_a_const_fn() {} | ^^^^^^^^^^^^^^^^^^^^^^^ -error: aborting due to 7 previous errors +error: aborting due to 9 previous errors diff --git a/tests/ui/consts/unstable-const-fn-in-libcore.stderr b/tests/ui/consts/unstable-const-fn-in-libcore.stderr index e546694070d..2bdec1bf41b 100644 --- a/tests/ui/consts/unstable-const-fn-in-libcore.stderr +++ b/tests/ui/consts/unstable-const-fn-in-libcore.stderr @@ -1,14 +1,14 @@ error: `~const` can only be applied to `#[const_trait]` traits - --> $DIR/unstable-const-fn-in-libcore.rs:19:39 + --> $DIR/unstable-const-fn-in-libcore.rs:19:32 | LL | const fn unwrap_or_else<F: ~const FnOnce() -> T>(self, f: F) -> T { - | ^^^^^^^^^^^^^ + | ^^^^^^ error: `~const` can only be applied to `#[const_trait]` traits - --> $DIR/unstable-const-fn-in-libcore.rs:19:39 + --> $DIR/unstable-const-fn-in-libcore.rs:19:32 | LL | const fn unwrap_or_else<F: ~const FnOnce() -> T>(self, f: F) -> T { - | ^^^^^^^^^^^^^ + | ^^^^^^ | = note: duplicate diagnostic emitted due to `-Z deduplicate-diagnostics=no` diff --git a/tests/ui/consts/zst_no_llvm_alloc.rs b/tests/ui/consts/zst_no_llvm_alloc.rs index 48ef11e2b58..1e92e3bbd4c 100644 --- a/tests/ui/consts/zst_no_llvm_alloc.rs +++ b/tests/ui/consts/zst_no_llvm_alloc.rs @@ -17,8 +17,11 @@ fn main() { // The exact addresses returned by these library functions are not necessarily stable guarantees // but for now we assert that we're still matching. - assert_eq!(<Vec<i32>>::new().as_ptr(), <&[i32]>::default().as_ptr()); - assert_eq!(<Box<[i32]>>::default().as_ptr(), (&[]).as_ptr()); + #[allow(dangling_pointers_from_temporaries)] + { + assert_eq!(<Vec<i32>>::new().as_ptr(), <&[i32]>::default().as_ptr()); + assert_eq!(<Box<[i32]>>::default().as_ptr(), (&[]).as_ptr()); + }; // statics must have a unique address (see https://github.com/rust-lang/rust/issues/18297, not // clear whether this is a stable guarantee) diff --git a/tests/ui/coroutine/clone-impl.stderr b/tests/ui/coroutine/clone-impl.stderr index 5330d3bbd39..1256c97a02f 100644 --- a/tests/ui/coroutine/clone-impl.stderr +++ b/tests/ui/coroutine/clone-impl.stderr @@ -5,7 +5,7 @@ LL | move || { | ------- within this `{coroutine@$DIR/clone-impl.rs:43:5: 43:12}` ... LL | check_copy(&gen_clone_0); - | ^^^^^^^^^^^^^^^^^^^^^^^^ within `{coroutine@$DIR/clone-impl.rs:43:5: 43:12}`, the trait `Copy` is not implemented for `Vec<u32>`, which is required by `{coroutine@$DIR/clone-impl.rs:43:5: 43:12}: Copy` + | ^^^^^^^^^^^^^^^^^^^^^^^^ within `{coroutine@$DIR/clone-impl.rs:43:5: 43:12}`, the trait `Copy` is not implemented for `Vec<u32>` | note: captured value does not implement `Copy` --> $DIR/clone-impl.rs:47:14 @@ -25,7 +25,7 @@ LL | move || { | ------- within this `{coroutine@$DIR/clone-impl.rs:43:5: 43:12}` ... LL | check_copy(&gen_clone_0); - | ^^^^^^^^^^^^^^^^^^^^^^^^ within `{coroutine@$DIR/clone-impl.rs:43:5: 43:12}`, the trait `Copy` is not implemented for `Vec<char>`, which is required by `{coroutine@$DIR/clone-impl.rs:43:5: 43:12}: Copy` + | ^^^^^^^^^^^^^^^^^^^^^^^^ within `{coroutine@$DIR/clone-impl.rs:43:5: 43:12}`, the trait `Copy` is not implemented for `Vec<char>` | note: coroutine does not implement `Copy` as this value is used across a yield --> $DIR/clone-impl.rs:45:9 @@ -47,7 +47,7 @@ LL | move || { | ------- within this `{coroutine@$DIR/clone-impl.rs:58:5: 58:12}` ... LL | check_copy(&gen_clone_1); - | ^^^^^^^^^^^^^^^^^^^^^^^^ within `{coroutine@$DIR/clone-impl.rs:58:5: 58:12}`, the trait `Copy` is not implemented for `Vec<u32>`, which is required by `{coroutine@$DIR/clone-impl.rs:58:5: 58:12}: Copy` + | ^^^^^^^^^^^^^^^^^^^^^^^^ within `{coroutine@$DIR/clone-impl.rs:58:5: 58:12}`, the trait `Copy` is not implemented for `Vec<u32>` | note: captured value does not implement `Copy` --> $DIR/clone-impl.rs:68:14 @@ -67,7 +67,7 @@ LL | move || { | ------- within this `{coroutine@$DIR/clone-impl.rs:58:5: 58:12}` ... LL | check_copy(&gen_clone_1); - | ^^^^^^^^^^^^^^^^^^^^^^^^ within `{coroutine@$DIR/clone-impl.rs:58:5: 58:12}`, the trait `Copy` is not implemented for `Vec<char>`, which is required by `{coroutine@$DIR/clone-impl.rs:58:5: 58:12}: Copy` + | ^^^^^^^^^^^^^^^^^^^^^^^^ within `{coroutine@$DIR/clone-impl.rs:58:5: 58:12}`, the trait `Copy` is not implemented for `Vec<char>` | note: coroutine does not implement `Copy` as this value is used across a yield --> $DIR/clone-impl.rs:64:9 @@ -90,7 +90,7 @@ LL | move || { | ------- within this `{coroutine@$DIR/clone-impl.rs:79:5: 79:12}` ... LL | check_copy(&gen_non_clone); - | ^^^^^^^^^^^^^^^^^^^^^^^^^^ within `{coroutine@$DIR/clone-impl.rs:79:5: 79:12}`, the trait `Copy` is not implemented for `NonClone`, which is required by `{coroutine@$DIR/clone-impl.rs:79:5: 79:12}: Copy` + | ^^^^^^^^^^^^^^^^^^^^^^^^^^ within `{coroutine@$DIR/clone-impl.rs:79:5: 79:12}`, the trait `Copy` is not implemented for `NonClone` | note: captured value does not implement `Copy` --> $DIR/clone-impl.rs:81:14 @@ -115,7 +115,7 @@ LL | move || { | ------- within this `{coroutine@$DIR/clone-impl.rs:79:5: 79:12}` ... LL | check_clone(&gen_non_clone); - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^ within `{coroutine@$DIR/clone-impl.rs:79:5: 79:12}`, the trait `Clone` is not implemented for `NonClone`, which is required by `{coroutine@$DIR/clone-impl.rs:79:5: 79:12}: Clone` + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^ within `{coroutine@$DIR/clone-impl.rs:79:5: 79:12}`, the trait `Clone` is not implemented for `NonClone` | note: captured value does not implement `Clone` --> $DIR/clone-impl.rs:81:14 diff --git a/tests/ui/coroutine/drop-tracking-parent-expression.stderr b/tests/ui/coroutine/drop-tracking-parent-expression.stderr index 5f8d8495e4f..51fc20070bf 100644 --- a/tests/ui/coroutine/drop-tracking-parent-expression.stderr +++ b/tests/ui/coroutine/drop-tracking-parent-expression.stderr @@ -13,7 +13,7 @@ LL | | }; LL | | ); | |_____- in this macro invocation | - = help: within `{coroutine@$DIR/drop-tracking-parent-expression.rs:17:34: 17:41}`, the trait `Send` is not implemented for `derived_drop::Client`, which is required by `{coroutine@$DIR/drop-tracking-parent-expression.rs:17:34: 17:41}: Send` + = help: within `{coroutine@$DIR/drop-tracking-parent-expression.rs:17:34: 17:41}`, the trait `Send` is not implemented for `derived_drop::Client` note: coroutine is not `Send` as this value is used across a yield --> $DIR/drop-tracking-parent-expression.rs:21:22 | @@ -53,7 +53,7 @@ LL | | }; LL | | ); | |_____- in this macro invocation | - = help: within `{coroutine@$DIR/drop-tracking-parent-expression.rs:17:34: 17:41}`, the trait `Send` is not implemented for `significant_drop::Client`, which is required by `{coroutine@$DIR/drop-tracking-parent-expression.rs:17:34: 17:41}: Send` + = help: within `{coroutine@$DIR/drop-tracking-parent-expression.rs:17:34: 17:41}`, the trait `Send` is not implemented for `significant_drop::Client` note: coroutine is not `Send` as this value is used across a yield --> $DIR/drop-tracking-parent-expression.rs:21:22 | @@ -93,7 +93,7 @@ LL | | }; LL | | ); | |_____- in this macro invocation | - = help: within `{coroutine@$DIR/drop-tracking-parent-expression.rs:17:34: 17:41}`, the trait `Send` is not implemented for `insignificant_dtor::Client`, which is required by `{coroutine@$DIR/drop-tracking-parent-expression.rs:17:34: 17:41}: Send` + = help: within `{coroutine@$DIR/drop-tracking-parent-expression.rs:17:34: 17:41}`, the trait `Send` is not implemented for `insignificant_dtor::Client` note: coroutine is not `Send` as this value is used across a yield --> $DIR/drop-tracking-parent-expression.rs:21:22 | diff --git a/tests/ui/coroutine/drop-yield-twice.stderr b/tests/ui/coroutine/drop-yield-twice.stderr index 362c6e943ad..c5da35d9736 100644 --- a/tests/ui/coroutine/drop-yield-twice.stderr +++ b/tests/ui/coroutine/drop-yield-twice.stderr @@ -9,7 +9,7 @@ LL | | yield; LL | | }) | |______^ coroutine is not `Send` | - = help: within `{coroutine@$DIR/drop-yield-twice.rs:7:30: 7:32}`, the trait `Send` is not implemented for `Foo`, which is required by `{coroutine@$DIR/drop-yield-twice.rs:7:30: 7:32}: Send` + = help: within `{coroutine@$DIR/drop-yield-twice.rs:7:30: 7:32}`, the trait `Send` is not implemented for `Foo` note: coroutine is not `Send` as this value is used across a yield --> $DIR/drop-yield-twice.rs:9:9 | diff --git a/tests/ui/coroutine/issue-105084.stderr b/tests/ui/coroutine/issue-105084.stderr index 6b1701f0c2a..11b5852b638 100644 --- a/tests/ui/coroutine/issue-105084.stderr +++ b/tests/ui/coroutine/issue-105084.stderr @@ -29,7 +29,7 @@ LL | || { | -- within this `{coroutine@$DIR/issue-105084.rs:15:5: 15:7}` ... LL | let mut h = copy(g); - | ^^^^^^^ within `{coroutine@$DIR/issue-105084.rs:15:5: 15:7}`, the trait `Copy` is not implemented for `Box<(i32, ())>`, which is required by `{coroutine@$DIR/issue-105084.rs:15:5: 15:7}: Copy` + | ^^^^^^^ within `{coroutine@$DIR/issue-105084.rs:15:5: 15:7}`, the trait `Copy` is not implemented for `Box<(i32, ())>` | note: coroutine does not implement `Copy` as this value is used across a yield --> $DIR/issue-105084.rs:22:22 diff --git a/tests/ui/coroutine/issue-68112.stderr b/tests/ui/coroutine/issue-68112.stderr index bcfcb5ec6e6..124537b971e 100644 --- a/tests/ui/coroutine/issue-68112.stderr +++ b/tests/ui/coroutine/issue-68112.stderr @@ -4,7 +4,7 @@ error: coroutine cannot be sent between threads safely LL | require_send(send_gen); | ^^^^^^^^^^^^^^^^^^^^^^ coroutine is not `Send` | - = help: the trait `Sync` is not implemented for `RefCell<i32>`, which is required by `{coroutine@$DIR/issue-68112.rs:33:33: 33:35}: Send` + = help: the trait `Sync` is not implemented for `RefCell<i32>` = note: if you want to do aliasing and mutation between multiple threads, use `std::sync::RwLock` instead note: coroutine is not `Send` as this value is used across a yield --> $DIR/issue-68112.rs:36:9 @@ -26,7 +26,7 @@ error[E0277]: `RefCell<i32>` cannot be shared between threads safely LL | require_send(send_gen); | ^^^^^^^^^^^^^^^^^^^^^^ `RefCell<i32>` cannot be shared between threads safely | - = help: the trait `Sync` is not implemented for `RefCell<i32>`, which is required by `{coroutine@$DIR/issue-68112.rs:60:33: 60:35}: Send` + = help: the trait `Sync` is not implemented for `RefCell<i32>` = note: if you want to do aliasing and mutation between multiple threads, use `std::sync::RwLock` instead = note: required for `Arc<RefCell<i32>>` to implement `Send` note: required because it's used within this coroutine diff --git a/tests/ui/coroutine/not-send-sync.stderr b/tests/ui/coroutine/not-send-sync.stderr index 0f9cbdec130..c6d2ac0a557 100644 --- a/tests/ui/coroutine/not-send-sync.stderr +++ b/tests/ui/coroutine/not-send-sync.stderr @@ -9,7 +9,7 @@ LL | | drop(a); LL | | }); | |______^ coroutine is not `Sync` | - = help: within `{coroutine@$DIR/not-send-sync.rs:14:30: 14:32}`, the trait `Sync` is not implemented for `NotSync`, which is required by `{coroutine@$DIR/not-send-sync.rs:14:30: 14:32}: Sync` + = help: within `{coroutine@$DIR/not-send-sync.rs:14:30: 14:32}`, the trait `Sync` is not implemented for `NotSync` note: coroutine is not `Sync` as this value is used across a yield --> $DIR/not-send-sync.rs:17:9 | @@ -34,7 +34,7 @@ LL | | drop(a); LL | | }); | |______^ coroutine is not `Send` | - = help: within `{coroutine@$DIR/not-send-sync.rs:21:30: 21:32}`, the trait `Send` is not implemented for `NotSend`, which is required by `{coroutine@$DIR/not-send-sync.rs:21:30: 21:32}: Send` + = help: within `{coroutine@$DIR/not-send-sync.rs:21:30: 21:32}`, the trait `Send` is not implemented for `NotSend` note: coroutine is not `Send` as this value is used across a yield --> $DIR/not-send-sync.rs:24:9 | diff --git a/tests/ui/coroutine/parent-expression.stderr b/tests/ui/coroutine/parent-expression.stderr index 2d817f1bfd9..770ffda7a26 100644 --- a/tests/ui/coroutine/parent-expression.stderr +++ b/tests/ui/coroutine/parent-expression.stderr @@ -13,7 +13,7 @@ LL | | }; LL | | ); | |_____- in this macro invocation | - = help: within `{coroutine@$DIR/parent-expression.rs:17:34: 17:41}`, the trait `Send` is not implemented for `derived_drop::Client`, which is required by `{coroutine@$DIR/parent-expression.rs:17:34: 17:41}: Send` + = help: within `{coroutine@$DIR/parent-expression.rs:17:34: 17:41}`, the trait `Send` is not implemented for `derived_drop::Client` note: coroutine is not `Send` as this value is used across a yield --> $DIR/parent-expression.rs:21:22 | @@ -53,7 +53,7 @@ LL | | }; LL | | ); | |_____- in this macro invocation | - = help: within `{coroutine@$DIR/parent-expression.rs:17:34: 17:41}`, the trait `Send` is not implemented for `significant_drop::Client`, which is required by `{coroutine@$DIR/parent-expression.rs:17:34: 17:41}: Send` + = help: within `{coroutine@$DIR/parent-expression.rs:17:34: 17:41}`, the trait `Send` is not implemented for `significant_drop::Client` note: coroutine is not `Send` as this value is used across a yield --> $DIR/parent-expression.rs:21:22 | @@ -93,7 +93,7 @@ LL | | }; LL | | ); | |_____- in this macro invocation | - = help: within `{coroutine@$DIR/parent-expression.rs:17:34: 17:41}`, the trait `Send` is not implemented for `insignificant_dtor::Client`, which is required by `{coroutine@$DIR/parent-expression.rs:17:34: 17:41}: Send` + = help: within `{coroutine@$DIR/parent-expression.rs:17:34: 17:41}`, the trait `Send` is not implemented for `insignificant_dtor::Client` note: coroutine is not `Send` as this value is used across a yield --> $DIR/parent-expression.rs:21:22 | diff --git a/tests/ui/coroutine/print/coroutine-print-verbose-1.stderr b/tests/ui/coroutine/print/coroutine-print-verbose-1.stderr index daf88fc1f23..410189b9ab6 100644 --- a/tests/ui/coroutine/print/coroutine-print-verbose-1.stderr +++ b/tests/ui/coroutine/print/coroutine-print-verbose-1.stderr @@ -4,7 +4,7 @@ error: coroutine cannot be sent between threads safely LL | require_send(send_gen); | ^^^^^^^^^^^^^^^^^^^^^^ coroutine is not `Send` | - = help: the trait `Sync` is not implemented for `RefCell<i32>`, which is required by `{test1::{closure#0} upvar_tys=() witness={test1::{closure#0}}}: Send` + = help: the trait `Sync` is not implemented for `RefCell<i32>` = note: if you want to do aliasing and mutation between multiple threads, use `std::sync::RwLock` instead note: coroutine is not `Send` as this value is used across a yield --> $DIR/coroutine-print-verbose-1.rs:35:9 @@ -25,7 +25,7 @@ error[E0277]: `RefCell<i32>` cannot be shared between threads safely LL | require_send(send_gen); | ^^^^^^^^^^^^^^^^^^^^^^ `RefCell<i32>` cannot be shared between threads safely | - = help: the trait `Sync` is not implemented for `RefCell<i32>`, which is required by `{test2::{closure#0} upvar_tys=() witness={test2::{closure#0}}}: Send` + = help: the trait `Sync` is not implemented for `RefCell<i32>` = note: if you want to do aliasing and mutation between multiple threads, use `std::sync::RwLock` instead = note: required for `Arc<RefCell<i32>>` to implement `Send` note: required because it's used within this coroutine diff --git a/tests/ui/coroutine/print/coroutine-print-verbose-2.stderr b/tests/ui/coroutine/print/coroutine-print-verbose-2.stderr index 0de53d9e1d7..2ab9d35f05a 100644 --- a/tests/ui/coroutine/print/coroutine-print-verbose-2.stderr +++ b/tests/ui/coroutine/print/coroutine-print-verbose-2.stderr @@ -9,7 +9,7 @@ LL | | drop(a); LL | | }); | |______^ coroutine is not `Sync` | - = help: within `{main::{closure#0} upvar_tys=() witness={main::{closure#0}}}`, the trait `Sync` is not implemented for `NotSync`, which is required by `{main::{closure#0} upvar_tys=() witness={main::{closure#0}}}: Sync` + = help: within `{main::{closure#0} upvar_tys=() witness={main::{closure#0}}}`, the trait `Sync` is not implemented for `NotSync` note: coroutine is not `Sync` as this value is used across a yield --> $DIR/coroutine-print-verbose-2.rs:20:9 | @@ -34,7 +34,7 @@ LL | | drop(a); LL | | }); | |______^ coroutine is not `Send` | - = help: within `{main::{closure#1} upvar_tys=() witness={main::{closure#1}}}`, the trait `Send` is not implemented for `NotSend`, which is required by `{main::{closure#1} upvar_tys=() witness={main::{closure#1}}}: Send` + = help: within `{main::{closure#1} upvar_tys=() witness={main::{closure#1}}}`, the trait `Send` is not implemented for `NotSend` note: coroutine is not `Send` as this value is used across a yield --> $DIR/coroutine-print-verbose-2.rs:27:9 | diff --git a/tests/ui/coroutine/ref-upvar-not-send.stderr b/tests/ui/coroutine/ref-upvar-not-send.stderr index 4c7deab3f4c..892b5d261c2 100644 --- a/tests/ui/coroutine/ref-upvar-not-send.stderr +++ b/tests/ui/coroutine/ref-upvar-not-send.stderr @@ -10,7 +10,7 @@ LL | | let _x = x; LL | | }); | |_____^ coroutine is not `Send` | - = help: the trait `Sync` is not implemented for `*mut ()`, which is required by `{coroutine@$DIR/ref-upvar-not-send.rs:15:30: 15:37}: Send` + = help: the trait `Sync` is not implemented for `*mut ()` note: captured value is not `Send` because `&` references cannot be sent unless their referent is `Sync` --> $DIR/ref-upvar-not-send.rs:19:18 | @@ -34,7 +34,7 @@ LL | | let _y = y; LL | | }); | |_____^ coroutine is not `Send` | - = help: within `{coroutine@$DIR/ref-upvar-not-send.rs:23:30: 23:37}`, the trait `Send` is not implemented for `*mut ()`, which is required by `{coroutine@$DIR/ref-upvar-not-send.rs:23:30: 23:37}: Send` + = help: within `{coroutine@$DIR/ref-upvar-not-send.rs:23:30: 23:37}`, the trait `Send` is not implemented for `*mut ()` note: captured value is not `Send` because `&mut` references cannot be sent unless their referent is `Send` --> $DIR/ref-upvar-not-send.rs:27:18 | diff --git a/tests/ui/coroutine/resume-arg-outlives-2.rs b/tests/ui/coroutine/resume-arg-outlives-2.rs new file mode 100644 index 00000000000..387b143ea27 --- /dev/null +++ b/tests/ui/coroutine/resume-arg-outlives-2.rs @@ -0,0 +1,34 @@ +// Regression test for 132104 + +#![feature(coroutine_trait, coroutines)] + +use std::ops::Coroutine; +use std::{thread, time}; + +fn demo<'not_static>(s: &'not_static str) -> thread::JoinHandle<()> { + let mut generator = Box::pin({ + #[coroutine] + move |_ctx| { + let ctx: &'not_static str = yield; + yield; + dbg!(ctx); + } + }); + + // exploit: + generator.as_mut().resume(""); + generator.as_mut().resume(s); // <- generator hoards it as `let ctx`. + //~^ ERROR borrowed data escapes outside of function + thread::spawn(move || { + thread::sleep(time::Duration::from_millis(200)); + generator.as_mut().resume(""); // <- resumes from the last `yield`, running `dbg!(ctx)`. + }) +} + +fn main() { + let local = String::from("..."); + let thread = demo(&local); + drop(local); + let _unrelated = String::from("UAF"); + thread.join().unwrap(); +} diff --git a/tests/ui/coroutine/resume-arg-outlives-2.stderr b/tests/ui/coroutine/resume-arg-outlives-2.stderr new file mode 100644 index 00000000000..3d630d7e7e4 --- /dev/null +++ b/tests/ui/coroutine/resume-arg-outlives-2.stderr @@ -0,0 +1,17 @@ +error[E0521]: borrowed data escapes outside of function + --> $DIR/resume-arg-outlives-2.rs:20:5 + | +LL | fn demo<'not_static>(s: &'not_static str) -> thread::JoinHandle<()> { + | ----------- - `s` is a reference that is only valid in the function body + | | + | lifetime `'not_static` defined here +... +LL | generator.as_mut().resume(s); // <- generator hoards it as `let ctx`. + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + | | + | `s` escapes the function body here + | argument requires that `'not_static` must outlive `'static` + +error: aborting due to 1 previous error + +For more information about this error, try `rustc --explain E0521`. diff --git a/tests/ui/coroutine/resume-arg-outlives.rs b/tests/ui/coroutine/resume-arg-outlives.rs new file mode 100644 index 00000000000..258be28e063 --- /dev/null +++ b/tests/ui/coroutine/resume-arg-outlives.rs @@ -0,0 +1,27 @@ +// Regression test for 132104 + +#![feature(coroutine_trait, coroutines)] + +use std::ops::Coroutine; +use std::pin::Pin; + +fn demo<'not_static>(s: &'not_static str) -> Pin<Box<impl Coroutine<&'not_static str> + 'static>> { + let mut generator = Box::pin({ + #[coroutine] + move |ctx: &'not_static str| { + yield; + dbg!(ctx); + } + }); + generator.as_mut().resume(s); + generator + //~^ ERROR lifetime may not live long enough +} + +fn main() { + let local = String::from("..."); + let mut coro = demo(&local); + drop(local); + let _unrelated = String::from("UAF"); + coro.as_mut().resume(""); +} diff --git a/tests/ui/coroutine/resume-arg-outlives.stderr b/tests/ui/coroutine/resume-arg-outlives.stderr new file mode 100644 index 00000000000..2a6337b4945 --- /dev/null +++ b/tests/ui/coroutine/resume-arg-outlives.stderr @@ -0,0 +1,20 @@ +error: lifetime may not live long enough + --> $DIR/resume-arg-outlives.rs:17:5 + | +LL | fn demo<'not_static>(s: &'not_static str) -> Pin<Box<impl Coroutine<&'not_static str> + 'static>> { + | ----------- lifetime `'not_static` defined here +... +LL | generator + | ^^^^^^^^^ returning this value requires that `'not_static` must outlive `'static` + | +help: consider changing `impl Coroutine<&'not_static str> + 'static`'s explicit `'static` bound to the lifetime of argument `s` + | +LL | fn demo<'not_static>(s: &'not_static str) -> Pin<Box<impl Coroutine<&'not_static str> + 'not_static>> { + | ~~~~~~~~~~~ +help: alternatively, add an explicit `'static` bound to this reference + | +LL | fn demo<'not_static>(s: &'static str) -> Pin<Box<impl Coroutine<&'not_static str> + 'static>> { + | ~~~~~~~~~~~~ + +error: aborting due to 1 previous error + diff --git a/tests/ui/coroutine/unresolved-ct-var.stderr b/tests/ui/coroutine/unresolved-ct-var.stderr index 8b87bac05ac..da2ec272f9f 100644 --- a/tests/ui/coroutine/unresolved-ct-var.stderr +++ b/tests/ui/coroutine/unresolved-ct-var.stderr @@ -8,7 +8,7 @@ LL | let s = std::array::from_fn(|_| ()).await; | | help: remove the `.await` | this call returns `[(); _]` | - = help: the trait `Future` is not implemented for `[(); _]`, which is required by `[(); _]: IntoFuture` + = help: the trait `Future` is not implemented for `[(); _]` = note: [(); _] must be a future or must implement `IntoFuture` to be awaited = note: required for `[(); _]` to implement `IntoFuture` diff --git a/tests/ui/coroutine/yield-outside-coroutine-issue-78653.stderr b/tests/ui/coroutine/yield-outside-coroutine-issue-78653.stderr index 921e8d5d47a..b288e581d88 100644 --- a/tests/ui/coroutine/yield-outside-coroutine-issue-78653.stderr +++ b/tests/ui/coroutine/yield-outside-coroutine-issue-78653.stderr @@ -21,7 +21,7 @@ error[E0277]: `{integer}` is not an iterator LL | yield || for i in 0 { } | ^ `{integer}` is not an iterator | - = help: the trait `Iterator` is not implemented for `{integer}`, which is required by `{integer}: IntoIterator` + = help: the trait `Iterator` is not implemented for `{integer}` = note: if you want to iterate between `start` until a value `end`, use the exclusive range syntax `start..end` or the inclusive range syntax `start..=end` = note: required for `{integer}` to implement `IntoIterator` diff --git a/tests/ui/delegation/unsupported.stderr b/tests/ui/delegation/unsupported.stderr index 1c79a603503..2f64d23b8d2 100644 --- a/tests/ui/delegation/unsupported.stderr +++ b/tests/ui/delegation/unsupported.stderr @@ -1,8 +1,3 @@ -error: using `#![feature(effects)]` without enabling next trait solver globally - | - = note: the next trait solver must be enabled globally for the effects feature to work correctly - = help: use `-Znext-solver` to enable - error[E0391]: cycle detected when computing type of `opaque::<impl at $DIR/unsupported.rs:26:5: 26:24>::{synthetic#0}` --> $DIR/unsupported.rs:27:25 | @@ -89,7 +84,7 @@ LL | reuse Trait::foo; | = note: cannot satisfy `_: effects::Trait` -error: aborting due to 5 previous errors; 2 warnings emitted +error: aborting due to 4 previous errors; 2 warnings emitted Some errors have detailed explanations: E0283, E0391. For more information about an error, try `rustc --explain E0283`. diff --git a/tests/ui/derives/derives-span-Debug-enum-struct-variant.stderr b/tests/ui/derives/derives-span-Debug-enum-struct-variant.stderr index b10805ac8f0..3f6c39bf939 100644 --- a/tests/ui/derives/derives-span-Debug-enum-struct-variant.stderr +++ b/tests/ui/derives/derives-span-Debug-enum-struct-variant.stderr @@ -7,7 +7,7 @@ LL | #[derive(Debug)] LL | x: Error | ^^^^^^^^ `Error` cannot be formatted using `{:?}` | - = help: the trait `Debug` is not implemented for `Error`, which is required by `&Error: Debug` + = help: the trait `Debug` is not implemented for `Error` = note: add `#[derive(Debug)]` to `Error` or manually `impl Debug for Error` = note: this error originates in the derive macro `Debug` (in Nightly builds, run with -Z macro-backtrace for more info) help: consider annotating `Error` with `#[derive(Debug)]` diff --git a/tests/ui/derives/derives-span-Debug-enum.stderr b/tests/ui/derives/derives-span-Debug-enum.stderr index 03297443901..eaeffaeb849 100644 --- a/tests/ui/derives/derives-span-Debug-enum.stderr +++ b/tests/ui/derives/derives-span-Debug-enum.stderr @@ -7,7 +7,7 @@ LL | #[derive(Debug)] LL | Error | ^^^^^ `Error` cannot be formatted using `{:?}` | - = help: the trait `Debug` is not implemented for `Error`, which is required by `&Error: Debug` + = help: the trait `Debug` is not implemented for `Error` = note: add `#[derive(Debug)]` to `Error` or manually `impl Debug for Error` = note: this error originates in the derive macro `Debug` (in Nightly builds, run with -Z macro-backtrace for more info) help: consider annotating `Error` with `#[derive(Debug)]` diff --git a/tests/ui/derives/derives-span-Debug-struct.stderr b/tests/ui/derives/derives-span-Debug-struct.stderr index 369c0b56ac4..4a725e260de 100644 --- a/tests/ui/derives/derives-span-Debug-struct.stderr +++ b/tests/ui/derives/derives-span-Debug-struct.stderr @@ -7,7 +7,7 @@ LL | struct Struct { LL | x: Error | ^^^^^^^^ `Error` cannot be formatted using `{:?}` | - = help: the trait `Debug` is not implemented for `Error`, which is required by `&Error: Debug` + = help: the trait `Debug` is not implemented for `Error` = note: add `#[derive(Debug)]` to `Error` or manually `impl Debug for Error` = note: this error originates in the derive macro `Debug` (in Nightly builds, run with -Z macro-backtrace for more info) help: consider annotating `Error` with `#[derive(Debug)]` diff --git a/tests/ui/derives/derives-span-Debug-tuple-struct.stderr b/tests/ui/derives/derives-span-Debug-tuple-struct.stderr index abfef9ef354..2f816e1c85b 100644 --- a/tests/ui/derives/derives-span-Debug-tuple-struct.stderr +++ b/tests/ui/derives/derives-span-Debug-tuple-struct.stderr @@ -7,7 +7,7 @@ LL | struct Struct( LL | Error | ^^^^^ `Error` cannot be formatted using `{:?}` | - = help: the trait `Debug` is not implemented for `Error`, which is required by `&Error: Debug` + = help: the trait `Debug` is not implemented for `Error` = note: add `#[derive(Debug)]` to `Error` or manually `impl Debug for Error` = note: this error originates in the derive macro `Debug` (in Nightly builds, run with -Z macro-backtrace for more info) help: consider annotating `Error` with `#[derive(Debug)]` diff --git a/tests/ui/deriving/auxiliary/another-proc-macro.rs b/tests/ui/deriving/auxiliary/another-proc-macro.rs index a05175c9de9..c992cde4066 100644 --- a/tests/ui/deriving/auxiliary/another-proc-macro.rs +++ b/tests/ui/deriving/auxiliary/another-proc-macro.rs @@ -6,7 +6,7 @@ extern crate proc_macro; -use proc_macro::{quote, TokenStream}; +use proc_macro::{TokenStream, quote}; #[proc_macro_derive(AnotherMacro, attributes(pointee))] pub fn derive(_input: TokenStream) -> TokenStream { diff --git a/tests/ui/deriving/built-in-proc-macro-scope.rs b/tests/ui/deriving/built-in-proc-macro-scope.rs index 41c95f63b13..6c473aefc5b 100644 --- a/tests/ui/deriving/built-in-proc-macro-scope.rs +++ b/tests/ui/deriving/built-in-proc-macro-scope.rs @@ -2,14 +2,14 @@ //@ aux-build: another-proc-macro.rs //@ compile-flags: -Zunpretty=expanded -#![feature(derive_smart_pointer)] +#![feature(derive_coerce_pointee)] #[macro_use] extern crate another_proc_macro; -use another_proc_macro::{pointee, AnotherMacro}; +use another_proc_macro::{AnotherMacro, pointee}; -#[derive(core::marker::SmartPointer)] +#[derive(core::marker::CoercePointee)] #[repr(transparent)] pub struct Ptr<'a, #[pointee] T: ?Sized> { data: &'a mut T, diff --git a/tests/ui/deriving/built-in-proc-macro-scope.stdout b/tests/ui/deriving/built-in-proc-macro-scope.stdout index c649b7a9a57..07767dc229f 100644 --- a/tests/ui/deriving/built-in-proc-macro-scope.stdout +++ b/tests/ui/deriving/built-in-proc-macro-scope.stdout @@ -4,7 +4,7 @@ //@ aux-build: another-proc-macro.rs //@ compile-flags: -Zunpretty=expanded -#![feature(derive_smart_pointer)] +#![feature(derive_coerce_pointee)] #[prelude_import] use ::std::prelude::rust_2015::*; #[macro_use] @@ -13,7 +13,7 @@ extern crate std; #[macro_use] extern crate another_proc_macro; -use another_proc_macro::{pointee, AnotherMacro}; +use another_proc_macro::{AnotherMacro, pointee}; #[repr(transparent)] pub struct Ptr<'a, #[pointee] T: ?Sized> { diff --git a/tests/ui/deriving/smart-pointer-bounds-issue-127647.rs b/tests/ui/deriving/coerce-pointee-bounds-issue-127647.rs index 4cae1b32896..a1aabf1cb52 100644 --- a/tests/ui/deriving/smart-pointer-bounds-issue-127647.rs +++ b/tests/ui/deriving/coerce-pointee-bounds-issue-127647.rs @@ -1,8 +1,8 @@ //@ check-pass -#![feature(derive_smart_pointer)] +#![feature(derive_coerce_pointee)] -#[derive(core::marker::SmartPointer)] +#[derive(core::marker::CoercePointee)] #[repr(transparent)] pub struct Ptr<'a, #[pointee] T: OnDrop + ?Sized, X> { data: &'a mut T, @@ -13,7 +13,7 @@ pub trait OnDrop { fn on_drop(&mut self); } -#[derive(core::marker::SmartPointer)] +#[derive(core::marker::CoercePointee)] #[repr(transparent)] pub struct Ptr2<'a, #[pointee] T: ?Sized, X> where @@ -25,7 +25,7 @@ where pub trait MyTrait<T: ?Sized> {} -#[derive(core::marker::SmartPointer)] +#[derive(core::marker::CoercePointee)] #[repr(transparent)] pub struct Ptr3<'a, #[pointee] T: ?Sized, X> where @@ -35,14 +35,14 @@ where x: core::marker::PhantomData<X>, } -#[derive(core::marker::SmartPointer)] +#[derive(core::marker::CoercePointee)] #[repr(transparent)] pub struct Ptr4<'a, #[pointee] T: MyTrait<T> + ?Sized, X> { data: &'a mut T, x: core::marker::PhantomData<X>, } -#[derive(core::marker::SmartPointer)] +#[derive(core::marker::CoercePointee)] #[repr(transparent)] pub struct Ptr5<'a, #[pointee] T: ?Sized, X> where @@ -56,7 +56,7 @@ where pub struct Ptr5Companion<T: ?Sized>(core::marker::PhantomData<T>); pub struct Ptr5Companion2; -#[derive(core::marker::SmartPointer)] +#[derive(core::marker::CoercePointee)] #[repr(transparent)] pub struct Ptr6<'a, #[pointee] T: ?Sized, X: MyTrait<T> = (), const PARAM: usize = 0> { data: &'a mut T, @@ -65,7 +65,7 @@ pub struct Ptr6<'a, #[pointee] T: ?Sized, X: MyTrait<T> = (), const PARAM: usize // a reduced example from https://lore.kernel.org/all/20240402-linked-list-v1-1-b1c59ba7ae3b@google.com/ #[repr(transparent)] -#[derive(core::marker::SmartPointer)] +#[derive(core::marker::CoercePointee)] pub struct ListArc<#[pointee] T, const ID: u64 = 0> where T: ListArcSafe<ID> + ?Sized, diff --git a/tests/ui/deriving/deriving-smart-pointer-expanded.rs b/tests/ui/deriving/deriving-coerce-pointee-expanded.rs index e48ad3dd4bc..94be7031fb7 100644 --- a/tests/ui/deriving/deriving-smart-pointer-expanded.rs +++ b/tests/ui/deriving/deriving-coerce-pointee-expanded.rs @@ -1,17 +1,17 @@ //@ check-pass //@ compile-flags: -Zunpretty=expanded -#![feature(derive_smart_pointer)] -use std::marker::SmartPointer; +#![feature(derive_coerce_pointee)] +use std::marker::CoercePointee; pub trait MyTrait<T: ?Sized> {} -#[derive(SmartPointer)] +#[derive(CoercePointee)] #[repr(transparent)] struct MyPointer<'a, #[pointee] T: ?Sized> { ptr: &'a T, } -#[derive(core::marker::SmartPointer)] +#[derive(core::marker::CoercePointee)] #[repr(transparent)] pub struct MyPointer2<'a, Y, Z: MyTrait<T>, #[pointee] T: ?Sized + MyTrait<T>, X: MyTrait<T> = ()> where @@ -21,7 +21,7 @@ where x: core::marker::PhantomData<X>, } -#[derive(SmartPointer)] +#[derive(CoercePointee)] #[repr(transparent)] struct MyPointerWithoutPointee<'a, T: ?Sized> { ptr: &'a T, diff --git a/tests/ui/deriving/deriving-smart-pointer-expanded.stdout b/tests/ui/deriving/deriving-coerce-pointee-expanded.stdout index 68ef17f2b05..d6eaca5cba1 100644 --- a/tests/ui/deriving/deriving-smart-pointer-expanded.stdout +++ b/tests/ui/deriving/deriving-coerce-pointee-expanded.stdout @@ -2,12 +2,12 @@ #![no_std] //@ check-pass //@ compile-flags: -Zunpretty=expanded -#![feature(derive_smart_pointer)] +#![feature(derive_coerce_pointee)] #[prelude_import] use ::std::prelude::rust_2015::*; #[macro_use] extern crate std; -use std::marker::SmartPointer; +use std::marker::CoercePointee; pub trait MyTrait<T: ?Sized> {} diff --git a/tests/ui/deriving/deriving-smart-pointer-neg.rs b/tests/ui/deriving/deriving-coerce-pointee-neg.rs index 41d3039236f..deef35cdf70 100644 --- a/tests/ui/deriving/deriving-smart-pointer-neg.rs +++ b/tests/ui/deriving/deriving-coerce-pointee-neg.rs @@ -1,115 +1,131 @@ -#![feature(derive_smart_pointer, arbitrary_self_types)] +#![feature(derive_coerce_pointee, arbitrary_self_types)] extern crate core; -use std::marker::SmartPointer; +use std::marker::CoercePointee; -#[derive(SmartPointer)] -//~^ ERROR: `SmartPointer` can only be derived on `struct`s with `#[repr(transparent)]` +#[derive(CoercePointee)] +//~^ ERROR: `CoercePointee` can only be derived on `struct`s with `#[repr(transparent)]` enum NotStruct<'a, T: ?Sized> { Variant(&'a T), } -#[derive(SmartPointer)] -//~^ ERROR: `SmartPointer` can only be derived on `struct`s with at least one field +#[derive(CoercePointee)] +//~^ ERROR: `CoercePointee` can only be derived on `struct`s with at least one field #[repr(transparent)] struct NoField<'a, #[pointee] T: ?Sized> {} //~^ ERROR: lifetime parameter `'a` is never used //~| ERROR: type parameter `T` is never used -#[derive(SmartPointer)] -//~^ ERROR: `SmartPointer` can only be derived on `struct`s with at least one field +#[derive(CoercePointee)] +//~^ ERROR: `CoercePointee` can only be derived on `struct`s with at least one field #[repr(transparent)] struct NoFieldUnit<'a, #[pointee] T: ?Sized>(); //~^ ERROR: lifetime parameter `'a` is never used //~| ERROR: type parameter `T` is never used -#[derive(SmartPointer)] -//~^ ERROR: `SmartPointer` can only be derived on `struct`s that are generic over at least one type +#[derive(CoercePointee)] +//~^ ERROR: `CoercePointee` can only be derived on `struct`s that are generic over at least one type #[repr(transparent)] struct NoGeneric<'a>(&'a u8); -#[derive(SmartPointer)] -//~^ ERROR: exactly one generic type parameter must be marked as #[pointee] to derive SmartPointer traits +#[derive(CoercePointee)] +//~^ ERROR: exactly one generic type parameter must be marked as #[pointee] to derive CoercePointee traits #[repr(transparent)] struct AmbiguousPointee<'a, T1: ?Sized, T2: ?Sized> { a: (&'a T1, &'a T2), } -#[derive(SmartPointer)] +#[derive(CoercePointee)] #[repr(transparent)] struct TooManyPointees<'a, #[pointee] A: ?Sized, #[pointee] B: ?Sized>((&'a A, &'a B)); -//~^ ERROR: only one type parameter can be marked as `#[pointee]` when deriving SmartPointer traits +//~^ ERROR: only one type parameter can be marked as `#[pointee]` when deriving CoercePointee traits -#[derive(SmartPointer)] -//~^ ERROR: `SmartPointer` can only be derived on `struct`s with `#[repr(transparent)]` +#[derive(CoercePointee)] +//~^ ERROR: `CoercePointee` can only be derived on `struct`s with `#[repr(transparent)]` struct NotTransparent<'a, #[pointee] T: ?Sized> { ptr: &'a T, } -#[derive(SmartPointer)] +#[derive(CoercePointee)] #[repr(transparent)] struct NoMaybeSized<'a, #[pointee] T> { - //~^ ERROR: `derive(SmartPointer)` requires T to be marked `?Sized` + //~^ ERROR: `derive(CoercePointee)` requires T to be marked `?Sized` ptr: &'a T, } -#[derive(SmartPointer)] +#[derive(CoercePointee)] #[repr(transparent)] struct PointeeOnField<'a, #[pointee] T: ?Sized> { #[pointee] //~^ ERROR: the `#[pointee]` attribute may only be used on generic parameters - ptr: &'a T + ptr: &'a T, } -#[derive(SmartPointer)] +#[derive(CoercePointee)] #[repr(transparent)] -struct PointeeInTypeConstBlock<'a, T: ?Sized = [u32; const { struct UhOh<#[pointee] T>(T); 10 }]> { - //~^ ERROR: the `#[pointee]` attribute may only be used on generic parameters +struct PointeeInTypeConstBlock< + 'a, + T: ?Sized = [u32; const { + struct UhOh<#[pointee] T>(T); + //~^ ERROR: the `#[pointee]` attribute may only be used on generic parameters + 10 + }], +> { ptr: &'a T, } -#[derive(SmartPointer)] +#[derive(CoercePointee)] #[repr(transparent)] struct PointeeInConstConstBlock< 'a, T: ?Sized, - const V: u32 = { struct UhOh<#[pointee] T>(T); 10 }> - //~^ ERROR: the `#[pointee]` attribute may only be used on generic parameters -{ + const V: u32 = { + struct UhOh<#[pointee] T>(T); + //~^ ERROR: the `#[pointee]` attribute may only be used on generic parameters + 10 + }, +> { ptr: &'a T, } -#[derive(SmartPointer)] +#[derive(CoercePointee)] #[repr(transparent)] struct PointeeInAnotherTypeConstBlock<'a, #[pointee] T: ?Sized> { - ptr: PointeeInConstConstBlock<'a, T, { struct UhOh<#[pointee] T>(T); 0 }> - //~^ ERROR: the `#[pointee]` attribute may only be used on generic parameters + ptr: PointeeInConstConstBlock< + 'a, + T, + { + struct UhOh<#[pointee] T>(T); + //~^ ERROR: the `#[pointee]` attribute may only be used on generic parameters + 0 + }, + >, } // However, reordering attributes should work nevertheless. #[repr(transparent)] -#[derive(SmartPointer)] -struct ThisIsAPossibleSmartPointer<'a, #[pointee] T: ?Sized> { +#[derive(CoercePointee)] +struct ThisIsAPossibleCoercePointee<'a, #[pointee] T: ?Sized> { ptr: &'a T, } // Also, these paths to Sized should work -#[derive(SmartPointer)] +#[derive(CoercePointee)] #[repr(transparent)] struct StdSized<'a, #[pointee] T: ?std::marker::Sized> { ptr: &'a T, } -#[derive(SmartPointer)] +#[derive(CoercePointee)] #[repr(transparent)] struct CoreSized<'a, #[pointee] T: ?core::marker::Sized> { ptr: &'a T, } -#[derive(SmartPointer)] +#[derive(CoercePointee)] #[repr(transparent)] struct GlobalStdSized<'a, #[pointee] T: ?::std::marker::Sized> { ptr: &'a T, } -#[derive(SmartPointer)] +#[derive(CoercePointee)] #[repr(transparent)] struct GlobalCoreSized<'a, #[pointee] T: ?::core::marker::Sized> { ptr: &'a T, diff --git a/tests/ui/deriving/deriving-coerce-pointee-neg.stderr b/tests/ui/deriving/deriving-coerce-pointee-neg.stderr new file mode 100644 index 00000000000..e590d636d0e --- /dev/null +++ b/tests/ui/deriving/deriving-coerce-pointee-neg.stderr @@ -0,0 +1,119 @@ +error: `CoercePointee` can only be derived on `struct`s with `#[repr(transparent)]` + --> $DIR/deriving-coerce-pointee-neg.rs:6:10 + | +LL | #[derive(CoercePointee)] + | ^^^^^^^^^^^^^ + | + = note: this error originates in the derive macro `CoercePointee` (in Nightly builds, run with -Z macro-backtrace for more info) + +error: `CoercePointee` can only be derived on `struct`s with at least one field + --> $DIR/deriving-coerce-pointee-neg.rs:12:10 + | +LL | #[derive(CoercePointee)] + | ^^^^^^^^^^^^^ + | + = note: this error originates in the derive macro `CoercePointee` (in Nightly builds, run with -Z macro-backtrace for more info) + +error: `CoercePointee` can only be derived on `struct`s with at least one field + --> $DIR/deriving-coerce-pointee-neg.rs:19:10 + | +LL | #[derive(CoercePointee)] + | ^^^^^^^^^^^^^ + | + = note: this error originates in the derive macro `CoercePointee` (in Nightly builds, run with -Z macro-backtrace for more info) + +error: `CoercePointee` can only be derived on `struct`s that are generic over at least one type + --> $DIR/deriving-coerce-pointee-neg.rs:26:10 + | +LL | #[derive(CoercePointee)] + | ^^^^^^^^^^^^^ + | + = note: this error originates in the derive macro `CoercePointee` (in Nightly builds, run with -Z macro-backtrace for more info) + +error: exactly one generic type parameter must be marked as #[pointee] to derive CoercePointee traits + --> $DIR/deriving-coerce-pointee-neg.rs:31:10 + | +LL | #[derive(CoercePointee)] + | ^^^^^^^^^^^^^ + | + = note: this error originates in the derive macro `CoercePointee` (in Nightly builds, run with -Z macro-backtrace for more info) + +error: only one type parameter can be marked as `#[pointee]` when deriving CoercePointee traits + --> $DIR/deriving-coerce-pointee-neg.rs:40:39 + | +LL | struct TooManyPointees<'a, #[pointee] A: ?Sized, #[pointee] B: ?Sized>((&'a A, &'a B)); + | ^ ^ + +error: `CoercePointee` can only be derived on `struct`s with `#[repr(transparent)]` + --> $DIR/deriving-coerce-pointee-neg.rs:43:10 + | +LL | #[derive(CoercePointee)] + | ^^^^^^^^^^^^^ + | + = note: this error originates in the derive macro `CoercePointee` (in Nightly builds, run with -Z macro-backtrace for more info) + +error: `derive(CoercePointee)` requires T to be marked `?Sized` + --> $DIR/deriving-coerce-pointee-neg.rs:51:36 + | +LL | struct NoMaybeSized<'a, #[pointee] T> { + | ^ + +error: the `#[pointee]` attribute may only be used on generic parameters + --> $DIR/deriving-coerce-pointee-neg.rs:59:5 + | +LL | #[pointee] + | ^^^^^^^^^^ + +error: the `#[pointee]` attribute may only be used on generic parameters + --> $DIR/deriving-coerce-pointee-neg.rs:69:33 + | +LL | struct UhOh<#[pointee] T>(T); + | ^^^^^^^^^^ + +error: the `#[pointee]` attribute may only be used on generic parameters + --> $DIR/deriving-coerce-pointee-neg.rs:83:21 + | +LL | struct UhOh<#[pointee] T>(T); + | ^^^^^^^^^^ + +error: the `#[pointee]` attribute may only be used on generic parameters + --> $DIR/deriving-coerce-pointee-neg.rs:98:25 + | +LL | struct UhOh<#[pointee] T>(T); + | ^^^^^^^^^^ + +error[E0392]: lifetime parameter `'a` is never used + --> $DIR/deriving-coerce-pointee-neg.rs:15:16 + | +LL | struct NoField<'a, #[pointee] T: ?Sized> {} + | ^^ unused lifetime parameter + | + = help: consider removing `'a`, referring to it in a field, or using a marker such as `PhantomData` + +error[E0392]: type parameter `T` is never used + --> $DIR/deriving-coerce-pointee-neg.rs:15:31 + | +LL | struct NoField<'a, #[pointee] T: ?Sized> {} + | ^ unused type parameter + | + = help: consider removing `T`, referring to it in a field, or using a marker such as `PhantomData` + +error[E0392]: lifetime parameter `'a` is never used + --> $DIR/deriving-coerce-pointee-neg.rs:22:20 + | +LL | struct NoFieldUnit<'a, #[pointee] T: ?Sized>(); + | ^^ unused lifetime parameter + | + = help: consider removing `'a`, referring to it in a field, or using a marker such as `PhantomData` + +error[E0392]: type parameter `T` is never used + --> $DIR/deriving-coerce-pointee-neg.rs:22:35 + | +LL | struct NoFieldUnit<'a, #[pointee] T: ?Sized>(); + | ^ unused type parameter + | + = help: consider removing `T`, referring to it in a field, or using a marker such as `PhantomData` + +error: aborting due to 16 previous errors + +For more information about this error, try `rustc --explain E0392`. diff --git a/tests/ui/deriving/deriving-smart-pointer.rs b/tests/ui/deriving/deriving-coerce-pointee.rs index d34a502da68..26762e4d0fa 100644 --- a/tests/ui/deriving/deriving-smart-pointer.rs +++ b/tests/ui/deriving/deriving-coerce-pointee.rs @@ -1,9 +1,9 @@ //@ run-pass -#![feature(derive_smart_pointer, arbitrary_self_types)] +#![feature(derive_coerce_pointee, arbitrary_self_types)] -use std::marker::SmartPointer; +use std::marker::CoercePointee; -#[derive(SmartPointer)] +#[derive(CoercePointee)] #[repr(transparent)] struct MyPointer<'a, #[pointee] T: ?Sized> { ptr: &'a T, diff --git a/tests/ui/deriving/deriving-smart-pointer-neg.stderr b/tests/ui/deriving/deriving-smart-pointer-neg.stderr deleted file mode 100644 index 9ab117698c7..00000000000 --- a/tests/ui/deriving/deriving-smart-pointer-neg.stderr +++ /dev/null @@ -1,119 +0,0 @@ -error: `SmartPointer` can only be derived on `struct`s with `#[repr(transparent)]` - --> $DIR/deriving-smart-pointer-neg.rs:6:10 - | -LL | #[derive(SmartPointer)] - | ^^^^^^^^^^^^ - | - = note: this error originates in the derive macro `SmartPointer` (in Nightly builds, run with -Z macro-backtrace for more info) - -error: `SmartPointer` can only be derived on `struct`s with at least one field - --> $DIR/deriving-smart-pointer-neg.rs:12:10 - | -LL | #[derive(SmartPointer)] - | ^^^^^^^^^^^^ - | - = note: this error originates in the derive macro `SmartPointer` (in Nightly builds, run with -Z macro-backtrace for more info) - -error: `SmartPointer` can only be derived on `struct`s with at least one field - --> $DIR/deriving-smart-pointer-neg.rs:19:10 - | -LL | #[derive(SmartPointer)] - | ^^^^^^^^^^^^ - | - = note: this error originates in the derive macro `SmartPointer` (in Nightly builds, run with -Z macro-backtrace for more info) - -error: `SmartPointer` can only be derived on `struct`s that are generic over at least one type - --> $DIR/deriving-smart-pointer-neg.rs:26:10 - | -LL | #[derive(SmartPointer)] - | ^^^^^^^^^^^^ - | - = note: this error originates in the derive macro `SmartPointer` (in Nightly builds, run with -Z macro-backtrace for more info) - -error: exactly one generic type parameter must be marked as #[pointee] to derive SmartPointer traits - --> $DIR/deriving-smart-pointer-neg.rs:31:10 - | -LL | #[derive(SmartPointer)] - | ^^^^^^^^^^^^ - | - = note: this error originates in the derive macro `SmartPointer` (in Nightly builds, run with -Z macro-backtrace for more info) - -error: only one type parameter can be marked as `#[pointee]` when deriving SmartPointer traits - --> $DIR/deriving-smart-pointer-neg.rs:40:39 - | -LL | struct TooManyPointees<'a, #[pointee] A: ?Sized, #[pointee] B: ?Sized>((&'a A, &'a B)); - | ^ ^ - -error: `SmartPointer` can only be derived on `struct`s with `#[repr(transparent)]` - --> $DIR/deriving-smart-pointer-neg.rs:43:10 - | -LL | #[derive(SmartPointer)] - | ^^^^^^^^^^^^ - | - = note: this error originates in the derive macro `SmartPointer` (in Nightly builds, run with -Z macro-backtrace for more info) - -error: `derive(SmartPointer)` requires T to be marked `?Sized` - --> $DIR/deriving-smart-pointer-neg.rs:51:36 - | -LL | struct NoMaybeSized<'a, #[pointee] T> { - | ^ - -error: the `#[pointee]` attribute may only be used on generic parameters - --> $DIR/deriving-smart-pointer-neg.rs:59:5 - | -LL | #[pointee] - | ^^^^^^^^^^ - -error: the `#[pointee]` attribute may only be used on generic parameters - --> $DIR/deriving-smart-pointer-neg.rs:66:74 - | -LL | struct PointeeInTypeConstBlock<'a, T: ?Sized = [u32; const { struct UhOh<#[pointee] T>(T); 10 }]> { - | ^^^^^^^^^^ - -error: the `#[pointee]` attribute may only be used on generic parameters - --> $DIR/deriving-smart-pointer-neg.rs:76:34 - | -LL | const V: u32 = { struct UhOh<#[pointee] T>(T); 10 }> - | ^^^^^^^^^^ - -error: the `#[pointee]` attribute may only be used on generic parameters - --> $DIR/deriving-smart-pointer-neg.rs:85:56 - | -LL | ptr: PointeeInConstConstBlock<'a, T, { struct UhOh<#[pointee] T>(T); 0 }> - | ^^^^^^^^^^ - -error[E0392]: lifetime parameter `'a` is never used - --> $DIR/deriving-smart-pointer-neg.rs:15:16 - | -LL | struct NoField<'a, #[pointee] T: ?Sized> {} - | ^^ unused lifetime parameter - | - = help: consider removing `'a`, referring to it in a field, or using a marker such as `PhantomData` - -error[E0392]: type parameter `T` is never used - --> $DIR/deriving-smart-pointer-neg.rs:15:31 - | -LL | struct NoField<'a, #[pointee] T: ?Sized> {} - | ^ unused type parameter - | - = help: consider removing `T`, referring to it in a field, or using a marker such as `PhantomData` - -error[E0392]: lifetime parameter `'a` is never used - --> $DIR/deriving-smart-pointer-neg.rs:22:20 - | -LL | struct NoFieldUnit<'a, #[pointee] T: ?Sized>(); - | ^^ unused lifetime parameter - | - = help: consider removing `'a`, referring to it in a field, or using a marker such as `PhantomData` - -error[E0392]: type parameter `T` is never used - --> $DIR/deriving-smart-pointer-neg.rs:22:35 - | -LL | struct NoFieldUnit<'a, #[pointee] T: ?Sized>(); - | ^ unused type parameter - | - = help: consider removing `T`, referring to it in a field, or using a marker such as `PhantomData` - -error: aborting due to 16 previous errors - -For more information about this error, try `rustc --explain E0392`. diff --git a/tests/ui/deriving/issue-103157.stderr b/tests/ui/deriving/issue-103157.stderr index 612a7aff225..9754b0289c0 100644 --- a/tests/ui/deriving/issue-103157.stderr +++ b/tests/ui/deriving/issue-103157.stderr @@ -5,7 +5,7 @@ LL | #[derive(PartialEq, Eq)] | -- in this derive macro expansion ... LL | Float(Option<f64>), - | ^^^^^^^^^^^ the trait `Eq` is not implemented for `f64`, which is required by `Option<f64>: Eq` + | ^^^^^^^^^^^ the trait `Eq` is not implemented for `f64` | = help: the following other types implement trait `Eq`: i128 diff --git a/tests/ui/deriving/proc-macro-attribute-mixing.rs b/tests/ui/deriving/proc-macro-attribute-mixing.rs index 489665ebeb5..80a0d068ce7 100644 --- a/tests/ui/deriving/proc-macro-attribute-mixing.rs +++ b/tests/ui/deriving/proc-macro-attribute-mixing.rs @@ -1,5 +1,5 @@ // This test certify that we can mix attribute macros from Rust and external proc-macros. -// For instance, `#[derive(Default)]` uses `#[default]` and `#[derive(SmartPointer)]` uses +// For instance, `#[derive(Default)]` uses `#[default]` and `#[derive(CoercePointee)]` uses // `#[pointee]`. // The scoping rule should allow the use of the said two attributes when external proc-macros // are in scope. @@ -8,7 +8,7 @@ //@ aux-build: another-proc-macro.rs //@ compile-flags: -Zunpretty=expanded -#![feature(derive_smart_pointer)] +#![feature(derive_coerce_pointee)] #[macro_use] extern crate another_proc_macro; diff --git a/tests/ui/deriving/proc-macro-attribute-mixing.stdout b/tests/ui/deriving/proc-macro-attribute-mixing.stdout index f314f6efbe2..03128c6c957 100644 --- a/tests/ui/deriving/proc-macro-attribute-mixing.stdout +++ b/tests/ui/deriving/proc-macro-attribute-mixing.stdout @@ -1,7 +1,7 @@ #![feature(prelude_import)] #![no_std] // This test certify that we can mix attribute macros from Rust and external proc-macros. -// For instance, `#[derive(Default)]` uses `#[default]` and `#[derive(SmartPointer)]` uses +// For instance, `#[derive(Default)]` uses `#[default]` and `#[derive(CoercePointee)]` uses // `#[pointee]`. // The scoping rule should allow the use of the said two attributes when external proc-macros // are in scope. @@ -10,7 +10,7 @@ //@ aux-build: another-proc-macro.rs //@ compile-flags: -Zunpretty=expanded -#![feature(derive_smart_pointer)] +#![feature(derive_coerce_pointee)] #[prelude_import] use ::std::prelude::rust_2015::*; #[macro_use] diff --git a/tests/ui/drop/drop_order.rs b/tests/ui/drop/drop_order.rs index 29b68d666fc..7a999c7c330 100644 --- a/tests/ui/drop/drop_order.rs +++ b/tests/ui/drop/drop_order.rs @@ -4,8 +4,8 @@ //@ [edition2021] edition: 2021 //@ [edition2024] compile-flags: -Z unstable-options //@ [edition2024] edition: 2024 + #![feature(let_chains)] -#![cfg_attr(edition2024, feature(if_let_rescope))] use std::cell::RefCell; use std::convert::TryInto; diff --git a/tests/ui/drop/drop_order_if_let_rescope.rs b/tests/ui/drop/drop_order_if_let_rescope.rs index ae9f381820e..cea84bbaa2b 100644 --- a/tests/ui/drop/drop_order_if_let_rescope.rs +++ b/tests/ui/drop/drop_order_if_let_rescope.rs @@ -3,7 +3,6 @@ //@ compile-flags: -Z validate-mir -Zunstable-options #![feature(let_chains)] -#![feature(if_let_rescope)] use std::cell::RefCell; use std::convert::TryInto; diff --git a/tests/ui/drop/if-let-rescope-borrowck-suggestions.rs b/tests/ui/drop/if-let-rescope-borrowck-suggestions.rs index 2476f7cf258..e055c20d777 100644 --- a/tests/ui/drop/if-let-rescope-borrowck-suggestions.rs +++ b/tests/ui/drop/if-let-rescope-borrowck-suggestions.rs @@ -1,7 +1,6 @@ //@ edition: 2024 //@ compile-flags: -Z validate-mir -Zunstable-options -#![feature(if_let_rescope)] #![deny(if_let_rescope)] struct Droppy; diff --git a/tests/ui/drop/if-let-rescope-borrowck-suggestions.stderr b/tests/ui/drop/if-let-rescope-borrowck-suggestions.stderr index 0c6f1ea28d2..3c87e196af6 100644 --- a/tests/ui/drop/if-let-rescope-borrowck-suggestions.stderr +++ b/tests/ui/drop/if-let-rescope-borrowck-suggestions.stderr @@ -1,5 +1,5 @@ error[E0716]: temporary value dropped while borrowed - --> $DIR/if-let-rescope-borrowck-suggestions.rs:22:39 + --> $DIR/if-let-rescope-borrowck-suggestions.rs:21:39 | LL | do_something(if let Some(value) = Droppy.get_ref() { value } else { &0 }); | ^^^^^^ - temporary value is freed at the end of this statement @@ -7,7 +7,7 @@ LL | do_something(if let Some(value) = Droppy.get_ref() { value } else { &0 | creates a temporary value which is freed while still in use | note: lifetimes for temporaries generated in `if let`s have been shortened in Edition 2024 so that they are dropped here instead - --> $DIR/if-let-rescope-borrowck-suggestions.rs:22:64 + --> $DIR/if-let-rescope-borrowck-suggestions.rs:21:64 | LL | do_something(if let Some(value) = Droppy.get_ref() { value } else { &0 }); | ^ @@ -22,7 +22,7 @@ LL | do_something({ match Droppy.get_ref() { Some(value) => { value } _ => | ~~~~~~~ ++++++++++++++++ ~~~~ ++ error[E0716]: temporary value dropped while borrowed - --> $DIR/if-let-rescope-borrowck-suggestions.rs:24:39 + --> $DIR/if-let-rescope-borrowck-suggestions.rs:23:39 | LL | do_something(if let Some(value) = Droppy.get_ref() { | ^^^^^^ creates a temporary value which is freed while still in use @@ -31,7 +31,7 @@ LL | } else if let Some(value) = Droppy.get_ref() { | - temporary value is freed at the end of this statement | note: lifetimes for temporaries generated in `if let`s have been shortened in Edition 2024 so that they are dropped here instead - --> $DIR/if-let-rescope-borrowck-suggestions.rs:27:5 + --> $DIR/if-let-rescope-borrowck-suggestions.rs:26:5 | LL | } else if let Some(value) = Droppy.get_ref() { | ^ @@ -53,7 +53,7 @@ LL ~ }}}); | error[E0716]: temporary value dropped while borrowed - --> $DIR/if-let-rescope-borrowck-suggestions.rs:27:33 + --> $DIR/if-let-rescope-borrowck-suggestions.rs:26:33 | LL | } else if let Some(value) = Droppy.get_ref() { | ^^^^^^ creates a temporary value which is freed while still in use @@ -62,7 +62,7 @@ LL | } else { | - temporary value is freed at the end of this statement | note: lifetimes for temporaries generated in `if let`s have been shortened in Edition 2024 so that they are dropped here instead - --> $DIR/if-let-rescope-borrowck-suggestions.rs:30:5 + --> $DIR/if-let-rescope-borrowck-suggestions.rs:29:5 | LL | } else { | ^ diff --git a/tests/ui/drop/lint-if-let-rescope-gated.with_feature_gate.stderr b/tests/ui/drop/lint-if-let-rescope-gated.edition2021.stderr index 48b7f3e11a6..48b7f3e11a6 100644 --- a/tests/ui/drop/lint-if-let-rescope-gated.with_feature_gate.stderr +++ b/tests/ui/drop/lint-if-let-rescope-gated.edition2021.stderr diff --git a/tests/ui/drop/lint-if-let-rescope-gated.rs b/tests/ui/drop/lint-if-let-rescope-gated.rs index cef5de5a8fe..ba0246573b4 100644 --- a/tests/ui/drop/lint-if-let-rescope-gated.rs +++ b/tests/ui/drop/lint-if-let-rescope-gated.rs @@ -1,13 +1,13 @@ // This test checks that the lint `if_let_rescope` only actions -// when the feature gate is enabled. -// Edition 2021 is used here because the lint should work especially -// when edition migration towards 2024 is run. +// when Edition 2021 or prior is targeted here because the lint should work especially +// when edition migration towards 2024 is executed. -//@ revisions: with_feature_gate without_feature_gate -//@ [without_feature_gate] check-pass -//@ edition: 2021 +//@ revisions: edition2021 edition2024 +//@ [edition2021] edition: 2021 +//@ [edition2024] edition: 2024 +//@ [edition2024] compile-flags: -Zunstable-options +//@ [edition2024] check-pass -#![cfg_attr(with_feature_gate, feature(if_let_rescope))] #![deny(if_let_rescope)] #![allow(irrefutable_let_patterns)] @@ -25,10 +25,10 @@ impl Droppy { fn main() { if let Some(_value) = Droppy.get() { - //[with_feature_gate]~^ ERROR: `if let` assigns a shorter lifetime since Edition 2024 - //[with_feature_gate]~| HELP: a `match` with a single arm can preserve the drop order up to Edition 2021 - //[with_feature_gate]~| WARN: this changes meaning in Rust 2024 + //[edition2021]~^ ERROR: `if let` assigns a shorter lifetime since Edition 2024 + //[edition2021]~| HELP: a `match` with a single arm can preserve the drop order up to Edition 2021 + //[edition2021]~| WARN: this changes meaning in Rust 2024 } else { - //[with_feature_gate]~^ HELP: the value is now dropped here in Edition 2024 + //[edition2021]~^ HELP: the value is now dropped here in Edition 2024 } } diff --git a/tests/ui/drop/lint-if-let-rescope-with-macro.rs b/tests/ui/drop/lint-if-let-rescope-with-macro.rs index 282b3320d30..e7aeb81f4d1 100644 --- a/tests/ui/drop/lint-if-let-rescope-with-macro.rs +++ b/tests/ui/drop/lint-if-let-rescope-with-macro.rs @@ -4,7 +4,6 @@ //@ edition:2021 //@ compile-flags: -Z unstable-options -#![feature(if_let_rescope)] #![deny(if_let_rescope)] #![allow(irrefutable_let_patterns)] diff --git a/tests/ui/drop/lint-if-let-rescope-with-macro.stderr b/tests/ui/drop/lint-if-let-rescope-with-macro.stderr index 5fd0c61d17a..de6cf6e8500 100644 --- a/tests/ui/drop/lint-if-let-rescope-with-macro.stderr +++ b/tests/ui/drop/lint-if-let-rescope-with-macro.stderr @@ -1,5 +1,5 @@ error: `if let` assigns a shorter lifetime since Edition 2024 - --> $DIR/lint-if-let-rescope-with-macro.rs:13:12 + --> $DIR/lint-if-let-rescope-with-macro.rs:12:12 | LL | if let $p = $e { $($conseq)* } else { $($alt)* } | ^^^ @@ -16,7 +16,7 @@ LL | | }; = warning: this changes meaning in Rust 2024 = note: for more information, see issue #124085 <https://github.com/rust-lang/rust/issues/124085> help: the value is now dropped here in Edition 2024 - --> $DIR/lint-if-let-rescope-with-macro.rs:13:38 + --> $DIR/lint-if-let-rescope-with-macro.rs:12:38 | LL | if let $p = $e { $($conseq)* } else { $($alt)* } | ^ @@ -29,7 +29,7 @@ LL | | {} LL | | }; | |_____- in this macro invocation note: the lint level is defined here - --> $DIR/lint-if-let-rescope-with-macro.rs:8:9 + --> $DIR/lint-if-let-rescope-with-macro.rs:7:9 | LL | #![deny(if_let_rescope)] | ^^^^^^^^^^^^^^ diff --git a/tests/ui/drop/lint-if-let-rescope.fixed b/tests/ui/drop/lint-if-let-rescope.fixed index 199068d0fd2..fec2e3b2ae7 100644 --- a/tests/ui/drop/lint-if-let-rescope.fixed +++ b/tests/ui/drop/lint-if-let-rescope.fixed @@ -1,7 +1,7 @@ //@ run-rustfix #![deny(if_let_rescope)] -#![feature(if_let_rescope, stmt_expr_attributes)] +#![feature(stmt_expr_attributes)] #![allow(irrefutable_let_patterns, unused_parens)] fn droppy() -> Droppy { diff --git a/tests/ui/drop/lint-if-let-rescope.rs b/tests/ui/drop/lint-if-let-rescope.rs index 4c043c0266c..ee184695b97 100644 --- a/tests/ui/drop/lint-if-let-rescope.rs +++ b/tests/ui/drop/lint-if-let-rescope.rs @@ -1,7 +1,7 @@ //@ run-rustfix #![deny(if_let_rescope)] -#![feature(if_let_rescope, stmt_expr_attributes)] +#![feature(stmt_expr_attributes)] #![allow(irrefutable_let_patterns, unused_parens)] fn droppy() -> Droppy { diff --git a/tests/ui/dropck/const_drop_is_valid.stderr b/tests/ui/dropck/const_drop_is_valid.stderr index f15b7ba946d..2383a6668a8 100644 --- a/tests/ui/dropck/const_drop_is_valid.stderr +++ b/tests/ui/dropck/const_drop_is_valid.stderr @@ -17,11 +17,6 @@ LL | #![feature(effects)] = note: see issue #102090 <https://github.com/rust-lang/rust/issues/102090> for more information = note: `#[warn(incomplete_features)]` on by default -error: using `#![feature(effects)]` without enabling next trait solver globally - | - = note: the next trait solver must be enabled globally for the effects feature to work correctly - = help: use `-Znext-solver` to enable - error: const `impl` for trait `Drop` which is not marked with `#[const_trait]` --> $DIR/const_drop_is_valid.rs:6:12 | @@ -39,7 +34,7 @@ LL | impl const Drop for A {} | = help: implement the missing item: `fn drop(&mut self) { todo!() }` -error: aborting due to 4 previous errors; 1 warning emitted +error: aborting due to 3 previous errors; 1 warning emitted Some errors have detailed explanations: E0046, E0658. For more information about an error, try `rustc --explain E0046`. diff --git a/tests/ui/dst/dst-bad-deep-2.stderr b/tests/ui/dst/dst-bad-deep-2.stderr index 554e81bee10..c7e9854340f 100644 --- a/tests/ui/dst/dst-bad-deep-2.stderr +++ b/tests/ui/dst/dst-bad-deep-2.stderr @@ -4,7 +4,7 @@ error[E0277]: the size for values of type `[isize]` cannot be known at compilati LL | let h: &(([isize],),) = &(*g,); | ^^^^^ doesn't have a size known at compile-time | - = help: within `(([isize],),)`, the trait `Sized` is not implemented for `[isize]`, which is required by `(([isize],),): Sized` + = help: within `(([isize],),)`, the trait `Sized` is not implemented for `[isize]` = note: required because it appears within the type `([isize],)` = note: required because it appears within the type `(([isize],),)` = note: tuples must have a statically known size to be initialized diff --git a/tests/ui/dst/dst-bad-deep.stderr b/tests/ui/dst/dst-bad-deep.stderr index 4f180e593f8..1b0f9738ab0 100644 --- a/tests/ui/dst/dst-bad-deep.stderr +++ b/tests/ui/dst/dst-bad-deep.stderr @@ -4,7 +4,7 @@ error[E0277]: the size for values of type `[isize]` cannot be known at compilati LL | let h: &Fat<Fat<[isize]>> = &Fat { ptr: *g }; | ^^^^^^^^^^^^^^^ doesn't have a size known at compile-time | - = help: within `Fat<Fat<[isize]>>`, the trait `Sized` is not implemented for `[isize]`, which is required by `Fat<Fat<[isize]>>: Sized` + = help: within `Fat<Fat<[isize]>>`, the trait `Sized` is not implemented for `[isize]` note: required because it appears within the type `Fat<[isize]>` --> $DIR/dst-bad-deep.rs:6:8 | diff --git a/tests/ui/editions/edition-keywords-2015-2015-parsing.rs b/tests/ui/editions/edition-keywords-2015-2015-parsing.rs index 07104bdf217..4751d280467 100644 --- a/tests/ui/editions/edition-keywords-2015-2015-parsing.rs +++ b/tests/ui/editions/edition-keywords-2015-2015-parsing.rs @@ -13,8 +13,8 @@ pub fn check_async() { let mut r#async = 1; // OK r#async = consumes_async!(async); // OK - r#async = consumes_async!(r#async); //~ ERROR no rules expected the token `r#async` - r#async = consumes_async_raw!(async); //~ ERROR no rules expected the token `async` + r#async = consumes_async!(r#async); //~ ERROR no rules expected `r#async` + r#async = consumes_async_raw!(async); //~ ERROR no rules expected `async` r#async = consumes_async_raw!(r#async); // OK if passes_ident!(async) == 1 {} // OK diff --git a/tests/ui/editions/edition-keywords-2015-2015-parsing.stderr b/tests/ui/editions/edition-keywords-2015-2015-parsing.stderr index 39944622d07..2519a9fded2 100644 --- a/tests/ui/editions/edition-keywords-2015-2015-parsing.stderr +++ b/tests/ui/editions/edition-keywords-2015-2015-parsing.stderr @@ -1,4 +1,4 @@ -error: no rules expected the token `r#async` +error: no rules expected `r#async` --> $DIR/edition-keywords-2015-2015-parsing.rs:16:31 | LL | r#async = consumes_async!(r#async); @@ -10,7 +10,7 @@ note: while trying to match `async` LL | (async) => (1) | ^^^^^ -error: no rules expected the token `async` +error: no rules expected `async` --> $DIR/edition-keywords-2015-2015-parsing.rs:17:35 | LL | r#async = consumes_async_raw!(async); diff --git a/tests/ui/editions/edition-keywords-2015-2018-parsing.rs b/tests/ui/editions/edition-keywords-2015-2018-parsing.rs index 3c294f95cd2..4404ea26fb3 100644 --- a/tests/ui/editions/edition-keywords-2015-2018-parsing.rs +++ b/tests/ui/editions/edition-keywords-2015-2018-parsing.rs @@ -13,8 +13,8 @@ pub fn check_async() { let mut r#async = 1; // OK r#async = consumes_async!(async); // OK - r#async = consumes_async!(r#async); //~ ERROR no rules expected the token `r#async` - r#async = consumes_async_raw!(async); //~ ERROR no rules expected the token `async` + r#async = consumes_async!(r#async); //~ ERROR no rules expected `r#async` + r#async = consumes_async_raw!(async); //~ ERROR no rules expected `async` r#async = consumes_async_raw!(r#async); // OK if passes_ident!(async) == 1 {} // OK diff --git a/tests/ui/editions/edition-keywords-2015-2018-parsing.stderr b/tests/ui/editions/edition-keywords-2015-2018-parsing.stderr index fa83908e666..0c0e5738415 100644 --- a/tests/ui/editions/edition-keywords-2015-2018-parsing.stderr +++ b/tests/ui/editions/edition-keywords-2015-2018-parsing.stderr @@ -1,4 +1,4 @@ -error: no rules expected the token `r#async` +error: no rules expected `r#async` --> $DIR/edition-keywords-2015-2018-parsing.rs:16:31 | LL | r#async = consumes_async!(r#async); @@ -10,7 +10,7 @@ note: while trying to match `async` LL | (async) => (1) | ^^^^^ -error: no rules expected the token `async` +error: no rules expected `async` --> $DIR/edition-keywords-2015-2018-parsing.rs:17:35 | LL | r#async = consumes_async_raw!(async); diff --git a/tests/ui/editions/edition-keywords-2018-2015-parsing.rs b/tests/ui/editions/edition-keywords-2018-2015-parsing.rs index 59184543274..c346be50856 100644 --- a/tests/ui/editions/edition-keywords-2018-2015-parsing.rs +++ b/tests/ui/editions/edition-keywords-2018-2015-parsing.rs @@ -17,8 +17,8 @@ pub fn check_async() { let mut r#async = 1; // OK r#async = consumes_async!(async); // OK - r#async = consumes_async!(r#async); //~ ERROR no rules expected the token `r#async` - r#async = consumes_async_raw!(async); //~ ERROR no rules expected the token `async` + r#async = consumes_async!(r#async); //~ ERROR no rules expected `r#async` + r#async = consumes_async_raw!(async); //~ ERROR no rules expected keyword `async` r#async = consumes_async_raw!(r#async); // OK if passes_ident!(async) == 1 {} // FIXME: Edition hygiene bug, async here is 2018 and reserved diff --git a/tests/ui/editions/edition-keywords-2018-2015-parsing.stderr b/tests/ui/editions/edition-keywords-2018-2015-parsing.stderr index 42db75f6659..aed5837abea 100644 --- a/tests/ui/editions/edition-keywords-2018-2015-parsing.stderr +++ b/tests/ui/editions/edition-keywords-2018-2015-parsing.stderr @@ -20,19 +20,19 @@ help: escape `async` to use it as an identifier LL | module::r#async(); | ++ -error: no rules expected the token `r#async` +error: no rules expected `r#async` --> $DIR/edition-keywords-2018-2015-parsing.rs:20:31 | LL | r#async = consumes_async!(r#async); | ^^^^^^^ no rules expected this token in macro call | -note: while trying to match `async` +note: while trying to match keyword `async` --> $DIR/auxiliary/edition-kw-macro-2015.rs:17:6 | LL | (async) => (1) | ^^^^^ -error: no rules expected the token `async` +error: no rules expected keyword `async` --> $DIR/edition-keywords-2018-2015-parsing.rs:21:35 | LL | r#async = consumes_async_raw!(async); diff --git a/tests/ui/editions/edition-keywords-2018-2018-parsing.rs b/tests/ui/editions/edition-keywords-2018-2018-parsing.rs index 4975246fa94..b75b68b3feb 100644 --- a/tests/ui/editions/edition-keywords-2018-2018-parsing.rs +++ b/tests/ui/editions/edition-keywords-2018-2018-parsing.rs @@ -24,8 +24,8 @@ pub fn check_async() { let mut r#async = 1; // OK r#async = consumes_async!(async); // OK - r#async = consumes_async!(r#async); //~ ERROR no rules expected the token `r#async` - r#async = consumes_async_raw!(async); //~ ERROR no rules expected the token `async` + r#async = consumes_async!(r#async); //~ ERROR no rules expected `r#async` + r#async = consumes_async_raw!(async); //~ ERROR no rules expected keyword `async` r#async = consumes_async_raw!(r#async); // OK if passes_ident!(async) == 1 {} // FIXME: Edition hygiene bug, async here is 2018 and reserved diff --git a/tests/ui/editions/edition-keywords-2018-2018-parsing.stderr b/tests/ui/editions/edition-keywords-2018-2018-parsing.stderr index 4bbe1597233..6503e9cc73c 100644 --- a/tests/ui/editions/edition-keywords-2018-2018-parsing.stderr +++ b/tests/ui/editions/edition-keywords-2018-2018-parsing.stderr @@ -20,19 +20,19 @@ help: escape `async` to use it as an identifier LL | module::r#async(); | ++ -error: no rules expected the token `r#async` +error: no rules expected `r#async` --> $DIR/edition-keywords-2018-2018-parsing.rs:27:31 | LL | r#async = consumes_async!(r#async); | ^^^^^^^ no rules expected this token in macro call | -note: while trying to match `async` +note: while trying to match keyword `async` --> $DIR/auxiliary/edition-kw-macro-2018.rs:17:6 | LL | (async) => (1) | ^^^^^ -error: no rules expected the token `async` +error: no rules expected keyword `async` --> $DIR/edition-keywords-2018-2018-parsing.rs:28:35 | LL | r#async = consumes_async_raw!(async); diff --git a/tests/ui/error-codes/E0277-2.stderr b/tests/ui/error-codes/E0277-2.stderr index f4e18e3bb53..9a262f75590 100644 --- a/tests/ui/error-codes/E0277-2.stderr +++ b/tests/ui/error-codes/E0277-2.stderr @@ -4,7 +4,7 @@ error[E0277]: `*const u8` cannot be sent between threads safely LL | is_send::<Foo>(); | ^^^ `*const u8` cannot be sent between threads safely | - = help: within `Foo`, the trait `Send` is not implemented for `*const u8`, which is required by `Foo: Send` + = help: within `Foo`, the trait `Send` is not implemented for `*const u8` note: required because it appears within the type `Baz` --> $DIR/E0277-2.rs:9:8 | diff --git a/tests/ui/error-codes/E0277.stderr b/tests/ui/error-codes/E0277.stderr index 52ada36574e..a9ae8971df4 100644 --- a/tests/ui/error-codes/E0277.stderr +++ b/tests/ui/error-codes/E0277.stderr @@ -4,7 +4,7 @@ error[E0277]: the size for values of type `[u8]` cannot be known at compilation LL | fn f(p: Path) { } | ^^^^ doesn't have a size known at compile-time | - = help: within `Path`, the trait `Sized` is not implemented for `[u8]`, which is required by `Path: Sized` + = help: within `Path`, the trait `Sized` is not implemented for `[u8]` note: required because it appears within the type `Path` --> $SRC_DIR/std/src/path.rs:LL:COL = help: unsized fn params are gated as an unstable feature diff --git a/tests/ui/errors/trait-bound-error-spans/blame-trait-error.stderr b/tests/ui/errors/trait-bound-error-spans/blame-trait-error.stderr index bd4e9348227..9228a047e87 100644 --- a/tests/ui/errors/trait-bound-error-spans/blame-trait-error.stderr +++ b/tests/ui/errors/trait-bound-error-spans/blame-trait-error.stderr @@ -2,7 +2,7 @@ error[E0277]: the trait bound `Q: T3` is not satisfied --> $DIR/blame-trait-error.rs:53:46 | LL | want(Wrapper { value: Burrito { filling: q } }); - | ---- ^ the trait `T3` is not implemented for `Q`, which is required by `Wrapper<Burrito<Q>>: T1` + | ---- ^ the trait `T3` is not implemented for `Q` | | | required by a bound introduced by this call | @@ -38,7 +38,7 @@ LL | want(Some(())); | | | required by a bound introduced by this call | - = help: the trait `Iterator` is not implemented for `()`, which is required by `Option<()>: T1` + = help: the trait `Iterator` is not implemented for `()` = help: the trait `T1` is implemented for `Option<It>` note: required for `Option<()>` to implement `T1` --> $DIR/blame-trait-error.rs:21:20 @@ -109,7 +109,7 @@ error[E0277]: the trait bound `Q: T3` is not satisfied --> $DIR/blame-trait-error.rs:65:45 | LL | want(&ExampleTuple::ExampleTupleVariant(q)); - | ---- ^ the trait `T3` is not implemented for `Q`, which is required by `&ExampleTuple<Q>: T1` + | ---- ^ the trait `T3` is not implemented for `Q` | | | required by a bound introduced by this call | @@ -134,7 +134,7 @@ error[E0277]: the trait bound `Q: T3` is not satisfied --> $DIR/blame-trait-error.rs:68:31 | LL | want(&ExampleTupleVariant(q)); - | ---- ^ the trait `T3` is not implemented for `Q`, which is required by `&ExampleTuple<Q>: T1` + | ---- ^ the trait `T3` is not implemented for `Q` | | | required by a bound introduced by this call | @@ -159,7 +159,7 @@ error[E0277]: the trait bound `Q: T3` is not satisfied --> $DIR/blame-trait-error.rs:71:50 | LL | want(&ExampleOtherTuple::ExampleTupleVariant(q)); - | ---- ^ the trait `T3` is not implemented for `Q`, which is required by `&ExampleTuple<Q>: T1` + | ---- ^ the trait `T3` is not implemented for `Q` | | | required by a bound introduced by this call | @@ -184,7 +184,7 @@ error[E0277]: the trait bound `Q: T3` is not satisfied --> $DIR/blame-trait-error.rs:74:44 | LL | want(&ExampleDifferentTupleVariantName(q)); - | ---- ^ the trait `T3` is not implemented for `Q`, which is required by `&ExampleTuple<Q>: T1` + | ---- ^ the trait `T3` is not implemented for `Q` | | | required by a bound introduced by this call | @@ -209,7 +209,7 @@ error[E0277]: the trait bound `Q: T3` is not satisfied --> $DIR/blame-trait-error.rs:77:45 | LL | want(&ExampleYetAnotherTupleVariantName(q)); - | ---- ^ the trait `T3` is not implemented for `Q`, which is required by `&ExampleTuple<Q>: T1` + | ---- ^ the trait `T3` is not implemented for `Q` | | | required by a bound introduced by this call | @@ -234,7 +234,7 @@ error[E0277]: the trait bound `Q: T3` is not satisfied --> $DIR/blame-trait-error.rs:80:56 | LL | want(&ExampleStruct::ExampleStructVariant { field: q }); - | ---- required by a bound introduced by this call ^ the trait `T3` is not implemented for `Q`, which is required by `&ExampleStruct<Q>: T1` + | ---- required by a bound introduced by this call ^ the trait `T3` is not implemented for `Q` | note: required for `ExampleStruct<Q>` to implement `T1` --> $DIR/blame-trait-error.rs:45:9 @@ -257,7 +257,7 @@ error[E0277]: the trait bound `Q: T3` is not satisfied --> $DIR/blame-trait-error.rs:83:41 | LL | want(&ExampleStructVariant { field: q }); - | ---- ^ the trait `T3` is not implemented for `Q`, which is required by `&ExampleStruct<Q>: T1` + | ---- ^ the trait `T3` is not implemented for `Q` | | | required by a bound introduced by this call | @@ -282,7 +282,7 @@ error[E0277]: the trait bound `Q: T3` is not satisfied --> $DIR/blame-trait-error.rs:86:61 | LL | want(&ExampleOtherStruct::ExampleStructVariant { field: q }); - | ---- required by a bound introduced by this call ^ the trait `T3` is not implemented for `Q`, which is required by `&ExampleStruct<Q>: T1` + | ---- required by a bound introduced by this call ^ the trait `T3` is not implemented for `Q` | note: required for `ExampleStruct<Q>` to implement `T1` --> $DIR/blame-trait-error.rs:45:9 @@ -305,7 +305,7 @@ error[E0277]: the trait bound `Q: T3` is not satisfied --> $DIR/blame-trait-error.rs:89:54 | LL | want(&ExampleDifferentStructVariantName { field: q }); - | ---- required by a bound introduced by this call ^ the trait `T3` is not implemented for `Q`, which is required by `&ExampleStruct<Q>: T1` + | ---- required by a bound introduced by this call ^ the trait `T3` is not implemented for `Q` | note: required for `ExampleStruct<Q>` to implement `T1` --> $DIR/blame-trait-error.rs:45:9 @@ -328,7 +328,7 @@ error[E0277]: the trait bound `Q: T3` is not satisfied --> $DIR/blame-trait-error.rs:92:55 | LL | want(&ExampleYetAnotherStructVariantName { field: q }); - | ---- required by a bound introduced by this call ^ the trait `T3` is not implemented for `Q`, which is required by `&ExampleStruct<Q>: T1` + | ---- required by a bound introduced by this call ^ the trait `T3` is not implemented for `Q` | note: required for `ExampleStruct<Q>` to implement `T1` --> $DIR/blame-trait-error.rs:45:9 @@ -351,7 +351,7 @@ error[E0277]: the trait bound `Q: T3` is not satisfied --> $DIR/blame-trait-error.rs:95:38 | LL | want(&ExampleActuallyTupleStruct(q, 0)); - | ---- ^ the trait `T3` is not implemented for `Q`, which is required by `&ExampleActuallyTupleStruct<Q>: T1` + | ---- ^ the trait `T3` is not implemented for `Q` | | | required by a bound introduced by this call | @@ -376,7 +376,7 @@ error[E0277]: the trait bound `Q: T3` is not satisfied --> $DIR/blame-trait-error.rs:98:43 | LL | want(&ExampleActuallyTupleStructOther(q, 0)); - | ---- ^ the trait `T3` is not implemented for `Q`, which is required by `&ExampleActuallyTupleStruct<Q>: T1` + | ---- ^ the trait `T3` is not implemented for `Q` | | | required by a bound introduced by this call | diff --git a/tests/ui/errors/traits/blame-trait-error-spans-on-exprs.stderr b/tests/ui/errors/traits/blame-trait-error-spans-on-exprs.stderr index a2df6843f43..b6a24e12bcc 100644 --- a/tests/ui/errors/traits/blame-trait-error-spans-on-exprs.stderr +++ b/tests/ui/errors/traits/blame-trait-error-spans-on-exprs.stderr @@ -2,7 +2,7 @@ error[E0277]: the trait bound `Q: T3` is not satisfied --> $DIR/blame-trait-error-spans-on-exprs.rs:81:60 | LL | want(Wrapper { value: Burrito { spicy: false, filling: q } }); - | ---- required by a bound introduced by this call ^ the trait `T3` is not implemented for `Q`, which is required by `Wrapper<Burrito<Q>>: T1` + | ---- required by a bound introduced by this call ^ the trait `T3` is not implemented for `Q` | note: required for `Burrito<Q>` to implement `T2` --> $DIR/blame-trait-error-spans-on-exprs.rs:22:13 @@ -32,7 +32,7 @@ error[E0277]: the trait bound `Q: T3` is not satisfied --> $DIR/blame-trait-error-spans-on-exprs.rs:85:84 | LL | want(Wrapper { value: BurritoKinds::SmallBurrito { spicy: true, small_filling: q } }); - | ---- required by a bound introduced by this call ^ the trait `T3` is not implemented for `Q`, which is required by `Wrapper<BurritoKinds<Q>>: T1` + | ---- required by a bound introduced by this call ^ the trait `T3` is not implemented for `Q` | note: required for `BurritoKinds<Q>` to implement `T2` --> $DIR/blame-trait-error-spans-on-exprs.rs:32:13 @@ -62,7 +62,7 @@ error[E0277]: the trait bound `Q: T3` is not satisfied --> $DIR/blame-trait-error-spans-on-exprs.rs:89:39 | LL | want(Wrapper { value: Taco(false, q) }); - | ---- ^ the trait `T3` is not implemented for `Q`, which is required by `Wrapper<Taco<Q>>: T1` + | ---- ^ the trait `T3` is not implemented for `Q` | | | required by a bound introduced by this call | @@ -94,7 +94,7 @@ error[E0277]: the trait bound `Q: T3` is not satisfied --> $DIR/blame-trait-error-spans-on-exprs.rs:93:53 | LL | want(Wrapper { value: TacoKinds::OneTaco(false, q) }); - | ---- ^ the trait `T3` is not implemented for `Q`, which is required by `Wrapper<TacoKinds<Q>>: T1` + | ---- ^ the trait `T3` is not implemented for `Q` | | | required by a bound introduced by this call | @@ -126,7 +126,7 @@ error[E0277]: the trait bound `Q: T3` is not satisfied --> $DIR/blame-trait-error-spans-on-exprs.rs:97:74 | LL | want(Wrapper { value: GenericBurrito { spiciness: NotSpicy, filling: q } }); - | ---- required by a bound introduced by this call ^ the trait `T3` is not implemented for `Q`, which is required by `Wrapper<GenericBurrito<NotSpicy, Q>>: T1` + | ---- required by a bound introduced by this call ^ the trait `T3` is not implemented for `Q` | note: required for `GenericBurrito<NotSpicy, Q>` to implement `T2` --> $DIR/blame-trait-error-spans-on-exprs.rs:47:16 @@ -156,7 +156,7 @@ error[E0277]: the trait bound `Q: T2` is not satisfied --> $DIR/blame-trait-error-spans-on-exprs.rs:101:14 | LL | want((3, q)); - | ---- ^ the trait `T2` is not implemented for `Q`, which is required by `({integer}, Q): T1` + | ---- ^ the trait `T2` is not implemented for `Q` | | | required by a bound introduced by this call | @@ -181,7 +181,7 @@ error[E0277]: the trait bound `Q: T3` is not satisfied --> $DIR/blame-trait-error-spans-on-exprs.rs:105:31 | LL | want(Wrapper { value: (3, q) }); - | ---- ^ the trait `T3` is not implemented for `Q`, which is required by `Wrapper<({integer}, Q)>: T1` + | ---- ^ the trait `T3` is not implemented for `Q` | | | required by a bound introduced by this call | @@ -213,7 +213,7 @@ error[E0277]: the trait bound `Q: T3` is not satisfied --> $DIR/blame-trait-error-spans-on-exprs.rs:109:15 | LL | want(((3, q), 5)); - | ---- ^ the trait `T3` is not implemented for `Q`, which is required by `(({integer}, Q), {integer}): T1` + | ---- ^ the trait `T3` is not implemented for `Q` | | | required by a bound introduced by this call | @@ -245,7 +245,7 @@ error[E0277]: the trait bound `Q: T1` is not satisfied --> $DIR/blame-trait-error-spans-on-exprs.rs:112:49 | LL | want(DoubleWrapper { item: Wrapper { value: q } }); - | ---- ^ the trait `T1` is not implemented for `Q`, which is required by `DoubleWrapper<Q>: T1` + | ---- ^ the trait `T1` is not implemented for `Q` | | | required by a bound introduced by this call | @@ -270,7 +270,7 @@ error[E0277]: the trait bound `Q: T1` is not satisfied --> $DIR/blame-trait-error-spans-on-exprs.rs:115:88 | LL | want(DoubleWrapper { item: Wrapper { value: DoubleWrapper { item: Wrapper { value: q } } } }); - | ---- required by a bound introduced by this call ^ the trait `T1` is not implemented for `Q`, which is required by `DoubleWrapper<DoubleWrapper<Q>>: T1` + | ---- required by a bound introduced by this call ^ the trait `T1` is not implemented for `Q` | note: required for `DoubleWrapper<Q>` to implement `T1` --> $DIR/blame-trait-error-spans-on-exprs.rs:72:13 @@ -295,7 +295,7 @@ error[E0277]: the trait bound `Q: T3` is not satisfied --> $DIR/blame-trait-error-spans-on-exprs.rs:119:27 | LL | want(Wrapper { value: AliasBurrito { spiciness: q, filling: q } }); - | ---- ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ the trait `T3` is not implemented for `Q`, which is required by `Wrapper<GenericBurrito<Q, Q>>: T1` + | ---- ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ the trait `T3` is not implemented for `Q` | | | required by a bound introduced by this call | @@ -327,7 +327,7 @@ error[E0277]: the trait bound `Q: T1` is not satisfied --> $DIR/blame-trait-error-spans-on-exprs.rs:122:35 | LL | want(Two { a: Two { a: (), b: q }, b: () }); - | ---- ^ the trait `T1` is not implemented for `Q`, which is required by `Two<Two<(), Q>, ()>: T1` + | ---- ^ the trait `T1` is not implemented for `Q` | | | required by a bound introduced by this call | @@ -354,7 +354,7 @@ error[E0277]: the trait bound `Q: T1` is not satisfied LL | want( | ---- required by a bound introduced by this call LL | Two { a: Two { a: (), b: Two { a: Two { a: (), b: q }, b: () } }, b: () }, - | ^ the trait `T1` is not implemented for `Q`, which is required by `Two<Two<(), Two<Two<(), Q>, ()>>, ()>: T1` + | ^ the trait `T1` is not implemented for `Q` | note: required for `Two<Two<(), Q>, ()>` to implement `T1` --> $DIR/blame-trait-error-spans-on-exprs.rs:66:19 @@ -379,7 +379,7 @@ error[E0277]: the trait bound `Q: T3` is not satisfied --> $DIR/blame-trait-error-spans-on-exprs.rs:133:44 | LL | want(&Burrito { spicy: false, filling: q }); - | ---- ^ the trait `T3` is not implemented for `Q`, which is required by `&Burrito<Q>: T1` + | ---- ^ the trait `T3` is not implemented for `Q` | | | required by a bound introduced by this call | diff --git a/tests/ui/extern/extern-types-unsized.stderr b/tests/ui/extern/extern-types-unsized.stderr index 7428e6a60b5..a587d4dda55 100644 --- a/tests/ui/extern/extern-types-unsized.stderr +++ b/tests/ui/extern/extern-types-unsized.stderr @@ -21,7 +21,7 @@ error[E0277]: the size for values of type `A` cannot be known at compilation tim LL | assert_sized::<Foo>(); | ^^^ doesn't have a size known at compile-time | - = help: within `Foo`, the trait `Sized` is not implemented for `A`, which is required by `Foo: Sized` + = help: within `Foo`, the trait `Sized` is not implemented for `A` note: required because it appears within the type `Foo` --> $DIR/extern-types-unsized.rs:9:8 | @@ -43,7 +43,7 @@ error[E0277]: the size for values of type `A` cannot be known at compilation tim LL | assert_sized::<Bar<A>>(); | ^^^^^^ doesn't have a size known at compile-time | - = help: within `Bar<A>`, the trait `Sized` is not implemented for `A`, which is required by `Bar<A>: Sized` + = help: within `Bar<A>`, the trait `Sized` is not implemented for `A` note: required because it appears within the type `Bar<A>` --> $DIR/extern-types-unsized.rs:14:8 | @@ -65,7 +65,7 @@ error[E0277]: the size for values of type `A` cannot be known at compilation tim LL | assert_sized::<Bar<Bar<A>>>(); | ^^^^^^^^^^^ doesn't have a size known at compile-time | - = help: within `Bar<Bar<A>>`, the trait `Sized` is not implemented for `A`, which is required by `Bar<Bar<A>>: Sized` + = help: within `Bar<Bar<A>>`, the trait `Sized` is not implemented for `A` note: required because it appears within the type `Bar<A>` --> $DIR/extern-types-unsized.rs:14:8 | diff --git a/tests/ui/fail-simple.rs b/tests/ui/fail-simple.rs index cd81a5d0a0f..55e547ee72b 100644 --- a/tests/ui/fail-simple.rs +++ b/tests/ui/fail-simple.rs @@ -1,3 +1,3 @@ fn main() { - panic!(@); //~ ERROR no rules expected the token `@` + panic!(@); //~ ERROR no rules expected `@` } diff --git a/tests/ui/fail-simple.stderr b/tests/ui/fail-simple.stderr index 39fec3e2517..50c350b3ef5 100644 --- a/tests/ui/fail-simple.stderr +++ b/tests/ui/fail-simple.stderr @@ -1,4 +1,4 @@ -error: no rules expected the token `@` +error: no rules expected `@` --> $DIR/fail-simple.rs:2:12 | LL | panic!(@); diff --git a/tests/ui/feature-gates/feature-gate-derive-coerce-pointee.rs b/tests/ui/feature-gates/feature-gate-derive-coerce-pointee.rs new file mode 100644 index 00000000000..69bc70e8666 --- /dev/null +++ b/tests/ui/feature-gates/feature-gate-derive-coerce-pointee.rs @@ -0,0 +1,9 @@ +use std::marker::CoercePointee; //~ ERROR use of unstable library feature 'derive_coerce_pointee' + +#[derive(CoercePointee)] //~ ERROR use of unstable library feature 'derive_coerce_pointee' +#[repr(transparent)] +struct MyPointer<'a, #[pointee] T: ?Sized> { + ptr: &'a T, +} + +fn main() {} diff --git a/tests/ui/feature-gates/feature-gate-derive-coerce-pointee.stderr b/tests/ui/feature-gates/feature-gate-derive-coerce-pointee.stderr new file mode 100644 index 00000000000..0b52ceb782a --- /dev/null +++ b/tests/ui/feature-gates/feature-gate-derive-coerce-pointee.stderr @@ -0,0 +1,23 @@ +error[E0658]: use of unstable library feature 'derive_coerce_pointee' + --> $DIR/feature-gate-derive-coerce-pointee.rs:3:10 + | +LL | #[derive(CoercePointee)] + | ^^^^^^^^^^^^^ + | + = note: see issue #123430 <https://github.com/rust-lang/rust/issues/123430> for more information + = help: add `#![feature(derive_coerce_pointee)]` to the crate attributes to enable + = note: this compiler was built on YYYY-MM-DD; consider upgrading it if it is out of date + +error[E0658]: use of unstable library feature 'derive_coerce_pointee' + --> $DIR/feature-gate-derive-coerce-pointee.rs:1:5 + | +LL | use std::marker::CoercePointee; + | ^^^^^^^^^^^^^^^^^^^^^^^^^^ + | + = note: see issue #123430 <https://github.com/rust-lang/rust/issues/123430> for more information + = help: add `#![feature(derive_coerce_pointee)]` to the crate attributes to enable + = note: this compiler was built on YYYY-MM-DD; consider upgrading it if it is out of date + +error: aborting due to 2 previous errors + +For more information about this error, try `rustc --explain E0658`. diff --git a/tests/ui/feature-gates/feature-gate-derive-smart-pointer.rs b/tests/ui/feature-gates/feature-gate-derive-smart-pointer.rs deleted file mode 100644 index 7b4764ee768..00000000000 --- a/tests/ui/feature-gates/feature-gate-derive-smart-pointer.rs +++ /dev/null @@ -1,9 +0,0 @@ -use std::marker::SmartPointer; //~ ERROR use of unstable library feature 'derive_smart_pointer' - -#[derive(SmartPointer)] //~ ERROR use of unstable library feature 'derive_smart_pointer' -#[repr(transparent)] -struct MyPointer<'a, #[pointee] T: ?Sized> { - ptr: &'a T, -} - -fn main() {} diff --git a/tests/ui/feature-gates/feature-gate-derive-smart-pointer.stderr b/tests/ui/feature-gates/feature-gate-derive-smart-pointer.stderr deleted file mode 100644 index ea4d1271b7c..00000000000 --- a/tests/ui/feature-gates/feature-gate-derive-smart-pointer.stderr +++ /dev/null @@ -1,23 +0,0 @@ -error[E0658]: use of unstable library feature 'derive_smart_pointer' - --> $DIR/feature-gate-derive-smart-pointer.rs:3:10 - | -LL | #[derive(SmartPointer)] - | ^^^^^^^^^^^^ - | - = note: see issue #123430 <https://github.com/rust-lang/rust/issues/123430> for more information - = help: add `#![feature(derive_smart_pointer)]` to the crate attributes to enable - = note: this compiler was built on YYYY-MM-DD; consider upgrading it if it is out of date - -error[E0658]: use of unstable library feature 'derive_smart_pointer' - --> $DIR/feature-gate-derive-smart-pointer.rs:1:5 - | -LL | use std::marker::SmartPointer; - | ^^^^^^^^^^^^^^^^^^^^^^^^^ - | - = note: see issue #123430 <https://github.com/rust-lang/rust/issues/123430> for more information - = help: add `#![feature(derive_smart_pointer)]` to the crate attributes to enable - = note: this compiler was built on YYYY-MM-DD; consider upgrading it if it is out of date - -error: aborting due to 2 previous errors - -For more information about this error, try `rustc --explain E0658`. diff --git a/tests/ui/feature-gates/feature-gate-if-let-rescope.rs b/tests/ui/feature-gates/feature-gate-if-let-rescope.rs deleted file mode 100644 index bd1efd4fb7c..00000000000 --- a/tests/ui/feature-gates/feature-gate-if-let-rescope.rs +++ /dev/null @@ -1,27 +0,0 @@ -// This test shows the code that could have been accepted by enabling #![feature(if_let_rescope)] - -struct A; -struct B<'a, T>(&'a mut T); - -impl A { - fn f(&mut self) -> Option<B<'_, Self>> { - Some(B(self)) - } -} - -impl<'a, T> Drop for B<'a, T> { - fn drop(&mut self) { - // this is needed to keep NLL's hands off and to ensure - // the inner mutable borrow stays alive - } -} - -fn main() { - let mut a = A; - if let None = a.f().as_ref() { - unreachable!() - } else { - a.f().unwrap(); - //~^ ERROR cannot borrow `a` as mutable more than once at a time - }; -} diff --git a/tests/ui/feature-gates/feature-gate-if-let-rescope.stderr b/tests/ui/feature-gates/feature-gate-if-let-rescope.stderr deleted file mode 100644 index ff1846ae0b1..00000000000 --- a/tests/ui/feature-gates/feature-gate-if-let-rescope.stderr +++ /dev/null @@ -1,18 +0,0 @@ -error[E0499]: cannot borrow `a` as mutable more than once at a time - --> $DIR/feature-gate-if-let-rescope.rs:24:9 - | -LL | if let None = a.f().as_ref() { - | ----- - | | - | first mutable borrow occurs here - | a temporary with access to the first borrow is created here ... -... -LL | a.f().unwrap(); - | ^ second mutable borrow occurs here -LL | -LL | }; - | - ... and the first borrow might be used here, when that temporary is dropped and runs the destructor for type `Option<B<'_, A>>` - -error: aborting due to 1 previous error - -For more information about this error, try `rustc --explain E0499`. diff --git a/tests/ui/feature-gates/feature-gate-offset-of-slice.stderr b/tests/ui/feature-gates/feature-gate-offset-of-slice.stderr index 5cf34a897f4..ae8d50344d5 100644 --- a/tests/ui/feature-gates/feature-gate-offset-of-slice.stderr +++ b/tests/ui/feature-gates/feature-gate-offset-of-slice.stderr @@ -13,7 +13,7 @@ error[E0277]: the size for values of type `[i32]` cannot be known at compilation LL | offset_of!(T, y); | ^^^^^^^^^^^^^^^^ doesn't have a size known at compile-time | - = help: within `S`, the trait `Sized` is not implemented for `[i32]`, which is required by `S: Sized` + = help: within `S`, the trait `Sized` is not implemented for `[i32]` note: required because it appears within the type `S` --> $DIR/feature-gate-offset-of-slice.rs:3:8 | diff --git a/tests/ui/feature-gates/feature-gate-trivial_bounds.stderr b/tests/ui/feature-gates/feature-gate-trivial_bounds.stderr index 0ee2d93fb26..7d9c5b81651 100644 --- a/tests/ui/feature-gates/feature-gate-trivial_bounds.stderr +++ b/tests/ui/feature-gates/feature-gate-trivial_bounds.stderr @@ -120,7 +120,7 @@ error[E0277]: the size for values of type `(dyn A + 'static)` cannot be known at LL | fn unsized_local() where Dst<dyn A>: Sized { | ^^^^^^^^^^^^^^^^^ doesn't have a size known at compile-time | - = help: within `Dst<(dyn A + 'static)>`, the trait `Sized` is not implemented for `(dyn A + 'static)`, which is required by `Dst<(dyn A + 'static)>: Sized` + = help: within `Dst<(dyn A + 'static)>`, the trait `Sized` is not implemented for `(dyn A + 'static)` note: required because it appears within the type `Dst<(dyn A + 'static)>` --> $DIR/feature-gate-trivial_bounds.rs:48:8 | diff --git a/tests/ui/fmt/ifmt-unimpl.stderr b/tests/ui/fmt/ifmt-unimpl.stderr index f83e7c87728..b8d4425a4a7 100644 --- a/tests/ui/fmt/ifmt-unimpl.stderr +++ b/tests/ui/fmt/ifmt-unimpl.stderr @@ -2,7 +2,7 @@ error[E0277]: the trait bound `str: UpperHex` is not satisfied --> $DIR/ifmt-unimpl.rs:2:21 | LL | format!("{:X}", "3"); - | ---- ^^^ the trait `UpperHex` is not implemented for `str`, which is required by `&str: UpperHex` + | ---- ^^^ the trait `UpperHex` is not implemented for `str` | | | required by a bound introduced by this call | diff --git a/tests/ui/for/for-c-in-str.stderr b/tests/ui/for/for-c-in-str.stderr index 2544df64629..475cf8c8874 100644 --- a/tests/ui/for/for-c-in-str.stderr +++ b/tests/ui/for/for-c-in-str.stderr @@ -4,7 +4,7 @@ error[E0277]: `&str` is not an iterator LL | for c in "asdf" { | ^^^^^^ `&str` is not an iterator; try calling `.chars()` or `.bytes()` | - = help: the trait `Iterator` is not implemented for `&str`, which is required by `&str: IntoIterator` + = help: the trait `Iterator` is not implemented for `&str` = note: required for `&str` to implement `IntoIterator` error: aborting due to 1 previous error diff --git a/tests/ui/for/for-loop-bogosity.stderr b/tests/ui/for/for-loop-bogosity.stderr index 143e4a4efd1..194a2fa08ce 100644 --- a/tests/ui/for/for-loop-bogosity.stderr +++ b/tests/ui/for/for-loop-bogosity.stderr @@ -4,7 +4,7 @@ error[E0277]: `MyStruct` is not an iterator LL | for x in bogus { | ^^^^^ `MyStruct` is not an iterator | - = help: the trait `Iterator` is not implemented for `MyStruct`, which is required by `MyStruct: IntoIterator` + = help: the trait `Iterator` is not implemented for `MyStruct` = note: required for `MyStruct` to implement `IntoIterator` error: aborting due to 1 previous error diff --git a/tests/ui/function-pointer/unsized-ret.stderr b/tests/ui/function-pointer/unsized-ret.stderr index 81d603f4b20..66116273ff4 100644 --- a/tests/ui/function-pointer/unsized-ret.stderr +++ b/tests/ui/function-pointer/unsized-ret.stderr @@ -4,7 +4,7 @@ error[E0277]: the size for values of type `str` cannot be known at compilation t LL | foo::<fn() -> str, _>(None, ()); | ^^^^^^^^^^^ doesn't have a size known at compile-time | - = help: within `fn() -> str`, the trait `Sized` is not implemented for `str`, which is required by `fn() -> str: Fn<_>` + = help: within `fn() -> str`, the trait `Sized` is not implemented for `str` = note: required because it appears within the type `fn() -> str` note: required by a bound in `foo` --> $DIR/unsized-ret.rs:5:11 @@ -18,7 +18,7 @@ error[E0277]: the size for values of type `(dyn std::fmt::Display + 'a)` cannot LL | foo::<for<'a> fn(&'a ()) -> (dyn std::fmt::Display + 'a), _>(None, (&(),)); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ doesn't have a size known at compile-time | - = help: within `for<'a> fn(&'a ()) -> (dyn std::fmt::Display + 'a)`, the trait `for<'a> Sized` is not implemented for `(dyn std::fmt::Display + 'a)`, which is required by `for<'a> fn(&'a ()) -> (dyn std::fmt::Display + 'a): Fn<_>` + = help: within `for<'a> fn(&'a ()) -> (dyn std::fmt::Display + 'a)`, the trait `for<'a> Sized` is not implemented for `(dyn std::fmt::Display + 'a)` = note: required because it appears within the type `for<'a> fn(&'a ()) -> (dyn std::fmt::Display + 'a)` note: required by a bound in `foo` --> $DIR/unsized-ret.rs:5:11 diff --git a/tests/ui/generic-associated-types/assume-gat-normalization-for-nested-goals.current.stderr b/tests/ui/generic-associated-types/assume-gat-normalization-for-nested-goals.current.stderr index c5c4f2c4d23..8779bab593a 100644 --- a/tests/ui/generic-associated-types/assume-gat-normalization-for-nested-goals.current.stderr +++ b/tests/ui/generic-associated-types/assume-gat-normalization-for-nested-goals.current.stderr @@ -2,7 +2,7 @@ error[E0277]: the trait bound `<Self as Foo>::Bar<()>: Eq<i32>` is not satisfied --> $DIR/assume-gat-normalization-for-nested-goals.rs:9:30 | LL | type Bar<T>: Baz<Self> = i32; - | ^^^ the trait `Eq<i32>` is not implemented for `<Self as Foo>::Bar<()>`, which is required by `i32: Baz<Self>` + | ^^^ the trait `Eq<i32>` is not implemented for `<Self as Foo>::Bar<()>` | note: required for `i32` to implement `Baz<Self>` --> $DIR/assume-gat-normalization-for-nested-goals.rs:16:23 diff --git a/tests/ui/generic-associated-types/assume-gat-normalization-for-nested-goals.next.stderr b/tests/ui/generic-associated-types/assume-gat-normalization-for-nested-goals.next.stderr index c5c4f2c4d23..8779bab593a 100644 --- a/tests/ui/generic-associated-types/assume-gat-normalization-for-nested-goals.next.stderr +++ b/tests/ui/generic-associated-types/assume-gat-normalization-for-nested-goals.next.stderr @@ -2,7 +2,7 @@ error[E0277]: the trait bound `<Self as Foo>::Bar<()>: Eq<i32>` is not satisfied --> $DIR/assume-gat-normalization-for-nested-goals.rs:9:30 | LL | type Bar<T>: Baz<Self> = i32; - | ^^^ the trait `Eq<i32>` is not implemented for `<Self as Foo>::Bar<()>`, which is required by `i32: Baz<Self>` + | ^^^ the trait `Eq<i32>` is not implemented for `<Self as Foo>::Bar<()>` | note: required for `i32` to implement `Baz<Self>` --> $DIR/assume-gat-normalization-for-nested-goals.rs:16:23 diff --git a/tests/ui/generic-associated-types/impl_bounds.stderr b/tests/ui/generic-associated-types/impl_bounds.stderr index c3b119e2144..261070d1db4 100644 --- a/tests/ui/generic-associated-types/impl_bounds.stderr +++ b/tests/ui/generic-associated-types/impl_bounds.stderr @@ -25,7 +25,7 @@ error[E0277]: the trait bound `T: Copy` is not satisfied --> $DIR/impl_bounds.rs:18:33 | LL | type C = String where Self: Copy; - | ^^^^ the trait `Copy` is not implemented for `T`, which is required by `Fooy<T>: Copy` + | ^^^^ the trait `Copy` is not implemented for `T` | note: required for `Fooy<T>` to implement `Copy` --> $DIR/impl_bounds.rs:10:10 @@ -50,7 +50,7 @@ error[E0277]: the trait bound `T: Copy` is not satisfied --> $DIR/impl_bounds.rs:20:24 | LL | fn d() where Self: Copy {} - | ^^^^ the trait `Copy` is not implemented for `T`, which is required by `Fooy<T>: Copy` + | ^^^^ the trait `Copy` is not implemented for `T` | note: required for `Fooy<T>` to implement `Copy` --> $DIR/impl_bounds.rs:10:10 diff --git a/tests/ui/generic-associated-types/issue-101020.stderr b/tests/ui/generic-associated-types/issue-101020.stderr index 7faab4e5274..9c3753c2d18 100644 --- a/tests/ui/generic-associated-types/issue-101020.stderr +++ b/tests/ui/generic-associated-types/issue-101020.stderr @@ -2,7 +2,7 @@ error[E0277]: the trait bound `for<'a> &'a mut (): Foo<&'a mut ()>` is not satis --> $DIR/issue-101020.rs:31:22 | LL | (&mut EmptyIter).consume(()); - | ^^^^^^^ the trait `for<'a> Foo<&'a mut ()>` is not implemented for `&'a mut ()`, which is required by `for<'a> &'a mut (): FuncInput<'a, &'a mut ()>` + | ^^^^^^^ the trait `for<'a> Foo<&'a mut ()>` is not implemented for `&'a mut ()` | help: this trait has no implementations, consider adding one --> $DIR/issue-101020.rs:28:1 diff --git a/tests/ui/generic-associated-types/issue-74824.current.stderr b/tests/ui/generic-associated-types/issue-74824.current.stderr index b06c7f127ac..231136612a0 100644 --- a/tests/ui/generic-associated-types/issue-74824.current.stderr +++ b/tests/ui/generic-associated-types/issue-74824.current.stderr @@ -14,7 +14,7 @@ error[E0277]: the trait bound `T: Clone` is not satisfied --> $DIR/issue-74824.rs:10:26 | LL | type Copy<T>: Copy = Box<T>; - | ^^^^^^ the trait `Clone` is not implemented for `T`, which is required by `<Self as UnsafeCopy>::Copy<T>: Copy` + | ^^^^^^ the trait `Clone` is not implemented for `T` | = note: required for `Box<T>` to implement `Clone` = note: required for `<Self as UnsafeCopy>::Copy<T>` to implement `Copy` diff --git a/tests/ui/generic-associated-types/issue-74824.next.stderr b/tests/ui/generic-associated-types/issue-74824.next.stderr index b06c7f127ac..231136612a0 100644 --- a/tests/ui/generic-associated-types/issue-74824.next.stderr +++ b/tests/ui/generic-associated-types/issue-74824.next.stderr @@ -14,7 +14,7 @@ error[E0277]: the trait bound `T: Clone` is not satisfied --> $DIR/issue-74824.rs:10:26 | LL | type Copy<T>: Copy = Box<T>; - | ^^^^^^ the trait `Clone` is not implemented for `T`, which is required by `<Self as UnsafeCopy>::Copy<T>: Copy` + | ^^^^^^ the trait `Clone` is not implemented for `T` | = note: required for `Box<T>` to implement `Clone` = note: required for `<Self as UnsafeCopy>::Copy<T>` to implement `Copy` diff --git a/tests/ui/higher-ranked/trait-bounds/normalize-under-binder/issue-89118.stderr b/tests/ui/higher-ranked/trait-bounds/normalize-under-binder/issue-89118.stderr index 761fd9045a1..7fe803550bd 100644 --- a/tests/ui/higher-ranked/trait-bounds/normalize-under-binder/issue-89118.stderr +++ b/tests/ui/higher-ranked/trait-bounds/normalize-under-binder/issue-89118.stderr @@ -2,7 +2,7 @@ error[E0277]: the trait bound `for<'a> &'a (): BufferMut` is not satisfied --> $DIR/issue-89118.rs:19:8 | LL | C: StackContext, - | ^^^^^^^^^^^^ the trait `for<'a> BufferMut` is not implemented for `&'a ()`, which is required by `for<'a> Ctx<()>: BufferUdpStateContext<&'a ()>` + | ^^^^^^^^^^^^ the trait `for<'a> BufferMut` is not implemented for `&'a ()` | help: this trait has no implementations, consider adding one --> $DIR/issue-89118.rs:1:1 @@ -29,7 +29,7 @@ error[E0277]: the trait bound `for<'a> &'a (): BufferMut` is not satisfied --> $DIR/issue-89118.rs:29:9 | LL | impl<C> EthernetWorker<C> {} - | ^^^^^^^^^^^^^^^^^ the trait `for<'a> BufferMut` is not implemented for `&'a ()`, which is required by `for<'a> Ctx<()>: BufferUdpStateContext<&'a ()>` + | ^^^^^^^^^^^^^^^^^ the trait `for<'a> BufferMut` is not implemented for `&'a ()` | help: this trait has no implementations, consider adding one --> $DIR/issue-89118.rs:1:1 @@ -56,7 +56,7 @@ error[E0277]: the trait bound `for<'a> &'a (): BufferMut` is not satisfied --> $DIR/issue-89118.rs:22:20 | LL | type Handler = Ctx<C::Dispatcher>; - | ^^^^^^^^^^^^^^^^^^ the trait `for<'a> BufferMut` is not implemented for `&'a ()`, which is required by `for<'a> Ctx<()>: BufferUdpStateContext<&'a ()>` + | ^^^^^^^^^^^^^^^^^^ the trait `for<'a> BufferMut` is not implemented for `&'a ()` | help: this trait has no implementations, consider adding one --> $DIR/issue-89118.rs:1:1 diff --git a/tests/ui/impl-trait/auto-trait-leak2.stderr b/tests/ui/impl-trait/auto-trait-leak2.stderr index 1fcde0372fc..52fa28145d6 100644 --- a/tests/ui/impl-trait/auto-trait-leak2.stderr +++ b/tests/ui/impl-trait/auto-trait-leak2.stderr @@ -9,7 +9,7 @@ LL | send(before()); | | | required by a bound introduced by this call | - = help: within `impl Fn(i32)`, the trait `Send` is not implemented for `Rc<Cell<i32>>`, which is required by `impl Fn(i32): Send` + = help: within `impl Fn(i32)`, the trait `Send` is not implemented for `Rc<Cell<i32>>` note: required because it's used within this closure --> $DIR/auto-trait-leak2.rs:10:5 | @@ -37,7 +37,7 @@ LL | send(after()); LL | fn after() -> impl Fn(i32) { | ------------ within this `impl Fn(i32)` | - = help: within `impl Fn(i32)`, the trait `Send` is not implemented for `Rc<Cell<i32>>`, which is required by `impl Fn(i32): Send` + = help: within `impl Fn(i32)`, the trait `Send` is not implemented for `Rc<Cell<i32>>` note: required because it's used within this closure --> $DIR/auto-trait-leak2.rs:38:5 | diff --git a/tests/crashes/126850.rs b/tests/ui/impl-trait/closure-in-type.rs index 0ddc24c8bb1..1e06e6e21fd 100644 --- a/tests/crashes/126850.rs +++ b/tests/ui/impl-trait/closure-in-type.rs @@ -1,4 +1,5 @@ -//@ known-bug: rust-lang/rust#126850 +//@ check-pass + fn bug<T>() -> impl Iterator< Item = [(); { |found: &String| Some(false); diff --git a/tests/ui/impl-trait/diagnostics/highlight-difference-between-expected-trait-and-found-trait.rs b/tests/ui/impl-trait/diagnostics/highlight-difference-between-expected-trait-and-found-trait.rs new file mode 100644 index 00000000000..f1c196a154d --- /dev/null +++ b/tests/ui/impl-trait/diagnostics/highlight-difference-between-expected-trait-and-found-trait.rs @@ -0,0 +1,20 @@ +//@ only-linux +//@ compile-flags: --error-format=human --color=always +//@ error-pattern: the trait bound + +trait Foo<T>: Bar<T> {} + +trait Bar<T> {} + +struct Struct; + +impl<T, K> Foo<K> for T where T: Bar<K> +{} + +impl<'a> Bar<()> for Struct {} + +fn foo() -> impl Foo<i32> { + Struct +} + +fn main() {} diff --git a/tests/ui/impl-trait/diagnostics/highlight-difference-between-expected-trait-and-found-trait.svg b/tests/ui/impl-trait/diagnostics/highlight-difference-between-expected-trait-and-found-trait.svg new file mode 100644 index 00000000000..a18fc11a1e3 --- /dev/null +++ b/tests/ui/impl-trait/diagnostics/highlight-difference-between-expected-trait-and-found-trait.svg @@ -0,0 +1,62 @@ +<svg width="1104px" height="344px" xmlns="http://www.w3.org/2000/svg"> + <style> + .fg { fill: #AAAAAA } + .bg { background: #000000 } + .fg-ansi256-009 { fill: #FF5555 } + .fg-ansi256-010 { fill: #55FF55 } + .fg-ansi256-012 { fill: #5555FF } + .fg-magenta { fill: #AA00AA } + .container { + padding: 0 10px; + line-height: 18px; + } + .bold { font-weight: bold; } + tspan { + font: 14px SFMono-Regular, Consolas, Liberation Mono, Menlo, monospace; + white-space: pre; + line-height: 18px; + } + </style> + + <rect width="100%" height="100%" y="0" rx="4.5" class="bg" /> + + <text xml:space="preserve" class="container fg"> + <tspan x="10px" y="28px"><tspan class="fg-ansi256-009 bold">error[E0277]</tspan><tspan class="bold">: the trait bound `Struct: Foo<i32>` is not satisfied</tspan> +</tspan> + <tspan x="10px" y="46px"><tspan> </tspan><tspan class="fg-ansi256-012 bold">--> </tspan><tspan>$DIR/highlight-difference-between-expected-trait-and-found-trait.rs:16:13</tspan> +</tspan> + <tspan x="10px" y="64px"><tspan> </tspan><tspan class="fg-ansi256-012 bold">|</tspan> +</tspan> + <tspan x="10px" y="82px"><tspan class="fg-ansi256-012 bold">LL</tspan><tspan> </tspan><tspan class="fg-ansi256-012 bold">|</tspan><tspan> fn foo() -> impl Foo<i32> {</tspan> +</tspan> + <tspan x="10px" y="100px"><tspan> </tspan><tspan class="fg-ansi256-012 bold">|</tspan><tspan> </tspan><tspan class="fg-ansi256-009 bold">^^^^^^^^^^^^^</tspan><tspan> </tspan><tspan class="fg-ansi256-009 bold">the trait `Bar<i32>` is not implemented for `Struct`</tspan> +</tspan> + <tspan x="10px" y="118px"><tspan> </tspan><tspan class="fg-ansi256-012 bold">|</tspan> +</tspan> + <tspan x="10px" y="136px"><tspan> </tspan><tspan class="fg-ansi256-012 bold">= </tspan><tspan class="bold">help</tspan><tspan>: the trait `Bar<()>` </tspan><tspan class="fg-magenta bold">is</tspan><tspan> implemented for `Struct`</tspan> +</tspan> + <tspan x="10px" y="154px"><tspan> </tspan><tspan class="fg-ansi256-012 bold">= </tspan><tspan class="bold">help</tspan><tspan>: for that trait implementation, expected `</tspan><tspan class="fg-magenta bold">()</tspan><tspan>`, found `</tspan><tspan class="fg-magenta bold">i32</tspan><tspan>`</tspan> +</tspan> + <tspan x="10px" y="172px"><tspan class="fg-ansi256-010 bold">note</tspan><tspan>: required for `Struct` to implement `Foo<i32>`</tspan> +</tspan> + <tspan x="10px" y="190px"><tspan> </tspan><tspan class="fg-ansi256-012 bold">--> </tspan><tspan>$DIR/highlight-difference-between-expected-trait-and-found-trait.rs:11:12</tspan> +</tspan> + <tspan x="10px" y="208px"><tspan> </tspan><tspan class="fg-ansi256-012 bold">|</tspan> +</tspan> + <tspan x="10px" y="226px"><tspan class="fg-ansi256-012 bold">LL</tspan><tspan> </tspan><tspan class="fg-ansi256-012 bold">|</tspan><tspan> impl<T, K> Foo<K> for T where T: Bar<K></tspan> +</tspan> + <tspan x="10px" y="244px"><tspan> </tspan><tspan class="fg-ansi256-012 bold">|</tspan><tspan> </tspan><tspan class="fg-ansi256-010 bold">^^^^^^</tspan><tspan> </tspan><tspan class="fg-ansi256-010 bold">^</tspan><tspan> </tspan><tspan class="fg-ansi256-012 bold">------</tspan><tspan> </tspan><tspan class="fg-ansi256-012 bold">unsatisfied trait bound introduced here</tspan> +</tspan> + <tspan x="10px" y="262px"> +</tspan> + <tspan x="10px" y="280px"><tspan class="fg-ansi256-009 bold">error</tspan><tspan class="bold">: aborting due to 1 previous error</tspan> +</tspan> + <tspan x="10px" y="298px"> +</tspan> + <tspan x="10px" y="316px"><tspan class="bold">For more information about this error, try `rustc --explain E0277`.</tspan> +</tspan> + <tspan x="10px" y="334px"> +</tspan> + </text> + +</svg> diff --git a/tests/ui/impl-trait/dyn-trait-return-should-be-impl-trait.stderr b/tests/ui/impl-trait/dyn-trait-return-should-be-impl-trait.stderr index 9c546659564..8716088ccbd 100644 --- a/tests/ui/impl-trait/dyn-trait-return-should-be-impl-trait.stderr +++ b/tests/ui/impl-trait/dyn-trait-return-should-be-impl-trait.stderr @@ -16,7 +16,7 @@ LL | fn fuz() -> (usize, Trait) { (42, Struct) } | | | doesn't have a size known at compile-time | - = help: within `(usize, (dyn Trait + 'static))`, the trait `Sized` is not implemented for `(dyn Trait + 'static)`, which is required by `(usize, (dyn Trait + 'static)): Sized` + = help: within `(usize, (dyn Trait + 'static))`, the trait `Sized` is not implemented for `(dyn Trait + 'static)` = note: required because it appears within the type `(usize, (dyn Trait + 'static))` = note: the return type of a function must have a statically known size @@ -38,7 +38,7 @@ LL | fn bar() -> (usize, dyn Trait) { (42, Struct) } | | | doesn't have a size known at compile-time | - = help: within `(usize, (dyn Trait + 'static))`, the trait `Sized` is not implemented for `(dyn Trait + 'static)`, which is required by `(usize, (dyn Trait + 'static)): Sized` + = help: within `(usize, (dyn Trait + 'static))`, the trait `Sized` is not implemented for `(dyn Trait + 'static)` = note: required because it appears within the type `(usize, (dyn Trait + 'static))` = note: the return type of a function must have a statically known size diff --git a/tests/ui/impl-trait/impl_trait_projections.rs b/tests/ui/impl-trait/impl_trait_projections.rs index 365ac85e2f6..2c277aee06d 100644 --- a/tests/ui/impl-trait/impl_trait_projections.rs +++ b/tests/ui/impl-trait/impl_trait_projections.rs @@ -10,30 +10,27 @@ fn path_parametrized_type_is_allowed() -> option::Option<impl Debug> { } fn projection_is_disallowed(x: impl Iterator) -> <impl Iterator>::Item { -//~^ ERROR `impl Trait` is not allowed in path parameters -//~| ERROR `impl Trait` is not allowed in path parameters +//~^ ERROR `impl Trait` is not allowed in paths x.next().unwrap() } fn projection_with_named_trait_is_disallowed(mut x: impl Iterator) -> <impl Iterator as Iterator>::Item -//~^ ERROR `impl Trait` is not allowed in path parameters +//~^ ERROR `impl Trait` is not allowed in paths { x.next().unwrap() } fn projection_with_named_trait_inside_path_is_disallowed() -> <::std::ops::Range<impl Debug> as Iterator>::Item -//~^ ERROR `impl Trait` is not allowed in path parameters -//~| ERROR `impl Debug: Step` is not satisfied +//~^ ERROR `impl Trait` is not allowed in paths { - //~^ ERROR `impl Debug: Step` is not satisfied (1i32..100).next().unwrap() } fn projection_from_impl_trait_inside_dyn_trait_is_disallowed() -> <dyn Iterator<Item = impl Debug> as Iterator>::Item -//~^ ERROR `impl Trait` is not allowed in path parameters +//~^ ERROR `impl Trait` is not allowed in paths { panic!() } diff --git a/tests/ui/impl-trait/impl_trait_projections.stderr b/tests/ui/impl-trait/impl_trait_projections.stderr index d62e3ac4183..5e0b80fcd59 100644 --- a/tests/ui/impl-trait/impl_trait_projections.stderr +++ b/tests/ui/impl-trait/impl_trait_projections.stderr @@ -1,73 +1,35 @@ -error[E0667]: `impl Trait` is not allowed in path parameters +error[E0562]: `impl Trait` is not allowed in paths --> $DIR/impl_trait_projections.rs:12:51 | LL | fn projection_is_disallowed(x: impl Iterator) -> <impl Iterator>::Item { | ^^^^^^^^^^^^^ + | + = note: `impl Trait` is only allowed in arguments and return types of functions and methods -error[E0667]: `impl Trait` is not allowed in path parameters - --> $DIR/impl_trait_projections.rs:19:9 +error[E0562]: `impl Trait` is not allowed in paths + --> $DIR/impl_trait_projections.rs:18:9 | LL | -> <impl Iterator as Iterator>::Item | ^^^^^^^^^^^^^ + | + = note: `impl Trait` is only allowed in arguments and return types of functions and methods -error[E0667]: `impl Trait` is not allowed in path parameters - --> $DIR/impl_trait_projections.rs:26:27 +error[E0562]: `impl Trait` is not allowed in paths + --> $DIR/impl_trait_projections.rs:25:27 | LL | -> <::std::ops::Range<impl Debug> as Iterator>::Item | ^^^^^^^^^^ + | + = note: `impl Trait` is only allowed in arguments and return types of functions and methods -error[E0667]: `impl Trait` is not allowed in path parameters - --> $DIR/impl_trait_projections.rs:35:29 +error[E0562]: `impl Trait` is not allowed in paths + --> $DIR/impl_trait_projections.rs:32:29 | LL | -> <dyn Iterator<Item = impl Debug> as Iterator>::Item | ^^^^^^^^^^ - -error[E0667]: `impl Trait` is not allowed in path parameters - --> $DIR/impl_trait_projections.rs:12:51 - | -LL | fn projection_is_disallowed(x: impl Iterator) -> <impl Iterator>::Item { - | ^^^^^^^^^^^^^ - -error[E0277]: the trait bound `impl Debug: Step` is not satisfied - --> $DIR/impl_trait_projections.rs:26:8 - | -LL | -> <::std::ops::Range<impl Debug> as Iterator>::Item - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ the trait `Step` is not implemented for `impl Debug`, which is required by `std::ops::Range<impl Debug>: Iterator` - | - = help: the following other types implement trait `Step`: - Char - Ipv4Addr - Ipv6Addr - char - i128 - i16 - i32 - i64 - and 8 others - = note: required for `std::ops::Range<impl Debug>` to implement `Iterator` - -error[E0277]: the trait bound `impl Debug: Step` is not satisfied - --> $DIR/impl_trait_projections.rs:29:1 - | -LL | / { -LL | | -LL | | (1i32..100).next().unwrap() -LL | | } - | |_^ the trait `Step` is not implemented for `impl Debug`, which is required by `std::ops::Range<impl Debug>: Iterator` | - = help: the following other types implement trait `Step`: - Char - Ipv4Addr - Ipv6Addr - char - i128 - i16 - i32 - i64 - and 8 others - = note: required for `std::ops::Range<impl Debug>` to implement `Iterator` + = note: `impl Trait` is only allowed in arguments and return types of functions and methods -error: aborting due to 7 previous errors +error: aborting due to 4 previous errors -Some errors have detailed explanations: E0277, E0667. -For more information about an error, try `rustc --explain E0277`. +For more information about this error, try `rustc --explain E0562`. diff --git a/tests/ui/impl-trait/in-trait/bad-projection-from-opaque.rs b/tests/ui/impl-trait/in-trait/bad-projection-from-opaque.rs new file mode 100644 index 00000000000..c2c22cd1abf --- /dev/null +++ b/tests/ui/impl-trait/in-trait/bad-projection-from-opaque.rs @@ -0,0 +1,22 @@ +// issue: rust-lang/rust#126725 + +trait Foo { + fn foo<'a>() -> <&'a impl Sized as Bar>::Output; + //~^ ERROR `impl Trait` is not allowed in paths +} + +trait Bar { + type Output; +} + +impl<'a> Bar for &'a () { + type Output = &'a i32; +} + +impl Foo for () { + fn foo<'a>() -> <&'a Self as Bar>::Output { + &0 + } +} + +fn main() {} diff --git a/tests/ui/impl-trait/in-trait/bad-projection-from-opaque.stderr b/tests/ui/impl-trait/in-trait/bad-projection-from-opaque.stderr new file mode 100644 index 00000000000..bea7ccd1a18 --- /dev/null +++ b/tests/ui/impl-trait/in-trait/bad-projection-from-opaque.stderr @@ -0,0 +1,11 @@ +error[E0562]: `impl Trait` is not allowed in paths + --> $DIR/bad-projection-from-opaque.rs:4:26 + | +LL | fn foo<'a>() -> <&'a impl Sized as Bar>::Output; + | ^^^^^^^^^^ + | + = note: `impl Trait` is only allowed in arguments and return types of functions and methods + +error: aborting due to 1 previous error + +For more information about this error, try `rustc --explain E0562`. diff --git a/tests/ui/impl-trait/in-trait/false-positive-predicate-entailment-error.current.stderr b/tests/ui/impl-trait/in-trait/false-positive-predicate-entailment-error.current.stderr index 058517f0014..38c7a9ea16e 100644 --- a/tests/ui/impl-trait/in-trait/false-positive-predicate-entailment-error.current.stderr +++ b/tests/ui/impl-trait/in-trait/false-positive-predicate-entailment-error.current.stderr @@ -8,7 +8,7 @@ LL | | ... | LL | | where LL | | F: Callback<Self::CallbackArg>, - | |_______________________________________^ the trait `MyFn<i32>` is not implemented for `F`, which is required by `F: Callback<i32>` + | |_______________________________________^ the trait `MyFn<i32>` is not implemented for `F` | note: required for `F` to implement `Callback<i32>` --> $DIR/false-positive-predicate-entailment-error.rs:14:21 @@ -26,7 +26,7 @@ error[E0277]: the trait bound `F: MyFn<i32>` is not satisfied --> $DIR/false-positive-predicate-entailment-error.rs:36:30 | LL | fn autobatch<F>(self) -> impl Trait - | ^^^^^^^^^^ the trait `MyFn<i32>` is not implemented for `F`, which is required by `F: Callback<i32>` + | ^^^^^^^^^^ the trait `MyFn<i32>` is not implemented for `F` | note: required for `F` to implement `Callback<i32>` --> $DIR/false-positive-predicate-entailment-error.rs:14:21 @@ -58,7 +58,7 @@ LL | | ... | LL | | where LL | | F: Callback<Self::CallbackArg>, - | |_______________________________________^ the trait `MyFn<i32>` is not implemented for `F`, which is required by `F: Callback<i32>` + | |_______________________________________^ the trait `MyFn<i32>` is not implemented for `F` | note: required for `F` to implement `Callback<i32>` --> $DIR/false-positive-predicate-entailment-error.rs:14:21 @@ -77,7 +77,7 @@ error[E0277]: the trait bound `F: MyFn<i32>` is not satisfied --> $DIR/false-positive-predicate-entailment-error.rs:36:30 | LL | fn autobatch<F>(self) -> impl Trait - | ^^^^^^^^^^ the trait `MyFn<i32>` is not implemented for `F`, which is required by `F: Callback<i32>` + | ^^^^^^^^^^ the trait `MyFn<i32>` is not implemented for `F` | note: required for `F` to implement `Callback<i32>` --> $DIR/false-positive-predicate-entailment-error.rs:14:21 @@ -91,7 +91,7 @@ error[E0277]: the trait bound `F: Callback<i32>` is not satisfied --> $DIR/false-positive-predicate-entailment-error.rs:27:12 | LL | F: Callback<Self::CallbackArg>; - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^ the trait `MyFn<i32>` is not implemented for `F`, which is required by `F: Callback<i32>` + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^ the trait `MyFn<i32>` is not implemented for `F` | note: required for `F` to implement `Callback<i32>` --> $DIR/false-positive-predicate-entailment-error.rs:14:21 @@ -111,7 +111,7 @@ LL | | ... | LL | | where LL | | F: Callback<Self::CallbackArg>, - | |_______________________________________^ the trait `MyFn<i32>` is not implemented for `F`, which is required by `F: Callback<i32>` + | |_______________________________________^ the trait `MyFn<i32>` is not implemented for `F` | note: required for `F` to implement `Callback<i32>` --> $DIR/false-positive-predicate-entailment-error.rs:14:21 diff --git a/tests/ui/impl-trait/in-trait/return-type-notation.rs b/tests/ui/impl-trait/in-trait/return-type-notation.rs new file mode 100644 index 00000000000..3945eb9bdee --- /dev/null +++ b/tests/ui/impl-trait/in-trait/return-type-notation.rs @@ -0,0 +1,9 @@ +#![allow(incomplete_features)] +#![feature(return_type_notation)] + +trait IntFactory { + fn stream(&self) -> impl IntFactory<stream(..): IntFactory<stream(..): Send> + Send>; + //~^ ERROR cycle detected when resolving lifetimes for `IntFactory::stream` +} + +pub fn main() {} diff --git a/tests/ui/impl-trait/in-trait/return-type-notation.stderr b/tests/ui/impl-trait/in-trait/return-type-notation.stderr new file mode 100644 index 00000000000..d9fd780cdff --- /dev/null +++ b/tests/ui/impl-trait/in-trait/return-type-notation.stderr @@ -0,0 +1,27 @@ +error[E0391]: cycle detected when resolving lifetimes for `IntFactory::stream` + --> $DIR/return-type-notation.rs:5:5 + | +LL | fn stream(&self) -> impl IntFactory<stream(..): IntFactory<stream(..): Send> + Send>; + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + | +note: ...which requires computing function signature of `IntFactory::stream`... + --> $DIR/return-type-notation.rs:5:5 + | +LL | fn stream(&self) -> impl IntFactory<stream(..): IntFactory<stream(..): Send> + Send>; + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ +note: ...which requires looking up late bound vars inside `IntFactory::stream`... + --> $DIR/return-type-notation.rs:5:5 + | +LL | fn stream(&self) -> impl IntFactory<stream(..): IntFactory<stream(..): Send> + Send>; + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + = note: ...which again requires resolving lifetimes for `IntFactory::stream`, completing the cycle +note: cycle used when listing captured lifetimes for opaque `IntFactory::stream::{opaque#0}` + --> $DIR/return-type-notation.rs:5:25 + | +LL | fn stream(&self) -> impl IntFactory<stream(..): IntFactory<stream(..): Send> + Send>; + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + = note: see https://rustc-dev-guide.rust-lang.org/overview.html#queries and https://rustc-dev-guide.rust-lang.org/query.html for more information + +error: aborting due to 1 previous error + +For more information about this error, try `rustc --explain E0391`. diff --git a/tests/ui/impl-trait/in-trait/variance.rs b/tests/ui/impl-trait/in-trait/variance.rs index 19905c608e3..cd2f43fca9a 100644 --- a/tests/ui/impl-trait/in-trait/variance.rs +++ b/tests/ui/impl-trait/in-trait/variance.rs @@ -4,7 +4,7 @@ trait Foo<'i> { fn implicit_capture_early<'a: 'a>() -> impl Sized {} - //~^ [Self: o, 'i: o, 'a: *, 'a: o, 'i: o] + //~^ [Self: o, 'i: o, 'a: *, 'i: o, 'a: o] fn explicit_capture_early<'a: 'a>() -> impl Sized + use<'i, 'a, Self> {} //~^ [Self: o, 'i: o, 'a: *, 'i: o, 'a: o] @@ -13,12 +13,12 @@ trait Foo<'i> { //~^ [Self: o, 'i: o, 'a: *, 'i: o] fn implicit_capture_late<'a>(_: &'a ()) -> impl Sized {} - //~^ [Self: o, 'i: o, 'a: o, 'i: o] + //~^ [Self: o, 'i: o, 'i: o, 'a: o] fn explicit_capture_late<'a>(_: &'a ()) -> impl Sized + use<'i, 'a, Self> {} //~^ [Self: o, 'i: o, 'i: o, 'a: o] - fn not_cpatured_late<'a>(_: &'a ()) -> impl Sized + use<'i, Self> {} + fn not_captured_late<'a>(_: &'a ()) -> impl Sized + use<'i, Self> {} //~^ [Self: o, 'i: o, 'i: o] } diff --git a/tests/ui/impl-trait/in-trait/variance.stderr b/tests/ui/impl-trait/in-trait/variance.stderr index f65174e1c35..d45cca982e9 100644 --- a/tests/ui/impl-trait/in-trait/variance.stderr +++ b/tests/ui/impl-trait/in-trait/variance.stderr @@ -1,4 +1,4 @@ -error: [Self: o, 'i: o, 'a: *, 'a: o, 'i: o] +error: [Self: o, 'i: o, 'a: *, 'i: o, 'a: o] --> $DIR/variance.rs:6:44 | LL | fn implicit_capture_early<'a: 'a>() -> impl Sized {} @@ -16,7 +16,7 @@ error: [Self: o, 'i: o, 'a: *, 'i: o] LL | fn not_captured_early<'a: 'a>() -> impl Sized + use<'i, Self> {} | ^^^^^^^^^^^^^^^^^^^^^^^^^^ -error: [Self: o, 'i: o, 'a: o, 'i: o] +error: [Self: o, 'i: o, 'i: o, 'a: o] --> $DIR/variance.rs:15:48 | LL | fn implicit_capture_late<'a>(_: &'a ()) -> impl Sized {} @@ -31,7 +31,7 @@ LL | fn explicit_capture_late<'a>(_: &'a ()) -> impl Sized + use<'i, 'a, Sel error: [Self: o, 'i: o, 'i: o] --> $DIR/variance.rs:21:44 | -LL | fn not_cpatured_late<'a>(_: &'a ()) -> impl Sized + use<'i, Self> {} +LL | fn not_captured_late<'a>(_: &'a ()) -> impl Sized + use<'i, Self> {} | ^^^^^^^^^^^^^^^^^^^^^^^^^^ error: aborting due to 6 previous errors diff --git a/tests/ui/impl-trait/issue-55872-1.stderr b/tests/ui/impl-trait/issue-55872-1.stderr index 0c86824e622..8912cce1b4b 100644 --- a/tests/ui/impl-trait/issue-55872-1.stderr +++ b/tests/ui/impl-trait/issue-55872-1.stderr @@ -11,7 +11,7 @@ error[E0277]: the trait bound `S: Copy` is not satisfied in `(S, T)` --> $DIR/issue-55872-1.rs:12:29 | LL | fn foo<T: Default>() -> Self::E { - | ^^^^^^^ within `(S, T)`, the trait `Copy` is not implemented for `S`, which is required by `(S, T): Copy` + | ^^^^^^^ within `(S, T)`, the trait `Copy` is not implemented for `S` | = note: required because it appears within the type `(S, T)` help: consider further restricting this bound @@ -23,7 +23,7 @@ error[E0277]: the trait bound `T: Copy` is not satisfied in `(S, T)` --> $DIR/issue-55872-1.rs:12:29 | LL | fn foo<T: Default>() -> Self::E { - | ^^^^^^^ within `(S, T)`, the trait `Copy` is not implemented for `T`, which is required by `(S, T): Copy` + | ^^^^^^^ within `(S, T)`, the trait `Copy` is not implemented for `T` | = note: required because it appears within the type `(S, T)` help: consider further restricting this bound diff --git a/tests/ui/impl-trait/issues/issue-57979-impl-trait-in-path.rs b/tests/ui/impl-trait/issues/issue-57979-impl-trait-in-path.rs index c5ecd1caae1..9466668b1dc 100644 --- a/tests/ui/impl-trait/issues/issue-57979-impl-trait-in-path.rs +++ b/tests/ui/impl-trait/issues/issue-57979-impl-trait-in-path.rs @@ -6,7 +6,7 @@ pub trait Bar { } pub trait Quux<T> { type Assoc; } pub fn demo(_: impl Quux<(), Assoc=<() as Quux<impl Bar>>::Assoc>) { } -//~^ ERROR `impl Trait` is not allowed in path parameters +//~^ ERROR `impl Trait` is not allowed in paths impl<T> Quux<T> for () { type Assoc = u32; } fn main() { } diff --git a/tests/ui/impl-trait/issues/issue-57979-impl-trait-in-path.stderr b/tests/ui/impl-trait/issues/issue-57979-impl-trait-in-path.stderr index 55f47785f0e..25547dfa66f 100644 --- a/tests/ui/impl-trait/issues/issue-57979-impl-trait-in-path.stderr +++ b/tests/ui/impl-trait/issues/issue-57979-impl-trait-in-path.stderr @@ -1,9 +1,11 @@ -error[E0667]: `impl Trait` is not allowed in path parameters +error[E0562]: `impl Trait` is not allowed in paths --> $DIR/issue-57979-impl-trait-in-path.rs:8:48 | LL | pub fn demo(_: impl Quux<(), Assoc=<() as Quux<impl Bar>>::Assoc>) { } | ^^^^^^^^ + | + = note: `impl Trait` is only allowed in arguments and return types of functions and methods error: aborting due to 1 previous error -For more information about this error, try `rustc --explain E0667`. +For more information about this error, try `rustc --explain E0562`. diff --git a/tests/ui/impl-trait/nested_impl_trait.stderr b/tests/ui/impl-trait/nested_impl_trait.stderr index 83d1347aff4..31c3e0c9013 100644 --- a/tests/ui/impl-trait/nested_impl_trait.stderr +++ b/tests/ui/impl-trait/nested_impl_trait.stderr @@ -46,7 +46,7 @@ error[E0277]: the trait bound `impl Debug: From<impl Into<u32>>` is not satisfie --> $DIR/nested_impl_trait.rs:6:46 | LL | fn bad_in_ret_position(x: impl Into<u32>) -> impl Into<impl Debug> { x } - | ^^^^^^^^^^^^^^^^^^^^^ the trait `From<impl Into<u32>>` is not implemented for `impl Debug`, which is required by `impl Into<u32>: Into<impl Debug>` + | ^^^^^^^^^^^^^^^^^^^^^ the trait `From<impl Into<u32>>` is not implemented for `impl Debug` | = help: the trait `Into<U>` is implemented for `T` = note: required for `impl Into<u32>` to implement `Into<impl Debug>` @@ -55,7 +55,7 @@ error[E0277]: the trait bound `impl Debug: From<impl Into<u32>>` is not satisfie --> $DIR/nested_impl_trait.rs:19:34 | LL | fn bad(x: impl Into<u32>) -> impl Into<impl Debug> { x } - | ^^^^^^^^^^^^^^^^^^^^^ the trait `From<impl Into<u32>>` is not implemented for `impl Debug`, which is required by `impl Into<u32>: Into<impl Debug>` + | ^^^^^^^^^^^^^^^^^^^^^ the trait `From<impl Into<u32>>` is not implemented for `impl Debug` | = help: the trait `Into<U>` is implemented for `T` = note: required for `impl Into<u32>` to implement `Into<impl Debug>` diff --git a/tests/ui/impl-trait/normalize-tait-in-const.stderr b/tests/ui/impl-trait/normalize-tait-in-const.stderr index b370a5d7eb1..f9142664f1b 100644 --- a/tests/ui/impl-trait/normalize-tait-in-const.stderr +++ b/tests/ui/impl-trait/normalize-tait-in-const.stderr @@ -1,28 +1,28 @@ error: `~const` can only be applied to `#[const_trait]` traits - --> $DIR/normalize-tait-in-const.rs:26:42 + --> $DIR/normalize-tait-in-const.rs:26:35 | LL | const fn with_positive<F: for<'a> ~const Fn(&'a Alias<'a>) + ~const Destruct>(fun: F) { - | ^^^^^^^^^^^^^^^^^ + | ^^^^^^ error: `~const` can only be applied to `#[const_trait]` traits - --> $DIR/normalize-tait-in-const.rs:26:69 + --> $DIR/normalize-tait-in-const.rs:26:62 | LL | const fn with_positive<F: for<'a> ~const Fn(&'a Alias<'a>) + ~const Destruct>(fun: F) { - | ^^^^^^^^ + | ^^^^^^ error: `~const` can only be applied to `#[const_trait]` traits - --> $DIR/normalize-tait-in-const.rs:26:42 + --> $DIR/normalize-tait-in-const.rs:26:35 | LL | const fn with_positive<F: for<'a> ~const Fn(&'a Alias<'a>) + ~const Destruct>(fun: F) { - | ^^^^^^^^^^^^^^^^^ + | ^^^^^^ | = note: duplicate diagnostic emitted due to `-Z deduplicate-diagnostics=no` error: `~const` can only be applied to `#[const_trait]` traits - --> $DIR/normalize-tait-in-const.rs:26:69 + --> $DIR/normalize-tait-in-const.rs:26:62 | LL | const fn with_positive<F: for<'a> ~const Fn(&'a Alias<'a>) + ~const Destruct>(fun: F) { - | ^^^^^^^^ + | ^^^^^^ | = note: duplicate diagnostic emitted due to `-Z deduplicate-diagnostics=no` diff --git a/tests/ui/indexing/index-help.stderr b/tests/ui/indexing/index-help.stderr index 1291bf2a461..4ec28ddf871 100644 --- a/tests/ui/indexing/index-help.stderr +++ b/tests/ui/indexing/index-help.stderr @@ -4,7 +4,7 @@ error[E0277]: the type `[{integer}]` cannot be indexed by `i32` LL | x[0i32]; | ^^^^ slice indices are of type `usize` or ranges of `usize` | - = help: the trait `SliceIndex<[{integer}]>` is not implemented for `i32`, which is required by `Vec<{integer}>: Index<_>` + = help: the trait `SliceIndex<[{integer}]>` is not implemented for `i32` = help: the trait `SliceIndex<[{integer}]>` is implemented for `usize` = help: for that trait implementation, expected `usize`, found `i32` = note: required for `Vec<{integer}>` to implement `Index<i32>` diff --git a/tests/ui/indexing/indexing-requires-a-uint.stderr b/tests/ui/indexing/indexing-requires-a-uint.stderr index 38e7881dcc6..3041c2c99a1 100644 --- a/tests/ui/indexing/indexing-requires-a-uint.stderr +++ b/tests/ui/indexing/indexing-requires-a-uint.stderr @@ -4,7 +4,7 @@ error[E0277]: the type `[{integer}]` cannot be indexed by `u8` LL | [0][0u8]; | ^^^ slice indices are of type `usize` or ranges of `usize` | - = help: the trait `SliceIndex<[{integer}]>` is not implemented for `u8`, which is required by `[{integer}; 1]: Index<_>` + = help: the trait `SliceIndex<[{integer}]>` is not implemented for `u8` = help: the trait `SliceIndex<[{integer}]>` is implemented for `usize` = help: for that trait implementation, expected `usize`, found `u8` = note: required for `[{integer}]` to implement `Index<u8>` diff --git a/tests/ui/indexing/point-at-index-for-obligation-failure.stderr b/tests/ui/indexing/point-at-index-for-obligation-failure.stderr index df4d7cc0683..4cced22789f 100644 --- a/tests/ui/indexing/point-at-index-for-obligation-failure.stderr +++ b/tests/ui/indexing/point-at-index-for-obligation-failure.stderr @@ -2,7 +2,7 @@ error[E0277]: the trait bound `String: Borrow<&str>` is not satisfied --> $DIR/point-at-index-for-obligation-failure.rs:5:9 | LL | &s - | ^^ the trait `Borrow<&str>` is not implemented for `String`, which is required by `HashMap<String, String>: Index<&_>` + | ^^ the trait `Borrow<&str>` is not implemented for `String` | = help: the trait `Borrow<str>` is implemented for `String` = help: for that trait implementation, expected `str`, found `&str` diff --git a/tests/ui/integral-indexing.stderr b/tests/ui/integral-indexing.stderr index ad2c3af424b..97e658617cf 100644 --- a/tests/ui/integral-indexing.stderr +++ b/tests/ui/integral-indexing.stderr @@ -4,7 +4,7 @@ error[E0277]: the type `[isize]` cannot be indexed by `u8` LL | v[3u8]; | ^^^ slice indices are of type `usize` or ranges of `usize` | - = help: the trait `SliceIndex<[isize]>` is not implemented for `u8`, which is required by `Vec<isize>: Index<_>` + = help: the trait `SliceIndex<[isize]>` is not implemented for `u8` = help: the trait `SliceIndex<[isize]>` is implemented for `usize` = help: for that trait implementation, expected `usize`, found `u8` = note: required for `Vec<isize>` to implement `Index<u8>` @@ -15,7 +15,7 @@ error[E0277]: the type `[isize]` cannot be indexed by `i8` LL | v[3i8]; | ^^^ slice indices are of type `usize` or ranges of `usize` | - = help: the trait `SliceIndex<[isize]>` is not implemented for `i8`, which is required by `Vec<isize>: Index<_>` + = help: the trait `SliceIndex<[isize]>` is not implemented for `i8` = help: the trait `SliceIndex<[isize]>` is implemented for `usize` = help: for that trait implementation, expected `usize`, found `i8` = note: required for `Vec<isize>` to implement `Index<i8>` @@ -26,7 +26,7 @@ error[E0277]: the type `[isize]` cannot be indexed by `u32` LL | v[3u32]; | ^^^^ slice indices are of type `usize` or ranges of `usize` | - = help: the trait `SliceIndex<[isize]>` is not implemented for `u32`, which is required by `Vec<isize>: Index<_>` + = help: the trait `SliceIndex<[isize]>` is not implemented for `u32` = help: the trait `SliceIndex<[isize]>` is implemented for `usize` = help: for that trait implementation, expected `usize`, found `u32` = note: required for `Vec<isize>` to implement `Index<u32>` @@ -37,7 +37,7 @@ error[E0277]: the type `[isize]` cannot be indexed by `i32` LL | v[3i32]; | ^^^^ slice indices are of type `usize` or ranges of `usize` | - = help: the trait `SliceIndex<[isize]>` is not implemented for `i32`, which is required by `Vec<isize>: Index<_>` + = help: the trait `SliceIndex<[isize]>` is not implemented for `i32` = help: the trait `SliceIndex<[isize]>` is implemented for `usize` = help: for that trait implementation, expected `usize`, found `i32` = note: required for `Vec<isize>` to implement `Index<i32>` @@ -48,7 +48,7 @@ error[E0277]: the type `[u8]` cannot be indexed by `u8` LL | s.as_bytes()[3u8]; | ^^^ slice indices are of type `usize` or ranges of `usize` | - = help: the trait `SliceIndex<[u8]>` is not implemented for `u8`, which is required by `[u8]: Index<_>` + = help: the trait `SliceIndex<[u8]>` is not implemented for `u8` = help: the trait `SliceIndex<[u8]>` is implemented for `usize` = help: for that trait implementation, expected `usize`, found `u8` = note: required for `[u8]` to implement `Index<u8>` @@ -59,7 +59,7 @@ error[E0277]: the type `[u8]` cannot be indexed by `i8` LL | s.as_bytes()[3i8]; | ^^^ slice indices are of type `usize` or ranges of `usize` | - = help: the trait `SliceIndex<[u8]>` is not implemented for `i8`, which is required by `[u8]: Index<_>` + = help: the trait `SliceIndex<[u8]>` is not implemented for `i8` = help: the trait `SliceIndex<[u8]>` is implemented for `usize` = help: for that trait implementation, expected `usize`, found `i8` = note: required for `[u8]` to implement `Index<i8>` @@ -70,7 +70,7 @@ error[E0277]: the type `[u8]` cannot be indexed by `u32` LL | s.as_bytes()[3u32]; | ^^^^ slice indices are of type `usize` or ranges of `usize` | - = help: the trait `SliceIndex<[u8]>` is not implemented for `u32`, which is required by `[u8]: Index<_>` + = help: the trait `SliceIndex<[u8]>` is not implemented for `u32` = help: the trait `SliceIndex<[u8]>` is implemented for `usize` = help: for that trait implementation, expected `usize`, found `u32` = note: required for `[u8]` to implement `Index<u32>` @@ -81,7 +81,7 @@ error[E0277]: the type `[u8]` cannot be indexed by `i32` LL | s.as_bytes()[3i32]; | ^^^^ slice indices are of type `usize` or ranges of `usize` | - = help: the trait `SliceIndex<[u8]>` is not implemented for `i32`, which is required by `[u8]: Index<_>` + = help: the trait `SliceIndex<[u8]>` is not implemented for `i32` = help: the trait `SliceIndex<[u8]>` is implemented for `usize` = help: for that trait implementation, expected `usize`, found `i32` = note: required for `[u8]` to implement `Index<i32>` diff --git a/tests/ui/interior-mutability/interior-mutability.stderr b/tests/ui/interior-mutability/interior-mutability.stderr index 29b250c1b07..cfc64445bf3 100644 --- a/tests/ui/interior-mutability/interior-mutability.stderr +++ b/tests/ui/interior-mutability/interior-mutability.stderr @@ -6,7 +6,7 @@ LL | catch_unwind(|| { x.set(23); }); | | | required by a bound introduced by this call | - = help: within `Cell<i32>`, the trait `RefUnwindSafe` is not implemented for `UnsafeCell<i32>`, which is required by `{closure@$DIR/interior-mutability.rs:5:18: 5:20}: UnwindSafe` + = help: within `Cell<i32>`, the trait `RefUnwindSafe` is not implemented for `UnsafeCell<i32>` note: required because it appears within the type `Cell<i32>` --> $SRC_DIR/core/src/cell.rs:LL:COL = note: required for `&Cell<i32>` to implement `UnwindSafe` diff --git a/tests/ui/intrinsics/safe-intrinsic-mismatch.effects.stderr b/tests/ui/intrinsics/safe-intrinsic-mismatch.effects.stderr index 55983a445a4..c59e357b275 100644 --- a/tests/ui/intrinsics/safe-intrinsic-mismatch.effects.stderr +++ b/tests/ui/intrinsics/safe-intrinsic-mismatch.effects.stderr @@ -1,8 +1,3 @@ -error: using `#![feature(effects)]` without enabling next trait solver globally - | - = note: the next trait solver must be enabled globally for the effects feature to work correctly - = help: use `-Znext-solver` to enable - error: intrinsic safety mismatch between list of intrinsics within the compiler and core library intrinsics for intrinsic `size_of` --> $DIR/safe-intrinsic-mismatch.rs:11:5 | @@ -47,6 +42,6 @@ LL | const fn const_deallocate(_ptr: *mut u8, _size: usize, _align: usize) {} = note: expected signature `unsafe fn(_, _, _)` found signature `fn(_, _, _)` -error: aborting due to 7 previous errors +error: aborting due to 6 previous errors For more information about this error, try `rustc --explain E0308`. diff --git a/tests/ui/issues/issue-21763.stderr b/tests/ui/issues/issue-21763.stderr index aa4938a0c0b..135b705eeef 100644 --- a/tests/ui/issues/issue-21763.stderr +++ b/tests/ui/issues/issue-21763.stderr @@ -4,7 +4,7 @@ error[E0277]: `Rc<()>` cannot be sent between threads safely LL | foo::<HashMap<Rc<()>, Rc<()>>>(); | ^^^^^^^^^^^^^^^^^^^^^^^ `Rc<()>` cannot be sent between threads safely | - = help: within `(Rc<()>, Rc<()>)`, the trait `Send` is not implemented for `Rc<()>`, which is required by `HashMap<Rc<()>, Rc<()>>: Send` + = help: within `(Rc<()>, Rc<()>)`, the trait `Send` is not implemented for `Rc<()>` = note: required because it appears within the type `(Rc<()>, Rc<()>)` = note: required for `hashbrown::raw::RawTable<(Rc<()>, Rc<()>)>` to implement `Send` note: required because it appears within the type `hashbrown::map::HashMap<Rc<()>, Rc<()>, RandomState>` diff --git a/tests/ui/issues/issue-22872.stderr b/tests/ui/issues/issue-22872.stderr index 03e5393da48..6ff710b1133 100644 --- a/tests/ui/issues/issue-22872.stderr +++ b/tests/ui/issues/issue-22872.stderr @@ -4,7 +4,7 @@ error[E0277]: `<P as Process<'_>>::Item` is not an iterator LL | let _: Box<dyn for<'b> Wrap<'b>> = Box::new(Wrapper(process)); | ^^^^^^^^^^^^^^^^^^^^^^^^^^ `<P as Process<'_>>::Item` is not an iterator | - = help: the trait `Iterator` is not implemented for `<P as Process<'_>>::Item`, which is required by `for<'b> Wrapper<P>: Wrap<'b>` + = help: the trait `Iterator` is not implemented for `<P as Process<'_>>::Item` note: required for `Wrapper<P>` to implement `for<'b> Wrap<'b>` --> $DIR/issue-22872.rs:7:13 | diff --git a/tests/ui/issues/issue-22874.stderr b/tests/ui/issues/issue-22874.stderr index 29ddf9756ff..7d5b601ed49 100644 --- a/tests/ui/issues/issue-22874.stderr +++ b/tests/ui/issues/issue-22874.stderr @@ -13,7 +13,7 @@ error[E0277]: the size for values of type `[String]` cannot be known at compilat LL | &table.rows[0] | ^^^^^^^^^^ doesn't have a size known at compile-time | - = help: the trait `Sized` is not implemented for `[String]`, which is required by `[_]: Index<_>` + = help: the trait `Sized` is not implemented for `[String]` = note: required for `[[String]]` to implement `Index<_>` error: aborting due to 2 previous errors diff --git a/tests/ui/issues/issue-40827.stderr b/tests/ui/issues/issue-40827.stderr index 44ae90cbc0f..7f5c578ae4f 100644 --- a/tests/ui/issues/issue-40827.stderr +++ b/tests/ui/issues/issue-40827.stderr @@ -6,7 +6,7 @@ LL | f(Foo(Arc::new(Bar::B(None)))); | | | required by a bound introduced by this call | - = help: within `Bar`, the trait `Sync` is not implemented for `Rc<Foo>`, which is required by `Foo: Send` + = help: within `Bar`, the trait `Sync` is not implemented for `Rc<Foo>` note: required because it appears within the type `Bar` --> $DIR/issue-40827.rs:6:6 | @@ -32,7 +32,7 @@ LL | f(Foo(Arc::new(Bar::B(None)))); | | | required by a bound introduced by this call | - = help: within `Bar`, the trait `Send` is not implemented for `Rc<Foo>`, which is required by `Foo: Send` + = help: within `Bar`, the trait `Send` is not implemented for `Rc<Foo>` note: required because it appears within the type `Bar` --> $DIR/issue-40827.rs:6:6 | diff --git a/tests/ui/issues/issue-7364.stderr b/tests/ui/issues/issue-7364.stderr index d5b6dde1f10..65ec1d75053 100644 --- a/tests/ui/issues/issue-7364.stderr +++ b/tests/ui/issues/issue-7364.stderr @@ -4,7 +4,7 @@ error[E0277]: `RefCell<isize>` cannot be shared between threads safely LL | static boxed: Box<RefCell<isize>> = Box::new(RefCell::new(0)); | ^^^^^^^^^^^^^^^^^^^ `RefCell<isize>` cannot be shared between threads safely | - = help: the trait `Sync` is not implemented for `RefCell<isize>`, which is required by `Box<RefCell<isize>>: Sync` + = help: the trait `Sync` is not implemented for `RefCell<isize>` = note: if you want to do aliasing and mutation between multiple threads, use `std::sync::RwLock` instead = note: required for `Unique<RefCell<isize>>` to implement `Sync` note: required because it appears within the type `Box<RefCell<isize>>` diff --git a/tests/ui/iterators/float_iterator_hint.stderr b/tests/ui/iterators/float_iterator_hint.stderr index 29319b9400f..c3cb00c3c68 100644 --- a/tests/ui/iterators/float_iterator_hint.stderr +++ b/tests/ui/iterators/float_iterator_hint.stderr @@ -4,7 +4,7 @@ error[E0277]: `{float}` is not an iterator LL | for i in 0.2 { | ^^^ `{float}` is not an iterator | - = help: the trait `Iterator` is not implemented for `{float}`, which is required by `{float}: IntoIterator` + = help: the trait `Iterator` is not implemented for `{float}` = note: if you want to iterate between `start` until a value `end`, use the exclusive range syntax `start..end` or the inclusive range syntax `start..=end` = note: required for `{float}` to implement `IntoIterator` diff --git a/tests/ui/iterators/integral.stderr b/tests/ui/iterators/integral.stderr index 74bbe28d6b7..c142fec8da0 100644 --- a/tests/ui/iterators/integral.stderr +++ b/tests/ui/iterators/integral.stderr @@ -4,7 +4,7 @@ error[E0277]: `{integer}` is not an iterator LL | for _ in 42 {} | ^^ `{integer}` is not an iterator | - = help: the trait `Iterator` is not implemented for `{integer}`, which is required by `{integer}: IntoIterator` + = help: the trait `Iterator` is not implemented for `{integer}` = note: if you want to iterate between `start` until a value `end`, use the exclusive range syntax `start..end` or the inclusive range syntax `start..=end` = note: required for `{integer}` to implement `IntoIterator` @@ -14,7 +14,7 @@ error[E0277]: `u8` is not an iterator LL | for _ in 42 as u8 {} | ^^^^^^^^ `u8` is not an iterator | - = help: the trait `Iterator` is not implemented for `u8`, which is required by `u8: IntoIterator` + = help: the trait `Iterator` is not implemented for `u8` = note: if you want to iterate between `start` until a value `end`, use the exclusive range syntax `start..end` or the inclusive range syntax `start..=end` = note: required for `u8` to implement `IntoIterator` @@ -24,7 +24,7 @@ error[E0277]: `i8` is not an iterator LL | for _ in 42 as i8 {} | ^^^^^^^^ `i8` is not an iterator | - = help: the trait `Iterator` is not implemented for `i8`, which is required by `i8: IntoIterator` + = help: the trait `Iterator` is not implemented for `i8` = note: if you want to iterate between `start` until a value `end`, use the exclusive range syntax `start..end` or the inclusive range syntax `start..=end` = note: required for `i8` to implement `IntoIterator` @@ -34,7 +34,7 @@ error[E0277]: `u16` is not an iterator LL | for _ in 42 as u16 {} | ^^^^^^^^^ `u16` is not an iterator | - = help: the trait `Iterator` is not implemented for `u16`, which is required by `u16: IntoIterator` + = help: the trait `Iterator` is not implemented for `u16` = note: if you want to iterate between `start` until a value `end`, use the exclusive range syntax `start..end` or the inclusive range syntax `start..=end` = note: required for `u16` to implement `IntoIterator` @@ -44,7 +44,7 @@ error[E0277]: `i16` is not an iterator LL | for _ in 42 as i16 {} | ^^^^^^^^^ `i16` is not an iterator | - = help: the trait `Iterator` is not implemented for `i16`, which is required by `i16: IntoIterator` + = help: the trait `Iterator` is not implemented for `i16` = note: if you want to iterate between `start` until a value `end`, use the exclusive range syntax `start..end` or the inclusive range syntax `start..=end` = note: required for `i16` to implement `IntoIterator` @@ -54,7 +54,7 @@ error[E0277]: `u32` is not an iterator LL | for _ in 42 as u32 {} | ^^^^^^^^^ `u32` is not an iterator | - = help: the trait `Iterator` is not implemented for `u32`, which is required by `u32: IntoIterator` + = help: the trait `Iterator` is not implemented for `u32` = note: if you want to iterate between `start` until a value `end`, use the exclusive range syntax `start..end` or the inclusive range syntax `start..=end` = note: required for `u32` to implement `IntoIterator` @@ -64,7 +64,7 @@ error[E0277]: `i32` is not an iterator LL | for _ in 42 as i32 {} | ^^^^^^^^^ `i32` is not an iterator | - = help: the trait `Iterator` is not implemented for `i32`, which is required by `i32: IntoIterator` + = help: the trait `Iterator` is not implemented for `i32` = note: if you want to iterate between `start` until a value `end`, use the exclusive range syntax `start..end` or the inclusive range syntax `start..=end` = note: required for `i32` to implement `IntoIterator` @@ -74,7 +74,7 @@ error[E0277]: `u64` is not an iterator LL | for _ in 42 as u64 {} | ^^^^^^^^^ `u64` is not an iterator | - = help: the trait `Iterator` is not implemented for `u64`, which is required by `u64: IntoIterator` + = help: the trait `Iterator` is not implemented for `u64` = note: if you want to iterate between `start` until a value `end`, use the exclusive range syntax `start..end` or the inclusive range syntax `start..=end` = note: required for `u64` to implement `IntoIterator` @@ -84,7 +84,7 @@ error[E0277]: `i64` is not an iterator LL | for _ in 42 as i64 {} | ^^^^^^^^^ `i64` is not an iterator | - = help: the trait `Iterator` is not implemented for `i64`, which is required by `i64: IntoIterator` + = help: the trait `Iterator` is not implemented for `i64` = note: if you want to iterate between `start` until a value `end`, use the exclusive range syntax `start..end` or the inclusive range syntax `start..=end` = note: required for `i64` to implement `IntoIterator` @@ -94,7 +94,7 @@ error[E0277]: `usize` is not an iterator LL | for _ in 42 as usize {} | ^^^^^^^^^^^ `usize` is not an iterator | - = help: the trait `Iterator` is not implemented for `usize`, which is required by `usize: IntoIterator` + = help: the trait `Iterator` is not implemented for `usize` = note: if you want to iterate between `start` until a value `end`, use the exclusive range syntax `start..end` or the inclusive range syntax `start..=end` = note: required for `usize` to implement `IntoIterator` @@ -104,7 +104,7 @@ error[E0277]: `isize` is not an iterator LL | for _ in 42 as isize {} | ^^^^^^^^^^^ `isize` is not an iterator | - = help: the trait `Iterator` is not implemented for `isize`, which is required by `isize: IntoIterator` + = help: the trait `Iterator` is not implemented for `isize` = note: if you want to iterate between `start` until a value `end`, use the exclusive range syntax `start..end` or the inclusive range syntax `start..=end` = note: required for `isize` to implement `IntoIterator` @@ -114,7 +114,7 @@ error[E0277]: `{float}` is not an iterator LL | for _ in 42.0 {} | ^^^^ `{float}` is not an iterator | - = help: the trait `Iterator` is not implemented for `{float}`, which is required by `{float}: IntoIterator` + = help: the trait `Iterator` is not implemented for `{float}` = note: if you want to iterate between `start` until a value `end`, use the exclusive range syntax `start..end` or the inclusive range syntax `start..=end` = note: required for `{float}` to implement `IntoIterator` diff --git a/tests/ui/iterators/issue-28098.stderr b/tests/ui/iterators/issue-28098.stderr index 3cb1b2f7270..a724f03ad4a 100644 --- a/tests/ui/iterators/issue-28098.stderr +++ b/tests/ui/iterators/issue-28098.stderr @@ -14,7 +14,7 @@ error[E0277]: `bool` is not an iterator LL | for _ in false {} | ^^^^^ `bool` is not an iterator | - = help: the trait `Iterator` is not implemented for `bool`, which is required by `bool: IntoIterator` + = help: the trait `Iterator` is not implemented for `bool` = note: required for `bool` to implement `IntoIterator` error[E0277]: `()` is not an iterator @@ -61,7 +61,7 @@ error[E0277]: `bool` is not an iterator LL | for _ in false {} | ^^^^^ `bool` is not an iterator | - = help: the trait `Iterator` is not implemented for `bool`, which is required by `bool: IntoIterator` + = help: the trait `Iterator` is not implemented for `bool` = note: required for `bool` to implement `IntoIterator` error[E0277]: `()` is not an iterator diff --git a/tests/ui/iterators/ranges.stderr b/tests/ui/iterators/ranges.stderr index a5d43ecbb63..b9fbcd5304b 100644 --- a/tests/ui/iterators/ranges.stderr +++ b/tests/ui/iterators/ranges.stderr @@ -4,7 +4,7 @@ error[E0277]: `RangeTo<{integer}>` is not an iterator LL | for _ in ..10 {} | ^^^^ if you meant to iterate until a value, add a starting value | - = help: the trait `Iterator` is not implemented for `RangeTo<{integer}>`, which is required by `RangeTo<{integer}>: IntoIterator` + = help: the trait `Iterator` is not implemented for `RangeTo<{integer}>` = note: `..end` is a `RangeTo`, which cannot be iterated on; you might have meant to have a bounded `Range`: `0..end` = note: required for `RangeTo<{integer}>` to implement `IntoIterator` @@ -14,7 +14,7 @@ error[E0277]: `RangeToInclusive<{integer}>` is not an iterator LL | for _ in ..=10 {} | ^^^^^ if you meant to iterate until a value (including it), add a starting value | - = help: the trait `Iterator` is not implemented for `RangeToInclusive<{integer}>`, which is required by `RangeToInclusive<{integer}>: IntoIterator` + = help: the trait `Iterator` is not implemented for `RangeToInclusive<{integer}>` = note: `..=end` is a `RangeToInclusive`, which cannot be iterated on; you might have meant to have a bounded `RangeInclusive`: `0..=end` = note: required for `RangeToInclusive<{integer}>` to implement `IntoIterator` diff --git a/tests/ui/iterators/string.stderr b/tests/ui/iterators/string.stderr index 29f560677c0..ddfe0169b84 100644 --- a/tests/ui/iterators/string.stderr +++ b/tests/ui/iterators/string.stderr @@ -4,7 +4,7 @@ error[E0277]: `String` is not an iterator LL | for _ in "".to_owned() {} | ^^^^^^^^^^^^^ `String` is not an iterator; try calling `.chars()` or `.bytes()` | - = help: the trait `Iterator` is not implemented for `String`, which is required by `String: IntoIterator` + = help: the trait `Iterator` is not implemented for `String` = note: required for `String` to implement `IntoIterator` error[E0277]: `&str` is not an iterator @@ -13,7 +13,7 @@ error[E0277]: `&str` is not an iterator LL | for _ in "" {} | ^^ `&str` is not an iterator; try calling `.chars()` or `.bytes()` | - = help: the trait `Iterator` is not implemented for `&str`, which is required by `&str: IntoIterator` + = help: the trait `Iterator` is not implemented for `&str` = note: required for `&str` to implement `IntoIterator` error: aborting due to 2 previous errors diff --git a/tests/ui/kindck/kindck-impl-type-params-2.stderr b/tests/ui/kindck/kindck-impl-type-params-2.stderr index a7d169d3ac4..38dc94f9104 100644 --- a/tests/ui/kindck/kindck-impl-type-params-2.stderr +++ b/tests/ui/kindck/kindck-impl-type-params-2.stderr @@ -2,7 +2,7 @@ error[E0277]: the trait bound `Box<{integer}>: Foo` is not satisfied --> $DIR/kindck-impl-type-params-2.rs:13:16 | LL | take_param(&x); - | ---------- ^^ the trait `Copy` is not implemented for `Box<{integer}>`, which is required by `Box<{integer}>: Foo` + | ---------- ^^ the trait `Copy` is not implemented for `Box<{integer}>` | | | required by a bound introduced by this call | diff --git a/tests/ui/kindck/kindck-impl-type-params.stderr b/tests/ui/kindck/kindck-impl-type-params.stderr index 5892596dc6a..da9a8e5532c 100644 --- a/tests/ui/kindck/kindck-impl-type-params.stderr +++ b/tests/ui/kindck/kindck-impl-type-params.stderr @@ -21,7 +21,7 @@ error[E0277]: the trait bound `T: Copy` is not satisfied --> $DIR/kindck-impl-type-params.rs:16:13 | LL | let a = &t as &dyn Gettable<T>; - | ^^ the trait `Copy` is not implemented for `T`, which is required by `S<T>: Gettable<T>` + | ^^ the trait `Copy` is not implemented for `T` | note: required for `S<T>` to implement `Gettable<T>` --> $DIR/kindck-impl-type-params.rs:12:32 @@ -59,7 +59,7 @@ error[E0277]: the trait bound `T: Copy` is not satisfied --> $DIR/kindck-impl-type-params.rs:23:31 | LL | let a: &dyn Gettable<T> = &t; - | ^^ the trait `Copy` is not implemented for `T`, which is required by `S<T>: Gettable<T>` + | ^^ the trait `Copy` is not implemented for `T` | note: required for `S<T>` to implement `Gettable<T>` --> $DIR/kindck-impl-type-params.rs:12:32 @@ -78,7 +78,7 @@ error[E0277]: the trait bound `String: Copy` is not satisfied --> $DIR/kindck-impl-type-params.rs:36:13 | LL | let a = t as Box<dyn Gettable<String>>; - | ^ the trait `Copy` is not implemented for `String`, which is required by `S<String>: Gettable<String>` + | ^ the trait `Copy` is not implemented for `String` | = help: the trait `Gettable<T>` is implemented for `S<T>` note: required for `S<String>` to implement `Gettable<String>` @@ -94,7 +94,7 @@ error[E0277]: the trait bound `Foo: Copy` is not satisfied --> $DIR/kindck-impl-type-params.rs:44:37 | LL | let a: Box<dyn Gettable<Foo>> = t; - | ^ the trait `Copy` is not implemented for `Foo`, which is required by `S<Foo>: Gettable<Foo>` + | ^ the trait `Copy` is not implemented for `Foo` | = help: the trait `Gettable<T>` is implemented for `S<T>` note: required for `S<Foo>` to implement `Gettable<Foo>` diff --git a/tests/ui/kindck/kindck-inherited-copy-bound.curr.stderr b/tests/ui/kindck/kindck-inherited-copy-bound.curr.stderr index e797ca01f4b..c392879db3e 100644 --- a/tests/ui/kindck/kindck-inherited-copy-bound.curr.stderr +++ b/tests/ui/kindck/kindck-inherited-copy-bound.curr.stderr @@ -2,7 +2,7 @@ error[E0277]: the trait bound `Box<{integer}>: Foo` is not satisfied --> $DIR/kindck-inherited-copy-bound.rs:21:16 | LL | take_param(&x); - | ---------- ^^ the trait `Copy` is not implemented for `Box<{integer}>`, which is required by `Box<{integer}>: Foo` + | ---------- ^^ the trait `Copy` is not implemented for `Box<{integer}>` | | | required by a bound introduced by this call | diff --git a/tests/ui/kindck/kindck-inherited-copy-bound.dyn_compatible_for_dispatch.stderr b/tests/ui/kindck/kindck-inherited-copy-bound.dyn_compatible_for_dispatch.stderr index b4424f4750e..34dcad13af3 100644 --- a/tests/ui/kindck/kindck-inherited-copy-bound.dyn_compatible_for_dispatch.stderr +++ b/tests/ui/kindck/kindck-inherited-copy-bound.dyn_compatible_for_dispatch.stderr @@ -2,7 +2,7 @@ error[E0277]: the trait bound `Box<{integer}>: Foo` is not satisfied --> $DIR/kindck-inherited-copy-bound.rs:21:16 | LL | take_param(&x); - | ---------- ^^ the trait `Copy` is not implemented for `Box<{integer}>`, which is required by `Box<{integer}>: Foo` + | ---------- ^^ the trait `Copy` is not implemented for `Box<{integer}>` | | | required by a bound introduced by this call | diff --git a/tests/ui/kindck/kindck-nonsendable-1.stderr b/tests/ui/kindck/kindck-nonsendable-1.stderr index 8cc931bc48e..8bb784d1d49 100644 --- a/tests/ui/kindck/kindck-nonsendable-1.stderr +++ b/tests/ui/kindck/kindck-nonsendable-1.stderr @@ -8,7 +8,7 @@ LL | bar(move|| foo(x)); | | within this `{closure@$DIR/kindck-nonsendable-1.rs:9:9: 9:15}` | required by a bound introduced by this call | - = help: within `{closure@$DIR/kindck-nonsendable-1.rs:9:9: 9:15}`, the trait `Send` is not implemented for `Rc<usize>`, which is required by `{closure@$DIR/kindck-nonsendable-1.rs:9:9: 9:15}: Send` + = help: within `{closure@$DIR/kindck-nonsendable-1.rs:9:9: 9:15}`, the trait `Send` is not implemented for `Rc<usize>` note: required because it's used within this closure --> $DIR/kindck-nonsendable-1.rs:9:9 | diff --git a/tests/ui/kindck/kindck-send-object.stderr b/tests/ui/kindck/kindck-send-object.stderr index 7d0c711abc4..0e2ff1730c8 100644 --- a/tests/ui/kindck/kindck-send-object.stderr +++ b/tests/ui/kindck/kindck-send-object.stderr @@ -4,7 +4,7 @@ error[E0277]: `&'static (dyn Dummy + 'static)` cannot be sent between threads sa LL | assert_send::<&'static (dyn Dummy + 'static)>(); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ `&'static (dyn Dummy + 'static)` cannot be sent between threads safely | - = help: the trait `Sync` is not implemented for `(dyn Dummy + 'static)`, which is required by `&'static (dyn Dummy + 'static): Send` + = help: the trait `Sync` is not implemented for `(dyn Dummy + 'static)` = note: required for `&'static (dyn Dummy + 'static)` to implement `Send` note: required by a bound in `assert_send` --> $DIR/kindck-send-object.rs:5:18 @@ -18,7 +18,7 @@ error[E0277]: `dyn Dummy` cannot be sent between threads safely LL | assert_send::<Box<dyn Dummy>>(); | ^^^^^^^^^^^^^^ `dyn Dummy` cannot be sent between threads safely | - = help: the trait `Send` is not implemented for `dyn Dummy`, which is required by `Box<dyn Dummy>: Send` + = help: the trait `Send` is not implemented for `dyn Dummy` = note: required for `Unique<dyn Dummy>` to implement `Send` note: required because it appears within the type `Box<dyn Dummy>` --> $SRC_DIR/alloc/src/boxed.rs:LL:COL diff --git a/tests/ui/kindck/kindck-send-object1.stderr b/tests/ui/kindck/kindck-send-object1.stderr index 7f39dab2086..e3ff2eb9ff4 100644 --- a/tests/ui/kindck/kindck-send-object1.stderr +++ b/tests/ui/kindck/kindck-send-object1.stderr @@ -4,7 +4,7 @@ error[E0277]: `&'a (dyn Dummy + 'a)` cannot be sent between threads safely LL | assert_send::<&'a dyn Dummy>(); | ^^^^^^^^^^^^^ `&'a (dyn Dummy + 'a)` cannot be sent between threads safely | - = help: the trait `Sync` is not implemented for `(dyn Dummy + 'a)`, which is required by `&'a (dyn Dummy + 'a): Send` + = help: the trait `Sync` is not implemented for `(dyn Dummy + 'a)` = note: required for `&'a (dyn Dummy + 'a)` to implement `Send` note: required by a bound in `assert_send` --> $DIR/kindck-send-object1.rs:5:18 @@ -18,7 +18,7 @@ error[E0277]: `(dyn Dummy + 'a)` cannot be sent between threads safely LL | assert_send::<Box<dyn Dummy + 'a>>(); | ^^^^^^^^^^^^^^^^^^^ `(dyn Dummy + 'a)` cannot be sent between threads safely | - = help: the trait `Send` is not implemented for `(dyn Dummy + 'a)`, which is required by `Box<(dyn Dummy + 'a)>: Send` + = help: the trait `Send` is not implemented for `(dyn Dummy + 'a)` = note: required for `Unique<(dyn Dummy + 'a)>` to implement `Send` note: required because it appears within the type `Box<(dyn Dummy + 'a)>` --> $SRC_DIR/alloc/src/boxed.rs:LL:COL diff --git a/tests/ui/kindck/kindck-send-object2.stderr b/tests/ui/kindck/kindck-send-object2.stderr index a481a132cce..8898bf5b3fa 100644 --- a/tests/ui/kindck/kindck-send-object2.stderr +++ b/tests/ui/kindck/kindck-send-object2.stderr @@ -4,7 +4,7 @@ error[E0277]: `&'static (dyn Dummy + 'static)` cannot be sent between threads sa LL | assert_send::<&'static dyn Dummy>(); | ^^^^^^^^^^^^^^^^^^ `&'static (dyn Dummy + 'static)` cannot be sent between threads safely | - = help: the trait `Sync` is not implemented for `(dyn Dummy + 'static)`, which is required by `&'static (dyn Dummy + 'static): Send` + = help: the trait `Sync` is not implemented for `(dyn Dummy + 'static)` = note: required for `&'static (dyn Dummy + 'static)` to implement `Send` note: required by a bound in `assert_send` --> $DIR/kindck-send-object2.rs:3:18 @@ -18,7 +18,7 @@ error[E0277]: `dyn Dummy` cannot be sent between threads safely LL | assert_send::<Box<dyn Dummy>>(); | ^^^^^^^^^^^^^^ `dyn Dummy` cannot be sent between threads safely | - = help: the trait `Send` is not implemented for `dyn Dummy`, which is required by `Box<dyn Dummy>: Send` + = help: the trait `Send` is not implemented for `dyn Dummy` = note: required for `Unique<dyn Dummy>` to implement `Send` note: required because it appears within the type `Box<dyn Dummy>` --> $SRC_DIR/alloc/src/boxed.rs:LL:COL diff --git a/tests/ui/kindck/kindck-send-owned.stderr b/tests/ui/kindck/kindck-send-owned.stderr index 4bc0212089b..860a9391bbb 100644 --- a/tests/ui/kindck/kindck-send-owned.stderr +++ b/tests/ui/kindck/kindck-send-owned.stderr @@ -4,7 +4,7 @@ error[E0277]: `*mut u8` cannot be sent between threads safely LL | assert_send::<Box<*mut u8>>(); | ^^^^^^^^^^^^ `*mut u8` cannot be sent between threads safely | - = help: the trait `Send` is not implemented for `*mut u8`, which is required by `Box<*mut u8>: Send` + = help: the trait `Send` is not implemented for `*mut u8` = note: required for `Unique<*mut u8>` to implement `Send` note: required because it appears within the type `Box<*mut u8>` --> $SRC_DIR/alloc/src/boxed.rs:LL:COL diff --git a/tests/ui/linkage-attr/framework.omit.stderr b/tests/ui/linkage-attr/framework.omit.stderr deleted file mode 100644 index 23e017cb012..00000000000 --- a/tests/ui/linkage-attr/framework.omit.stderr +++ /dev/null @@ -1,8 +0,0 @@ -error: linking with `LINKER` failed: exit status: 1 - | - ld: Undefined symbols: - _CFRunLoopGetTypeID, referenced from: - clang: error: linker command failed with exit code 1 (use -v to see invocation) - - -error: aborting due to 1 previous error diff --git a/tests/ui/linkage-attr/framework.rs b/tests/ui/linkage-attr/framework.rs deleted file mode 100644 index 08f4394db21..00000000000 --- a/tests/ui/linkage-attr/framework.rs +++ /dev/null @@ -1,32 +0,0 @@ -// Check that linking frameworks on Apple platforms works. -//@ only-apple -//@ revisions: omit link weak both -//@ [omit]build-fail -//@ [link]run-pass -//@ [weak]run-pass -//@ [both]run-pass - -// The linker's exact error output changes between Xcode versions, depends on -// linker invocation details, and the linker sometimes outputs more warnings. -//@ compare-output-lines-by-subset -//@ normalize-stderr-test: "linking with `.*` failed" -> "linking with `LINKER` failed" -//@ normalize-stderr-test: "Undefined symbols for architecture .*" -> "ld: Undefined symbols:" -//@ normalize-stderr-test: "._CFRunLoopGetTypeID.," -> "_CFRunLoopGetTypeID," - -#![cfg_attr(any(weak, both), feature(link_arg_attribute))] - -#[cfg_attr(any(link, both), link(name = "CoreFoundation", kind = "framework"))] -#[cfg_attr( - any(weak, both), - link(name = "-weak_framework", kind = "link-arg", modifiers = "+verbatim"), - link(name = "CoreFoundation", kind = "link-arg", modifiers = "+verbatim") -)] -extern "C" { - fn CFRunLoopGetTypeID() -> core::ffi::c_ulong; -} - -pub fn main() { - unsafe { - CFRunLoopGetTypeID(); - } -} diff --git a/tests/ui/lint/dangling-pointers-from-temporaries/allow.rs b/tests/ui/lint/dangling-pointers-from-temporaries/allow.rs new file mode 100644 index 00000000000..d892ebdf606 --- /dev/null +++ b/tests/ui/lint/dangling-pointers-from-temporaries/allow.rs @@ -0,0 +1,23 @@ +#![allow(dangling_pointers_from_temporaries)] + +fn main() { + dbg!(String::new().as_ptr()); + // ^ no error + + #[deny(dangling_pointers_from_temporaries)] + { + dbg!(String::new().as_ptr()); + //~^ ERROR a dangling pointer will be produced because the temporary `String` will be dropped + } + S.foo() +} + +struct S; + +impl S { + #[warn(dangling_pointers_from_temporaries)] + fn foo(self) { + dbg!(String::new().as_ptr()); + //~^ WARNING a dangling pointer will be produced because the temporary `String` will be dropped + } +} diff --git a/tests/ui/lint/dangling-pointers-from-temporaries/allow.stderr b/tests/ui/lint/dangling-pointers-from-temporaries/allow.stderr new file mode 100644 index 00000000000..fd434eacf3d --- /dev/null +++ b/tests/ui/lint/dangling-pointers-from-temporaries/allow.stderr @@ -0,0 +1,34 @@ +error: a dangling pointer will be produced because the temporary `String` will be dropped + --> $DIR/allow.rs:9:28 + | +LL | dbg!(String::new().as_ptr()); + | ------------- ^^^^^^ this pointer will immediately be invalid + | | + | this `String` is deallocated at the end of the statement, bind it to a variable to extend its lifetime + | + = note: pointers do not have a lifetime; when calling `as_ptr` the `String` will be deallocated at the end of the statement because nothing is referencing it as far as the type system is concerned + = help: for more information, see <https://doc.rust-lang.org/reference/destructors.html> +note: the lint level is defined here + --> $DIR/allow.rs:7:12 + | +LL | #[deny(dangling_pointers_from_temporaries)] + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + +warning: a dangling pointer will be produced because the temporary `String` will be dropped + --> $DIR/allow.rs:20:28 + | +LL | dbg!(String::new().as_ptr()); + | ------------- ^^^^^^ this pointer will immediately be invalid + | | + | this `String` is deallocated at the end of the statement, bind it to a variable to extend its lifetime + | + = note: pointers do not have a lifetime; when calling `as_ptr` the `String` will be deallocated at the end of the statement because nothing is referencing it as far as the type system is concerned + = help: for more information, see <https://doc.rust-lang.org/reference/destructors.html> +note: the lint level is defined here + --> $DIR/allow.rs:18:12 + | +LL | #[warn(dangling_pointers_from_temporaries)] + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + +error: aborting due to 1 previous error; 1 warning emitted + diff --git a/tests/ui/lint/dangling-pointers-from-temporaries/calls.rs b/tests/ui/lint/dangling-pointers-from-temporaries/calls.rs new file mode 100644 index 00000000000..b376582a886 --- /dev/null +++ b/tests/ui/lint/dangling-pointers-from-temporaries/calls.rs @@ -0,0 +1,52 @@ +#![deny(dangling_pointers_from_temporaries)] + +use std::ffi::{c_char, CString}; + +fn cstring() -> CString { + CString::new("hello").unwrap() +} + +fn consume(ptr: *const c_char) { + let c = unsafe { ptr.read() }; + dbg!(c); +} + +// None of these should trigger the lint. +fn ok() { + consume(cstring().as_ptr()); + consume({ cstring() }.as_ptr()); + consume({ cstring().as_ptr() }); + consume(cstring().as_ptr().cast()); + consume({ cstring() }.as_ptr().cast()); + consume({ cstring().as_ptr() }.cast()); +} + +// All of these should trigger the lint. +fn not_ok() { + { + let ptr = cstring().as_ptr(); + //~^ ERROR a dangling pointer will be produced because the temporary `CString` will be dropped + consume(ptr); + } + consume({ + let ptr = cstring().as_ptr(); + //~^ ERROR a dangling pointer will be produced because the temporary `CString` will be dropped + ptr + }); + consume({ + let s = cstring(); + s.as_ptr() + //^ FIXME: should error + }); + let _ptr: *const u8 = cstring().as_ptr().cast(); + //~^ ERROR a dangling pointer will be produced because the temporary `CString` will be dropped + let _ptr: *const u8 = { cstring() }.as_ptr().cast(); + //~^ ERROR a dangling pointer will be produced because the temporary `CString` will be dropped + let _ptr: *const u8 = { cstring().as_ptr() }.cast(); + //~^ ERROR a dangling pointer will be produced because the temporary `CString` will be dropped +} + +fn main() { + ok(); + not_ok(); +} diff --git a/tests/ui/lint/dangling-pointers-from-temporaries/calls.stderr b/tests/ui/lint/dangling-pointers-from-temporaries/calls.stderr new file mode 100644 index 00000000000..d1615b76d82 --- /dev/null +++ b/tests/ui/lint/dangling-pointers-from-temporaries/calls.stderr @@ -0,0 +1,62 @@ +error: a dangling pointer will be produced because the temporary `CString` will be dropped + --> $DIR/calls.rs:27:29 + | +LL | let ptr = cstring().as_ptr(); + | --------- ^^^^^^ this pointer will immediately be invalid + | | + | this `CString` is deallocated at the end of the statement, bind it to a variable to extend its lifetime + | + = note: pointers do not have a lifetime; when calling `as_ptr` the `CString` will be deallocated at the end of the statement because nothing is referencing it as far as the type system is concerned + = help: for more information, see <https://doc.rust-lang.org/reference/destructors.html> +note: the lint level is defined here + --> $DIR/calls.rs:1:9 + | +LL | #![deny(dangling_pointers_from_temporaries)] + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + +error: a dangling pointer will be produced because the temporary `CString` will be dropped + --> $DIR/calls.rs:32:29 + | +LL | let ptr = cstring().as_ptr(); + | --------- ^^^^^^ this pointer will immediately be invalid + | | + | this `CString` is deallocated at the end of the statement, bind it to a variable to extend its lifetime + | + = note: pointers do not have a lifetime; when calling `as_ptr` the `CString` will be deallocated at the end of the statement because nothing is referencing it as far as the type system is concerned + = help: for more information, see <https://doc.rust-lang.org/reference/destructors.html> + +error: a dangling pointer will be produced because the temporary `CString` will be dropped + --> $DIR/calls.rs:41:37 + | +LL | let _ptr: *const u8 = cstring().as_ptr().cast(); + | --------- ^^^^^^ this pointer will immediately be invalid + | | + | this `CString` is deallocated at the end of the statement, bind it to a variable to extend its lifetime + | + = note: pointers do not have a lifetime; when calling `as_ptr` the `CString` will be deallocated at the end of the statement because nothing is referencing it as far as the type system is concerned + = help: for more information, see <https://doc.rust-lang.org/reference/destructors.html> + +error: a dangling pointer will be produced because the temporary `CString` will be dropped + --> $DIR/calls.rs:43:41 + | +LL | let _ptr: *const u8 = { cstring() }.as_ptr().cast(); + | ------------- ^^^^^^ this pointer will immediately be invalid + | | + | this `CString` is deallocated at the end of the statement, bind it to a variable to extend its lifetime + | + = note: pointers do not have a lifetime; when calling `as_ptr` the `CString` will be deallocated at the end of the statement because nothing is referencing it as far as the type system is concerned + = help: for more information, see <https://doc.rust-lang.org/reference/destructors.html> + +error: a dangling pointer will be produced because the temporary `CString` will be dropped + --> $DIR/calls.rs:45:39 + | +LL | let _ptr: *const u8 = { cstring().as_ptr() }.cast(); + | --------- ^^^^^^ this pointer will immediately be invalid + | | + | this `CString` is deallocated at the end of the statement, bind it to a variable to extend its lifetime + | + = note: pointers do not have a lifetime; when calling `as_ptr` the `CString` will be deallocated at the end of the statement because nothing is referencing it as far as the type system is concerned + = help: for more information, see <https://doc.rust-lang.org/reference/destructors.html> + +error: aborting due to 5 previous errors + diff --git a/tests/ui/lint/lint-temporary-cstring-as-param.rs b/tests/ui/lint/dangling-pointers-from-temporaries/cstring-as-param.rs index 9f5805367e4..fb6ed363272 100644 --- a/tests/ui/lint/lint-temporary-cstring-as-param.rs +++ b/tests/ui/lint/dangling-pointers-from-temporaries/cstring-as-param.rs @@ -1,4 +1,7 @@ +//@ check-pass + #![deny(temporary_cstring_as_ptr)] +//~^ WARNING lint `temporary_cstring_as_ptr` has been renamed to `dangling_pointers_from_temporaries` use std::ffi::CString; use std::os::raw::c_char; @@ -7,5 +10,4 @@ fn some_function(data: *const c_char) {} fn main() { some_function(CString::new("").unwrap().as_ptr()); - //~^ ERROR getting the inner pointer of a temporary `CString` } diff --git a/tests/ui/lint/dangling-pointers-from-temporaries/cstring-as-param.stderr b/tests/ui/lint/dangling-pointers-from-temporaries/cstring-as-param.stderr new file mode 100644 index 00000000000..dd54b4971dd --- /dev/null +++ b/tests/ui/lint/dangling-pointers-from-temporaries/cstring-as-param.stderr @@ -0,0 +1,10 @@ +warning: lint `temporary_cstring_as_ptr` has been renamed to `dangling_pointers_from_temporaries` + --> $DIR/cstring-as-param.rs:3:9 + | +LL | #![deny(temporary_cstring_as_ptr)] + | ^^^^^^^^^^^^^^^^^^^^^^^^ help: use the new name: `dangling_pointers_from_temporaries` + | + = note: `#[warn(renamed_and_removed_lints)]` on by default + +warning: 1 warning emitted + diff --git a/tests/ui/lint/lint-temporary-cstring-as-ptr.rs b/tests/ui/lint/dangling-pointers-from-temporaries/cstring-as-ptr.rs index fab792f1284..a98378794ab 100644 --- a/tests/ui/lint/lint-temporary-cstring-as-ptr.rs +++ b/tests/ui/lint/dangling-pointers-from-temporaries/cstring-as-ptr.rs @@ -1,17 +1,18 @@ // this program is not technically incorrect, but is an obscure enough style to be worth linting #![deny(temporary_cstring_as_ptr)] +//~^ WARNING lint `temporary_cstring_as_ptr` has been renamed to `dangling_pointers_from_temporaries` use std::ffi::CString; macro_rules! mymacro { () => { let s = CString::new("some text").unwrap().as_ptr(); - //~^ ERROR getting the inner pointer of a temporary `CString` + //~^ ERROR a dangling pointer will be produced because the temporary `CString` will be dropped } } fn main() { let s = CString::new("some text").unwrap().as_ptr(); - //~^ ERROR getting the inner pointer of a temporary `CString` + //~^ ERROR a dangling pointer will be produced because the temporary `CString` will be dropped mymacro!(); } diff --git a/tests/ui/lint/lint-temporary-cstring-as-ptr.stderr b/tests/ui/lint/dangling-pointers-from-temporaries/cstring-as-ptr.stderr index 4e5c8aa0693..5289fbb8723 100644 --- a/tests/ui/lint/lint-temporary-cstring-as-ptr.stderr +++ b/tests/ui/lint/dangling-pointers-from-temporaries/cstring-as-ptr.stderr @@ -1,24 +1,32 @@ -error: getting the inner pointer of a temporary `CString` - --> $DIR/lint-temporary-cstring-as-ptr.rs:14:48 +warning: lint `temporary_cstring_as_ptr` has been renamed to `dangling_pointers_from_temporaries` + --> $DIR/cstring-as-ptr.rs:2:9 + | +LL | #![deny(temporary_cstring_as_ptr)] + | ^^^^^^^^^^^^^^^^^^^^^^^^ help: use the new name: `dangling_pointers_from_temporaries` + | + = note: `#[warn(renamed_and_removed_lints)]` on by default + +error: a dangling pointer will be produced because the temporary `CString` will be dropped + --> $DIR/cstring-as-ptr.rs:15:48 | LL | let s = CString::new("some text").unwrap().as_ptr(); - | ---------------------------------- ^^^^^^ this pointer will be invalid + | ---------------------------------- ^^^^^^ this pointer will immediately be invalid | | | this `CString` is deallocated at the end of the statement, bind it to a variable to extend its lifetime | = note: pointers do not have a lifetime; when calling `as_ptr` the `CString` will be deallocated at the end of the statement because nothing is referencing it as far as the type system is concerned - = help: for more information, see https://doc.rust-lang.org/reference/destructors.html + = help: for more information, see <https://doc.rust-lang.org/reference/destructors.html> note: the lint level is defined here - --> $DIR/lint-temporary-cstring-as-ptr.rs:2:9 + --> $DIR/cstring-as-ptr.rs:2:9 | LL | #![deny(temporary_cstring_as_ptr)] | ^^^^^^^^^^^^^^^^^^^^^^^^ -error: getting the inner pointer of a temporary `CString` - --> $DIR/lint-temporary-cstring-as-ptr.rs:8:52 +error: a dangling pointer will be produced because the temporary `CString` will be dropped + --> $DIR/cstring-as-ptr.rs:9:52 | LL | let s = CString::new("some text").unwrap().as_ptr(); - | ---------------------------------- ^^^^^^ this pointer will be invalid + | ---------------------------------- ^^^^^^ this pointer will immediately be invalid | | | this `CString` is deallocated at the end of the statement, bind it to a variable to extend its lifetime ... @@ -26,8 +34,8 @@ LL | mymacro!(); | ---------- in this macro invocation | = note: pointers do not have a lifetime; when calling `as_ptr` the `CString` will be deallocated at the end of the statement because nothing is referencing it as far as the type system is concerned - = help: for more information, see https://doc.rust-lang.org/reference/destructors.html + = help: for more information, see <https://doc.rust-lang.org/reference/destructors.html> = note: this error originates in the macro `mymacro` (in Nightly builds, run with -Z macro-backtrace for more info) -error: aborting due to 2 previous errors +error: aborting due to 2 previous errors; 1 warning emitted diff --git a/tests/ui/lint/dangling-pointers-from-temporaries/emacs.rs b/tests/ui/lint/dangling-pointers-from-temporaries/emacs.rs new file mode 100644 index 00000000000..b9b7bd3ade1 --- /dev/null +++ b/tests/ui/lint/dangling-pointers-from-temporaries/emacs.rs @@ -0,0 +1,19 @@ +//@ check-pass + +#![deny(dangling_pointers_from_temporaries)] + +// The original code example comes from bindgen-produced code for emacs. +// Hence the name of the test. +// https://github.com/rust-lang/rust/pull/128985#issuecomment-2338951363 + +use std::ffi::{c_char, CString}; + +fn read(ptr: *const c_char) -> c_char { + unsafe { ptr.read() } +} + +fn main() { + let fnptr: Option<fn(ptr: *const c_char) -> c_char> = Some(read); + let x = fnptr.unwrap()(CString::new("foo").unwrap().as_ptr()); + assert_eq!(x as u8, b'f'); +} diff --git a/tests/ui/lint/dangling-pointers-from-temporaries/example-from-issue123613.rs b/tests/ui/lint/dangling-pointers-from-temporaries/example-from-issue123613.rs new file mode 100644 index 00000000000..0fb07a3f3bc --- /dev/null +++ b/tests/ui/lint/dangling-pointers-from-temporaries/example-from-issue123613.rs @@ -0,0 +1,13 @@ +#![deny(dangling_pointers_from_temporaries)] + +const MAX_PATH: usize = 260; +fn main() { + let str1 = String::with_capacity(MAX_PATH).as_mut_ptr(); + //~^ ERROR a dangling pointer will be produced because the temporary `String` will be dropped + let str2 = String::from("TotototototototototototototototototoT").as_ptr(); + //~^ ERROR a dangling pointer will be produced because the temporary `String` will be dropped + unsafe { + std::ptr::copy_nonoverlapping(str2, str1, 30); + println!("{:?}", String::from_raw_parts(str1, 30, 30)); + } +} diff --git a/tests/ui/lint/dangling-pointers-from-temporaries/example-from-issue123613.stderr b/tests/ui/lint/dangling-pointers-from-temporaries/example-from-issue123613.stderr new file mode 100644 index 00000000000..0de794f6ae2 --- /dev/null +++ b/tests/ui/lint/dangling-pointers-from-temporaries/example-from-issue123613.stderr @@ -0,0 +1,29 @@ +error: a dangling pointer will be produced because the temporary `String` will be dropped + --> $DIR/example-from-issue123613.rs:5:48 + | +LL | let str1 = String::with_capacity(MAX_PATH).as_mut_ptr(); + | ------------------------------- ^^^^^^^^^^ this pointer will immediately be invalid + | | + | this `String` is deallocated at the end of the statement, bind it to a variable to extend its lifetime + | + = note: pointers do not have a lifetime; when calling `as_mut_ptr` the `String` will be deallocated at the end of the statement because nothing is referencing it as far as the type system is concerned + = help: for more information, see <https://doc.rust-lang.org/reference/destructors.html> +note: the lint level is defined here + --> $DIR/example-from-issue123613.rs:1:9 + | +LL | #![deny(dangling_pointers_from_temporaries)] + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + +error: a dangling pointer will be produced because the temporary `String` will be dropped + --> $DIR/example-from-issue123613.rs:7:70 + | +LL | let str2 = String::from("TotototototototototototototototototoT").as_ptr(); + | ----------------------------------------------------- ^^^^^^ this pointer will immediately be invalid + | | + | this `String` is deallocated at the end of the statement, bind it to a variable to extend its lifetime + | + = note: pointers do not have a lifetime; when calling `as_ptr` the `String` will be deallocated at the end of the statement because nothing is referencing it as far as the type system is concerned + = help: for more information, see <https://doc.rust-lang.org/reference/destructors.html> + +error: aborting due to 2 previous errors + diff --git a/tests/ui/lint/dangling-pointers-from-temporaries/ext.rs b/tests/ui/lint/dangling-pointers-from-temporaries/ext.rs new file mode 100644 index 00000000000..a5e84d36090 --- /dev/null +++ b/tests/ui/lint/dangling-pointers-from-temporaries/ext.rs @@ -0,0 +1,32 @@ +#![deny(dangling_pointers_from_temporaries)] + +use std::fmt::Debug; + +trait Ext1 { + fn dbg(self) -> Self + where + Self: Sized + Debug, + { + dbg!(&self); + self + } +} + +impl<T> Ext1 for *const T {} + +trait Ext2 { + fn foo(self); +} + +impl Ext2 for *const u32 { + fn foo(self) { + dbg!(unsafe { self.read() }); + } +} + +fn main() { + let _ptr1 = Vec::<u32>::new().as_ptr().dbg(); + //~^ ERROR a dangling pointer will be produced because the temporary `Vec<u32>` will be dropped + let _ptr2 = vec![0].as_ptr().foo(); + //~^ ERROR a dangling pointer will be produced because the temporary `Vec<u32>` will be dropped +} diff --git a/tests/ui/lint/dangling-pointers-from-temporaries/ext.stderr b/tests/ui/lint/dangling-pointers-from-temporaries/ext.stderr new file mode 100644 index 00000000000..5d401c89c0c --- /dev/null +++ b/tests/ui/lint/dangling-pointers-from-temporaries/ext.stderr @@ -0,0 +1,29 @@ +error: a dangling pointer will be produced because the temporary `Vec<u32>` will be dropped + --> $DIR/ext.rs:28:35 + | +LL | let _ptr1 = Vec::<u32>::new().as_ptr().dbg(); + | ----------------- ^^^^^^ this pointer will immediately be invalid + | | + | this `Vec<u32>` is deallocated at the end of the statement, bind it to a variable to extend its lifetime + | + = note: pointers do not have a lifetime; when calling `as_ptr` the `Vec<u32>` will be deallocated at the end of the statement because nothing is referencing it as far as the type system is concerned + = help: for more information, see <https://doc.rust-lang.org/reference/destructors.html> +note: the lint level is defined here + --> $DIR/ext.rs:1:9 + | +LL | #![deny(dangling_pointers_from_temporaries)] + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + +error: a dangling pointer will be produced because the temporary `Vec<u32>` will be dropped + --> $DIR/ext.rs:30:25 + | +LL | let _ptr2 = vec![0].as_ptr().foo(); + | ------- ^^^^^^ this pointer will immediately be invalid + | | + | this `Vec<u32>` is deallocated at the end of the statement, bind it to a variable to extend its lifetime + | + = note: pointers do not have a lifetime; when calling `as_ptr` the `Vec<u32>` will be deallocated at the end of the statement because nothing is referencing it as far as the type system is concerned + = help: for more information, see <https://doc.rust-lang.org/reference/destructors.html> + +error: aborting due to 2 previous errors + diff --git a/tests/ui/lint/dangling-pointers-from-temporaries/methods.rs b/tests/ui/lint/dangling-pointers-from-temporaries/methods.rs new file mode 100644 index 00000000000..26019b376d3 --- /dev/null +++ b/tests/ui/lint/dangling-pointers-from-temporaries/methods.rs @@ -0,0 +1,8 @@ +#![deny(dangling_pointers_from_temporaries)] + +fn main() { + vec![0u8].as_ptr(); + //~^ ERROR a dangling pointer will be produced because the temporary `Vec<u8>` will be dropped + vec![0u8].as_mut_ptr(); + //~^ ERROR a dangling pointer will be produced because the temporary `Vec<u8>` will be dropped +} diff --git a/tests/ui/lint/dangling-pointers-from-temporaries/methods.stderr b/tests/ui/lint/dangling-pointers-from-temporaries/methods.stderr new file mode 100644 index 00000000000..11c052c158e --- /dev/null +++ b/tests/ui/lint/dangling-pointers-from-temporaries/methods.stderr @@ -0,0 +1,29 @@ +error: a dangling pointer will be produced because the temporary `Vec<u8>` will be dropped + --> $DIR/methods.rs:4:15 + | +LL | vec![0u8].as_ptr(); + | --------- ^^^^^^ this pointer will immediately be invalid + | | + | this `Vec<u8>` is deallocated at the end of the statement, bind it to a variable to extend its lifetime + | + = note: pointers do not have a lifetime; when calling `as_ptr` the `Vec<u8>` will be deallocated at the end of the statement because nothing is referencing it as far as the type system is concerned + = help: for more information, see <https://doc.rust-lang.org/reference/destructors.html> +note: the lint level is defined here + --> $DIR/methods.rs:1:9 + | +LL | #![deny(dangling_pointers_from_temporaries)] + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + +error: a dangling pointer will be produced because the temporary `Vec<u8>` will be dropped + --> $DIR/methods.rs:6:15 + | +LL | vec![0u8].as_mut_ptr(); + | --------- ^^^^^^^^^^ this pointer will immediately be invalid + | | + | this `Vec<u8>` is deallocated at the end of the statement, bind it to a variable to extend its lifetime + | + = note: pointers do not have a lifetime; when calling `as_mut_ptr` the `Vec<u8>` will be deallocated at the end of the statement because nothing is referencing it as far as the type system is concerned + = help: for more information, see <https://doc.rust-lang.org/reference/destructors.html> + +error: aborting due to 2 previous errors + diff --git a/tests/ui/lint/dangling-pointers-from-temporaries/temporaries.rs b/tests/ui/lint/dangling-pointers-from-temporaries/temporaries.rs new file mode 100644 index 00000000000..1f216586ae8 --- /dev/null +++ b/tests/ui/lint/dangling-pointers-from-temporaries/temporaries.rs @@ -0,0 +1,136 @@ +#![allow(unused)] +#![deny(dangling_pointers_from_temporaries)] + +fn string() -> String { + "hello".into() +} + +struct Wrapper(String); + +fn main() { + // ConstBlock + const { String::new() }.as_ptr(); + + // Array + { + [string()].as_ptr(); // False negative + [true].as_ptr(); + } + + // Call + string().as_ptr(); + //~^ ERROR a dangling pointer will be produced because the temporary `String` will be dropped + + // MethodCall + "hello".to_string().as_ptr(); + //~^ ERROR a dangling pointer will be produced because the temporary `String` will be dropped + + // Tup + // impossible + + // Binary + (string() + "hello").as_ptr(); + //~^ ERROR a dangling pointer will be produced because the temporary `String` will be dropped + + // Path + { + let x = string(); + x.as_ptr(); + } + + // Unary + { + let x = string(); + let x: &String = &x; + (*x).as_ptr(); + (&[0u8]).as_ptr(); + (&string()).as_ptr(); // False negative + (*&string()).as_ptr(); // False negative + } + + // Lit + "hello".as_ptr(); + + // Cast + // impossible + + // Type + // impossible + + // DropTemps + // impossible + + // Let + // impossible + + // If + { + (if true { String::new() } else { "hello".into() }).as_ptr(); + //~^ ERROR a dangling pointer will be produced because the temporary `String` will be dropped + } + + // Loop + { + (loop { + break String::new(); + }) + .as_ptr(); + //~^ ERROR a dangling pointer will be produced because the temporary `String` will be dropped + } + + // Match + { + match string() { + s => s, + } + .as_ptr(); + //~^ ERROR a dangling pointer will be produced because the temporary `String` will be dropped + } + + // Closure + // impossible + + // Block + { string() }.as_ptr(); + //~^ ERROR a dangling pointer will be produced because the temporary `String` will be dropped + + // Assign, AssignOp + // impossible + + // Field + { + Wrapper(string()).0.as_ptr(); // False negative + let x = Wrapper(string()); + x.0.as_ptr(); + } + + // Index + { + vec![string()][0].as_ptr(); // False negative + let x = vec![string()]; + x[0].as_ptr(); + } + + // AddrOf, InlineAsm, OffsetOf + // impossible + + // Break, Continue, Ret + // are ! + + // Become, Yield + // unstable, are ! + + // Repeat + [0u8; 100].as_ptr(); + [const { String::new() }; 100].as_ptr(); + + // Struct + // Cannot test this without access to private fields of the linted types. + + // Err + // impossible + + // Macro + vec![0u8].as_ptr(); + //~^ ERROR a dangling pointer will be produced because the temporary `Vec<u8>` will be dropped +} diff --git a/tests/ui/lint/dangling-pointers-from-temporaries/temporaries.stderr b/tests/ui/lint/dangling-pointers-from-temporaries/temporaries.stderr new file mode 100644 index 00000000000..d2e9ac8c4e9 --- /dev/null +++ b/tests/ui/lint/dangling-pointers-from-temporaries/temporaries.stderr @@ -0,0 +1,99 @@ +error: a dangling pointer will be produced because the temporary `String` will be dropped + --> $DIR/temporaries.rs:21:14 + | +LL | string().as_ptr(); + | -------- ^^^^^^ this pointer will immediately be invalid + | | + | this `String` is deallocated at the end of the statement, bind it to a variable to extend its lifetime + | + = note: pointers do not have a lifetime; when calling `as_ptr` the `String` will be deallocated at the end of the statement because nothing is referencing it as far as the type system is concerned + = help: for more information, see <https://doc.rust-lang.org/reference/destructors.html> +note: the lint level is defined here + --> $DIR/temporaries.rs:2:9 + | +LL | #![deny(dangling_pointers_from_temporaries)] + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + +error: a dangling pointer will be produced because the temporary `String` will be dropped + --> $DIR/temporaries.rs:25:25 + | +LL | "hello".to_string().as_ptr(); + | ------------------- ^^^^^^ this pointer will immediately be invalid + | | + | this `String` is deallocated at the end of the statement, bind it to a variable to extend its lifetime + | + = note: pointers do not have a lifetime; when calling `as_ptr` the `String` will be deallocated at the end of the statement because nothing is referencing it as far as the type system is concerned + = help: for more information, see <https://doc.rust-lang.org/reference/destructors.html> + +error: a dangling pointer will be produced because the temporary `String` will be dropped + --> $DIR/temporaries.rs:32:26 + | +LL | (string() + "hello").as_ptr(); + | -------------------- ^^^^^^ this pointer will immediately be invalid + | | + | this `String` is deallocated at the end of the statement, bind it to a variable to extend its lifetime + | + = note: pointers do not have a lifetime; when calling `as_ptr` the `String` will be deallocated at the end of the statement because nothing is referencing it as far as the type system is concerned + = help: for more information, see <https://doc.rust-lang.org/reference/destructors.html> + +error: a dangling pointer will be produced because the temporary `String` will be dropped + --> $DIR/temporaries.rs:68:61 + | +LL | (if true { String::new() } else { "hello".into() }).as_ptr(); + | --------------------------------------------------- ^^^^^^ this pointer will immediately be invalid + | | + | this `String` is deallocated at the end of the statement, bind it to a variable to extend its lifetime + | + = note: pointers do not have a lifetime; when calling `as_ptr` the `String` will be deallocated at the end of the statement because nothing is referencing it as far as the type system is concerned + = help: for more information, see <https://doc.rust-lang.org/reference/destructors.html> + +error: a dangling pointer will be produced because the temporary `String` will be dropped + --> $DIR/temporaries.rs:77:10 + | +LL | / (loop { +LL | | break String::new(); +LL | | }) + | |__________- this `String` is deallocated at the end of the statement, bind it to a variable to extend its lifetime +LL | .as_ptr(); + | ^^^^^^ this pointer will immediately be invalid + | + = note: pointers do not have a lifetime; when calling `as_ptr` the `String` will be deallocated at the end of the statement because nothing is referencing it as far as the type system is concerned + = help: for more information, see <https://doc.rust-lang.org/reference/destructors.html> + +error: a dangling pointer will be produced because the temporary `String` will be dropped + --> $DIR/temporaries.rs:86:10 + | +LL | / match string() { +LL | | s => s, +LL | | } + | |_________- this `String` is deallocated at the end of the statement, bind it to a variable to extend its lifetime +LL | .as_ptr(); + | ^^^^^^ this pointer will immediately be invalid + | + = note: pointers do not have a lifetime; when calling `as_ptr` the `String` will be deallocated at the end of the statement because nothing is referencing it as far as the type system is concerned + = help: for more information, see <https://doc.rust-lang.org/reference/destructors.html> + +error: a dangling pointer will be produced because the temporary `String` will be dropped + --> $DIR/temporaries.rs:94:18 + | +LL | { string() }.as_ptr(); + | ------------ ^^^^^^ this pointer will immediately be invalid + | | + | this `String` is deallocated at the end of the statement, bind it to a variable to extend its lifetime + | + = note: pointers do not have a lifetime; when calling `as_ptr` the `String` will be deallocated at the end of the statement because nothing is referencing it as far as the type system is concerned + = help: for more information, see <https://doc.rust-lang.org/reference/destructors.html> + +error: a dangling pointer will be produced because the temporary `Vec<u8>` will be dropped + --> $DIR/temporaries.rs:134:15 + | +LL | vec![0u8].as_ptr(); + | --------- ^^^^^^ this pointer will immediately be invalid + | | + | this `Vec<u8>` is deallocated at the end of the statement, bind it to a variable to extend its lifetime + | + = note: pointers do not have a lifetime; when calling `as_ptr` the `Vec<u8>` will be deallocated at the end of the statement because nothing is referencing it as far as the type system is concerned + = help: for more information, see <https://doc.rust-lang.org/reference/destructors.html> + +error: aborting due to 8 previous errors + diff --git a/tests/ui/lint/dangling-pointers-from-temporaries/types.rs b/tests/ui/lint/dangling-pointers-from-temporaries/types.rs new file mode 100644 index 00000000000..2b515d3e6d5 --- /dev/null +++ b/tests/ui/lint/dangling-pointers-from-temporaries/types.rs @@ -0,0 +1,52 @@ +#![deny(dangling_pointers_from_temporaries)] + +use std::cell::Cell; +use std::ffi::{CStr, CString}; +use std::mem::MaybeUninit; + +struct AsPtrFake; + +impl AsPtrFake { + fn as_ptr(&self) -> *const () { + std::ptr::null() + } +} + +fn declval<T>() -> T { + loop {} +} + +fn main() { + declval::<CString>().as_ptr(); + //~^ ERROR a dangling pointer will be produced because the temporary `CString` will be dropped + declval::<String>().as_ptr(); + //~^ ERROR a dangling pointer will be produced because the temporary `String` will be dropped + declval::<Vec<u8>>().as_ptr(); + //~^ ERROR a dangling pointer will be produced because the temporary `Vec<u8>` will be dropped + declval::<Box<CString>>().as_ptr(); + //~^ ERROR a dangling pointer will be produced because the temporary `Box<CString>` will be dropped + declval::<Box<[u8]>>().as_ptr(); + //~^ ERROR a dangling pointer will be produced because the temporary `Box<[u8]>` will be dropped + declval::<Box<str>>().as_ptr(); + //~^ ERROR a dangling pointer will be produced because the temporary `Box<str>` will be dropped + declval::<Box<CStr>>().as_ptr(); + //~^ ERROR a dangling pointer will be produced because the temporary `Box<CStr>` will be dropped + declval::<[u8; 10]>().as_ptr(); + //~^ ERROR a dangling pointer will be produced because the temporary `[u8; 10]` will be dropped + declval::<Box<[u8; 10]>>().as_ptr(); + //~^ ERROR a dangling pointer will be produced because the temporary `Box<[u8; 10]>` will be dropped + declval::<Box<Vec<u8>>>().as_ptr(); + //~^ ERROR a dangling pointer will be produced because the temporary `Box<Vec<u8>>` will be dropped + declval::<Box<String>>().as_ptr(); + //~^ ERROR a dangling pointer will be produced because the temporary `Box<String>` will be dropped + declval::<Box<Box<Box<Box<[u8]>>>>>().as_ptr(); + //~^ ERROR a dangling pointer will be produced because the temporary `Box<Box<Box<Box<[u8]>>>>` will be dropped + declval::<Cell<u8>>().as_ptr(); + //~^ ERROR a dangling pointer will be produced because the temporary `Cell<u8>` will be dropped + declval::<MaybeUninit<u8>>().as_ptr(); + //~^ ERROR a dangling pointer will be produced because the temporary `MaybeUninit<u8>` will be dropped + declval::<Vec<AsPtrFake>>().as_ptr(); + //~^ ERROR a dangling pointer will be produced because the temporary `Vec<AsPtrFake>` will be dropped + declval::<Box<AsPtrFake>>().as_ptr(); + declval::<AsPtrFake>().as_ptr(); +} diff --git a/tests/ui/lint/dangling-pointers-from-temporaries/types.stderr b/tests/ui/lint/dangling-pointers-from-temporaries/types.stderr new file mode 100644 index 00000000000..c582a4c6540 --- /dev/null +++ b/tests/ui/lint/dangling-pointers-from-temporaries/types.stderr @@ -0,0 +1,172 @@ +error: a dangling pointer will be produced because the temporary `CString` will be dropped + --> $DIR/types.rs:20:26 + | +LL | declval::<CString>().as_ptr(); + | -------------------- ^^^^^^ this pointer will immediately be invalid + | | + | this `CString` is deallocated at the end of the statement, bind it to a variable to extend its lifetime + | + = note: pointers do not have a lifetime; when calling `as_ptr` the `CString` will be deallocated at the end of the statement because nothing is referencing it as far as the type system is concerned + = help: for more information, see <https://doc.rust-lang.org/reference/destructors.html> +note: the lint level is defined here + --> $DIR/types.rs:1:9 + | +LL | #![deny(dangling_pointers_from_temporaries)] + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + +error: a dangling pointer will be produced because the temporary `String` will be dropped + --> $DIR/types.rs:22:25 + | +LL | declval::<String>().as_ptr(); + | ------------------- ^^^^^^ this pointer will immediately be invalid + | | + | this `String` is deallocated at the end of the statement, bind it to a variable to extend its lifetime + | + = note: pointers do not have a lifetime; when calling `as_ptr` the `String` will be deallocated at the end of the statement because nothing is referencing it as far as the type system is concerned + = help: for more information, see <https://doc.rust-lang.org/reference/destructors.html> + +error: a dangling pointer will be produced because the temporary `Vec<u8>` will be dropped + --> $DIR/types.rs:24:26 + | +LL | declval::<Vec<u8>>().as_ptr(); + | -------------------- ^^^^^^ this pointer will immediately be invalid + | | + | this `Vec<u8>` is deallocated at the end of the statement, bind it to a variable to extend its lifetime + | + = note: pointers do not have a lifetime; when calling `as_ptr` the `Vec<u8>` will be deallocated at the end of the statement because nothing is referencing it as far as the type system is concerned + = help: for more information, see <https://doc.rust-lang.org/reference/destructors.html> + +error: a dangling pointer will be produced because the temporary `Box<CString>` will be dropped + --> $DIR/types.rs:26:31 + | +LL | declval::<Box<CString>>().as_ptr(); + | ------------------------- ^^^^^^ this pointer will immediately be invalid + | | + | this `Box<CString>` is deallocated at the end of the statement, bind it to a variable to extend its lifetime + | + = note: pointers do not have a lifetime; when calling `as_ptr` the `Box<CString>` will be deallocated at the end of the statement because nothing is referencing it as far as the type system is concerned + = help: for more information, see <https://doc.rust-lang.org/reference/destructors.html> + +error: a dangling pointer will be produced because the temporary `Box<[u8]>` will be dropped + --> $DIR/types.rs:28:28 + | +LL | declval::<Box<[u8]>>().as_ptr(); + | ---------------------- ^^^^^^ this pointer will immediately be invalid + | | + | this `Box<[u8]>` is deallocated at the end of the statement, bind it to a variable to extend its lifetime + | + = note: pointers do not have a lifetime; when calling `as_ptr` the `Box<[u8]>` will be deallocated at the end of the statement because nothing is referencing it as far as the type system is concerned + = help: for more information, see <https://doc.rust-lang.org/reference/destructors.html> + +error: a dangling pointer will be produced because the temporary `Box<str>` will be dropped + --> $DIR/types.rs:30:27 + | +LL | declval::<Box<str>>().as_ptr(); + | --------------------- ^^^^^^ this pointer will immediately be invalid + | | + | this `Box<str>` is deallocated at the end of the statement, bind it to a variable to extend its lifetime + | + = note: pointers do not have a lifetime; when calling `as_ptr` the `Box<str>` will be deallocated at the end of the statement because nothing is referencing it as far as the type system is concerned + = help: for more information, see <https://doc.rust-lang.org/reference/destructors.html> + +error: a dangling pointer will be produced because the temporary `Box<CStr>` will be dropped + --> $DIR/types.rs:32:28 + | +LL | declval::<Box<CStr>>().as_ptr(); + | ---------------------- ^^^^^^ this pointer will immediately be invalid + | | + | this `Box<CStr>` is deallocated at the end of the statement, bind it to a variable to extend its lifetime + | + = note: pointers do not have a lifetime; when calling `as_ptr` the `Box<CStr>` will be deallocated at the end of the statement because nothing is referencing it as far as the type system is concerned + = help: for more information, see <https://doc.rust-lang.org/reference/destructors.html> + +error: a dangling pointer will be produced because the temporary `[u8; 10]` will be dropped + --> $DIR/types.rs:34:27 + | +LL | declval::<[u8; 10]>().as_ptr(); + | --------------------- ^^^^^^ this pointer will immediately be invalid + | | + | this `[u8; 10]` is deallocated at the end of the statement, bind it to a variable to extend its lifetime + | + = note: pointers do not have a lifetime; when calling `as_ptr` the `[u8; 10]` will be deallocated at the end of the statement because nothing is referencing it as far as the type system is concerned + = help: for more information, see <https://doc.rust-lang.org/reference/destructors.html> + +error: a dangling pointer will be produced because the temporary `Box<[u8; 10]>` will be dropped + --> $DIR/types.rs:36:32 + | +LL | declval::<Box<[u8; 10]>>().as_ptr(); + | -------------------------- ^^^^^^ this pointer will immediately be invalid + | | + | this `Box<[u8; 10]>` is deallocated at the end of the statement, bind it to a variable to extend its lifetime + | + = note: pointers do not have a lifetime; when calling `as_ptr` the `Box<[u8; 10]>` will be deallocated at the end of the statement because nothing is referencing it as far as the type system is concerned + = help: for more information, see <https://doc.rust-lang.org/reference/destructors.html> + +error: a dangling pointer will be produced because the temporary `Box<Vec<u8>>` will be dropped + --> $DIR/types.rs:38:31 + | +LL | declval::<Box<Vec<u8>>>().as_ptr(); + | ------------------------- ^^^^^^ this pointer will immediately be invalid + | | + | this `Box<Vec<u8>>` is deallocated at the end of the statement, bind it to a variable to extend its lifetime + | + = note: pointers do not have a lifetime; when calling `as_ptr` the `Box<Vec<u8>>` will be deallocated at the end of the statement because nothing is referencing it as far as the type system is concerned + = help: for more information, see <https://doc.rust-lang.org/reference/destructors.html> + +error: a dangling pointer will be produced because the temporary `Box<String>` will be dropped + --> $DIR/types.rs:40:30 + | +LL | declval::<Box<String>>().as_ptr(); + | ------------------------ ^^^^^^ this pointer will immediately be invalid + | | + | this `Box<String>` is deallocated at the end of the statement, bind it to a variable to extend its lifetime + | + = note: pointers do not have a lifetime; when calling `as_ptr` the `Box<String>` will be deallocated at the end of the statement because nothing is referencing it as far as the type system is concerned + = help: for more information, see <https://doc.rust-lang.org/reference/destructors.html> + +error: a dangling pointer will be produced because the temporary `Box<Box<Box<Box<[u8]>>>>` will be dropped + --> $DIR/types.rs:42:43 + | +LL | declval::<Box<Box<Box<Box<[u8]>>>>>().as_ptr(); + | ------------------------------------- ^^^^^^ this pointer will immediately be invalid + | | + | this `Box<Box<Box<Box<[u8]>>>>` is deallocated at the end of the statement, bind it to a variable to extend its lifetime + | + = note: pointers do not have a lifetime; when calling `as_ptr` the `Box<Box<Box<Box<[u8]>>>>` will be deallocated at the end of the statement because nothing is referencing it as far as the type system is concerned + = help: for more information, see <https://doc.rust-lang.org/reference/destructors.html> + +error: a dangling pointer will be produced because the temporary `Cell<u8>` will be dropped + --> $DIR/types.rs:44:27 + | +LL | declval::<Cell<u8>>().as_ptr(); + | --------------------- ^^^^^^ this pointer will immediately be invalid + | | + | this `Cell<u8>` is deallocated at the end of the statement, bind it to a variable to extend its lifetime + | + = note: pointers do not have a lifetime; when calling `as_ptr` the `Cell<u8>` will be deallocated at the end of the statement because nothing is referencing it as far as the type system is concerned + = help: for more information, see <https://doc.rust-lang.org/reference/destructors.html> + +error: a dangling pointer will be produced because the temporary `MaybeUninit<u8>` will be dropped + --> $DIR/types.rs:46:34 + | +LL | declval::<MaybeUninit<u8>>().as_ptr(); + | ---------------------------- ^^^^^^ this pointer will immediately be invalid + | | + | this `MaybeUninit<u8>` is deallocated at the end of the statement, bind it to a variable to extend its lifetime + | + = note: pointers do not have a lifetime; when calling `as_ptr` the `MaybeUninit<u8>` will be deallocated at the end of the statement because nothing is referencing it as far as the type system is concerned + = help: for more information, see <https://doc.rust-lang.org/reference/destructors.html> + +error: a dangling pointer will be produced because the temporary `Vec<AsPtrFake>` will be dropped + --> $DIR/types.rs:48:33 + | +LL | declval::<Vec<AsPtrFake>>().as_ptr(); + | --------------------------- ^^^^^^ this pointer will immediately be invalid + | | + | this `Vec<AsPtrFake>` is deallocated at the end of the statement, bind it to a variable to extend its lifetime + | + = note: pointers do not have a lifetime; when calling `as_ptr` the `Vec<AsPtrFake>` will be deallocated at the end of the statement because nothing is referencing it as far as the type system is concerned + = help: for more information, see <https://doc.rust-lang.org/reference/destructors.html> + +error: aborting due to 15 previous errors + diff --git a/tests/ui/lint/keyword-idents/auxiliary/multi_file_submod.rs b/tests/ui/lint/keyword-idents/auxiliary/multi_file_submod.rs new file mode 100644 index 00000000000..08d6733d3e2 --- /dev/null +++ b/tests/ui/lint/keyword-idents/auxiliary/multi_file_submod.rs @@ -0,0 +1,10 @@ +// Submodule file used by test `../multi-file.rs`. + +// Keywords reserved from Rust 2018: +fn async() {} +fn await() {} +fn try() {} +fn dyn() {} + +// Keywords reserved from Rust 2024: +fn gen() {} diff --git a/tests/ui/lint/keyword-idents/multi-file.rs b/tests/ui/lint/keyword-idents/multi-file.rs new file mode 100644 index 00000000000..703e13f9ef6 --- /dev/null +++ b/tests/ui/lint/keyword-idents/multi-file.rs @@ -0,0 +1,14 @@ +#![deny(keyword_idents)] // Should affect the submodule, but doesn't. +//@ edition: 2015 +//@ known-bug: #132218 +//@ check-pass (known bug; should be check-fail) + +// Because `keyword_idents_2018` and `keyword_idents_2024` are pre-expansion +// lints, configuring them via lint attributes doesn't propagate to submodules +// in other files. +// <https://github.com/rust-lang/rust/issues/132218> + +#[path = "./auxiliary/multi_file_submod.rs"] +mod multi_file_submod; + +fn main() {} diff --git a/tests/ui/lint/lint-temporary-cstring-as-param.stderr b/tests/ui/lint/lint-temporary-cstring-as-param.stderr deleted file mode 100644 index 7aa21f2560c..00000000000 --- a/tests/ui/lint/lint-temporary-cstring-as-param.stderr +++ /dev/null @@ -1,18 +0,0 @@ -error: getting the inner pointer of a temporary `CString` - --> $DIR/lint-temporary-cstring-as-param.rs:9:45 - | -LL | some_function(CString::new("").unwrap().as_ptr()); - | ------------------------- ^^^^^^ this pointer will be invalid - | | - | this `CString` is deallocated at the end of the statement, bind it to a variable to extend its lifetime - | - = note: pointers do not have a lifetime; when calling `as_ptr` the `CString` will be deallocated at the end of the statement because nothing is referencing it as far as the type system is concerned - = help: for more information, see https://doc.rust-lang.org/reference/destructors.html -note: the lint level is defined here - --> $DIR/lint-temporary-cstring-as-param.rs:1:9 - | -LL | #![deny(temporary_cstring_as_ptr)] - | ^^^^^^^^^^^^^^^^^^^^^^^^ - -error: aborting due to 1 previous error - diff --git a/tests/ui/lint/non-snake-case/lint-non-snake-case-crate.cdylib_.stderr b/tests/ui/lint/non-snake-case/lint-non-snake-case-crate.cdylib_.stderr index 140d72b9742..1192b690e29 100644 --- a/tests/ui/lint/non-snake-case/lint-non-snake-case-crate.cdylib_.stderr +++ b/tests/ui/lint/non-snake-case/lint-non-snake-case-crate.cdylib_.stderr @@ -1,11 +1,11 @@ error: crate `NonSnakeCase` should have a snake case name - --> $DIR/lint-non-snake-case-crate.rs:29:18 + --> $DIR/lint-non-snake-case-crate.rs:36:18 | LL | #![crate_name = "NonSnakeCase"] | ^^^^^^^^^^^^ help: convert the identifier to snake case: `non_snake_case` | note: the lint level is defined here - --> $DIR/lint-non-snake-case-crate.rs:31:9 + --> $DIR/lint-non-snake-case-crate.rs:38:9 | LL | #![deny(non_snake_case)] | ^^^^^^^^^^^^^^ diff --git a/tests/ui/lint/non-snake-case/lint-non-snake-case-crate.dylib_.stderr b/tests/ui/lint/non-snake-case/lint-non-snake-case-crate.dylib_.stderr index 140d72b9742..1192b690e29 100644 --- a/tests/ui/lint/non-snake-case/lint-non-snake-case-crate.dylib_.stderr +++ b/tests/ui/lint/non-snake-case/lint-non-snake-case-crate.dylib_.stderr @@ -1,11 +1,11 @@ error: crate `NonSnakeCase` should have a snake case name - --> $DIR/lint-non-snake-case-crate.rs:29:18 + --> $DIR/lint-non-snake-case-crate.rs:36:18 | LL | #![crate_name = "NonSnakeCase"] | ^^^^^^^^^^^^ help: convert the identifier to snake case: `non_snake_case` | note: the lint level is defined here - --> $DIR/lint-non-snake-case-crate.rs:31:9 + --> $DIR/lint-non-snake-case-crate.rs:38:9 | LL | #![deny(non_snake_case)] | ^^^^^^^^^^^^^^ diff --git a/tests/ui/lint/non-snake-case/lint-non-snake-case-crate.lib_.stderr b/tests/ui/lint/non-snake-case/lint-non-snake-case-crate.lib_.stderr index 140d72b9742..1192b690e29 100644 --- a/tests/ui/lint/non-snake-case/lint-non-snake-case-crate.lib_.stderr +++ b/tests/ui/lint/non-snake-case/lint-non-snake-case-crate.lib_.stderr @@ -1,11 +1,11 @@ error: crate `NonSnakeCase` should have a snake case name - --> $DIR/lint-non-snake-case-crate.rs:29:18 + --> $DIR/lint-non-snake-case-crate.rs:36:18 | LL | #![crate_name = "NonSnakeCase"] | ^^^^^^^^^^^^ help: convert the identifier to snake case: `non_snake_case` | note: the lint level is defined here - --> $DIR/lint-non-snake-case-crate.rs:31:9 + --> $DIR/lint-non-snake-case-crate.rs:38:9 | LL | #![deny(non_snake_case)] | ^^^^^^^^^^^^^^ diff --git a/tests/ui/lint/non-snake-case/lint-non-snake-case-crate.proc_macro_.stderr b/tests/ui/lint/non-snake-case/lint-non-snake-case-crate.proc_macro_.stderr index 140d72b9742..1192b690e29 100644 --- a/tests/ui/lint/non-snake-case/lint-non-snake-case-crate.proc_macro_.stderr +++ b/tests/ui/lint/non-snake-case/lint-non-snake-case-crate.proc_macro_.stderr @@ -1,11 +1,11 @@ error: crate `NonSnakeCase` should have a snake case name - --> $DIR/lint-non-snake-case-crate.rs:29:18 + --> $DIR/lint-non-snake-case-crate.rs:36:18 | LL | #![crate_name = "NonSnakeCase"] | ^^^^^^^^^^^^ help: convert the identifier to snake case: `non_snake_case` | note: the lint level is defined here - --> $DIR/lint-non-snake-case-crate.rs:31:9 + --> $DIR/lint-non-snake-case-crate.rs:38:9 | LL | #![deny(non_snake_case)] | ^^^^^^^^^^^^^^ diff --git a/tests/ui/lint/non-snake-case/lint-non-snake-case-crate.rlib_.stderr b/tests/ui/lint/non-snake-case/lint-non-snake-case-crate.rlib_.stderr index 140d72b9742..1192b690e29 100644 --- a/tests/ui/lint/non-snake-case/lint-non-snake-case-crate.rlib_.stderr +++ b/tests/ui/lint/non-snake-case/lint-non-snake-case-crate.rlib_.stderr @@ -1,11 +1,11 @@ error: crate `NonSnakeCase` should have a snake case name - --> $DIR/lint-non-snake-case-crate.rs:29:18 + --> $DIR/lint-non-snake-case-crate.rs:36:18 | LL | #![crate_name = "NonSnakeCase"] | ^^^^^^^^^^^^ help: convert the identifier to snake case: `non_snake_case` | note: the lint level is defined here - --> $DIR/lint-non-snake-case-crate.rs:31:9 + --> $DIR/lint-non-snake-case-crate.rs:38:9 | LL | #![deny(non_snake_case)] | ^^^^^^^^^^^^^^ diff --git a/tests/ui/lint/non-snake-case/lint-non-snake-case-crate.rs b/tests/ui/lint/non-snake-case/lint-non-snake-case-crate.rs index 097b246c165..6f701cd27c6 100644 --- a/tests/ui/lint/non-snake-case/lint-non-snake-case-crate.rs +++ b/tests/ui/lint/non-snake-case/lint-non-snake-case-crate.rs @@ -10,10 +10,17 @@ // But should fire on non-binary crates. -//@[cdylib_] ignore-musl (dylibs are not supported) -//@[dylib_] ignore-musl (dylibs are not supported) -//@[dylib_] ignore-wasm (dylib is not supported) -//@[proc_macro_] ignore-wasm (dylib is not supported) +// FIXME(#132309): dylib crate type is not supported on wasm; we need a proper +// supports-crate-type directive. Also, needs-dynamic-linking should rule out +// musl since it supports neither dylibs nor cdylibs. +//@[dylib_] ignore-wasm +//@[dylib_] ignore-musl +//@[cdylib_] ignore-musl + +//@[dylib_] needs-dynamic-linking +//@[cdylib_] needs-dynamic-linking +//@[proc_macro_] force-host +//@[proc_macro_] no-prefer-dynamic //@[cdylib_] compile-flags: --crate-type=cdylib //@[dylib_] compile-flags: --crate-type=dylib diff --git a/tests/ui/lint/non-snake-case/lint-non-snake-case-crate.staticlib_.stderr b/tests/ui/lint/non-snake-case/lint-non-snake-case-crate.staticlib_.stderr index 140d72b9742..1192b690e29 100644 --- a/tests/ui/lint/non-snake-case/lint-non-snake-case-crate.staticlib_.stderr +++ b/tests/ui/lint/non-snake-case/lint-non-snake-case-crate.staticlib_.stderr @@ -1,11 +1,11 @@ error: crate `NonSnakeCase` should have a snake case name - --> $DIR/lint-non-snake-case-crate.rs:29:18 + --> $DIR/lint-non-snake-case-crate.rs:36:18 | LL | #![crate_name = "NonSnakeCase"] | ^^^^^^^^^^^^ help: convert the identifier to snake case: `non_snake_case` | note: the lint level is defined here - --> $DIR/lint-non-snake-case-crate.rs:31:9 + --> $DIR/lint-non-snake-case-crate.rs:38:9 | LL | #![deny(non_snake_case)] | ^^^^^^^^^^^^^^ diff --git a/tests/ui/macros/assert-trailing-junk.with-generic-asset.stderr b/tests/ui/macros/assert-trailing-junk.with-generic-asset.stderr index 1e73320e439..7582c8e8659 100644 --- a/tests/ui/macros/assert-trailing-junk.with-generic-asset.stderr +++ b/tests/ui/macros/assert-trailing-junk.with-generic-asset.stderr @@ -10,7 +10,7 @@ error: expected one of `,`, `.`, `?`, or an operator, found `some` LL | assert!(true some extra junk); | ^^^^ expected one of `,`, `.`, `?`, or an operator -error: no rules expected the token `blah` +error: no rules expected `blah` --> $DIR/assert-trailing-junk.rs:15:30 | LL | assert!(true, "whatever" blah); @@ -28,7 +28,7 @@ LL | assert!(true "whatever" blah); | | | help: try adding a comma -error: no rules expected the token `blah` +error: no rules expected `blah` --> $DIR/assert-trailing-junk.rs:18:29 | LL | assert!(true "whatever" blah); diff --git a/tests/ui/macros/assert-trailing-junk.without-generic-asset.stderr b/tests/ui/macros/assert-trailing-junk.without-generic-asset.stderr index 1e73320e439..7582c8e8659 100644 --- a/tests/ui/macros/assert-trailing-junk.without-generic-asset.stderr +++ b/tests/ui/macros/assert-trailing-junk.without-generic-asset.stderr @@ -10,7 +10,7 @@ error: expected one of `,`, `.`, `?`, or an operator, found `some` LL | assert!(true some extra junk); | ^^^^ expected one of `,`, `.`, `?`, or an operator -error: no rules expected the token `blah` +error: no rules expected `blah` --> $DIR/assert-trailing-junk.rs:15:30 | LL | assert!(true, "whatever" blah); @@ -28,7 +28,7 @@ LL | assert!(true "whatever" blah); | | | help: try adding a comma -error: no rules expected the token `blah` +error: no rules expected `blah` --> $DIR/assert-trailing-junk.rs:18:29 | LL | assert!(true "whatever" blah); diff --git a/tests/ui/macros/best-failure.rs b/tests/ui/macros/best-failure.rs index bbdd465d5ec..1b73066c874 100644 --- a/tests/ui/macros/best-failure.rs +++ b/tests/ui/macros/best-failure.rs @@ -2,7 +2,7 @@ macro_rules! number { (neg false, $self:ident) => { $self }; ($signed:tt => $ty:ty;) => { number!(neg $signed, $self); - //~^ ERROR no rules expected the token `$` + //~^ ERROR no rules expected `$` }; } diff --git a/tests/ui/macros/best-failure.stderr b/tests/ui/macros/best-failure.stderr index c5f8b9abc19..914ff7fd820 100644 --- a/tests/ui/macros/best-failure.stderr +++ b/tests/ui/macros/best-failure.stderr @@ -1,4 +1,4 @@ -error: no rules expected the token `$` +error: no rules expected `$` --> $DIR/best-failure.rs:4:30 | LL | macro_rules! number { diff --git a/tests/ui/macros/expr_2021_inline_const.edi2021.stderr b/tests/ui/macros/expr_2021_inline_const.edi2021.stderr index 22d662aaaf2..bf7eb3888b3 100644 --- a/tests/ui/macros/expr_2021_inline_const.edi2021.stderr +++ b/tests/ui/macros/expr_2021_inline_const.edi2021.stderr @@ -1,4 +1,4 @@ -error: no rules expected the token `const` +error: no rules expected keyword `const` --> $DIR/expr_2021_inline_const.rs:23:12 | LL | macro_rules! m2021 { @@ -13,7 +13,7 @@ note: while trying to match meta-variable `$e:expr_2021` LL | ($e:expr_2021) => { | ^^^^^^^^^^^^ -error: no rules expected the token `const` +error: no rules expected keyword `const` --> $DIR/expr_2021_inline_const.rs:24:12 | LL | macro_rules! m2024 { diff --git a/tests/ui/macros/expr_2021_inline_const.edi2024.stderr b/tests/ui/macros/expr_2021_inline_const.edi2024.stderr index 2555e4f757a..1028ddc4267 100644 --- a/tests/ui/macros/expr_2021_inline_const.edi2024.stderr +++ b/tests/ui/macros/expr_2021_inline_const.edi2024.stderr @@ -1,4 +1,4 @@ -error: no rules expected the token `const` +error: no rules expected keyword `const` --> $DIR/expr_2021_inline_const.rs:23:12 | LL | macro_rules! m2021 { diff --git a/tests/ui/macros/expr_2021_inline_const.rs b/tests/ui/macros/expr_2021_inline_const.rs index 39a542fe4d9..312256f1879 100644 --- a/tests/ui/macros/expr_2021_inline_const.rs +++ b/tests/ui/macros/expr_2021_inline_const.rs @@ -20,8 +20,8 @@ macro_rules! test { } fn main() { - m2021!(const { 1 }); //~ ERROR: no rules expected the token `const` - m2024!(const { 1 }); //[edi2021]~ ERROR: no rules expected the token `const` + m2021!(const { 1 }); //~ ERROR: no rules expected keyword `const` + m2024!(const { 1 }); //[edi2021]~ ERROR: no rules expected keyword `const` test!(expr); } diff --git a/tests/ui/macros/expr_2024_underscore_expr.edi2021.stderr b/tests/ui/macros/expr_2024_underscore_expr.edi2021.stderr index 34df20a69ef..7b3ca54bb71 100644 --- a/tests/ui/macros/expr_2024_underscore_expr.edi2021.stderr +++ b/tests/ui/macros/expr_2024_underscore_expr.edi2021.stderr @@ -1,4 +1,4 @@ -error: no rules expected the token `_` +error: no rules expected reserved identifier `_` --> $DIR/expr_2024_underscore_expr.rs:19:12 | LL | macro_rules! m2021 { @@ -13,7 +13,7 @@ note: while trying to match meta-variable `$e:expr_2021` LL | ($e:expr_2021) => { | ^^^^^^^^^^^^ -error: no rules expected the token `_` +error: no rules expected reserved identifier `_` --> $DIR/expr_2024_underscore_expr.rs:20:12 | LL | macro_rules! m2024 { diff --git a/tests/ui/macros/expr_2024_underscore_expr.edi2024.stderr b/tests/ui/macros/expr_2024_underscore_expr.edi2024.stderr index 372c5d8637c..59104dafa18 100644 --- a/tests/ui/macros/expr_2024_underscore_expr.edi2024.stderr +++ b/tests/ui/macros/expr_2024_underscore_expr.edi2024.stderr @@ -1,4 +1,4 @@ -error: no rules expected the token `_` +error: no rules expected reserved identifier `_` --> $DIR/expr_2024_underscore_expr.rs:19:12 | LL | macro_rules! m2021 { diff --git a/tests/ui/macros/expr_2024_underscore_expr.rs b/tests/ui/macros/expr_2024_underscore_expr.rs index 86e31374506..6f8ec139109 100644 --- a/tests/ui/macros/expr_2024_underscore_expr.rs +++ b/tests/ui/macros/expr_2024_underscore_expr.rs @@ -16,6 +16,6 @@ macro_rules! m2024 { } fn main() { - m2021!(_); //~ ERROR: no rules expected the token `_` - m2024!(_); //[edi2021]~ ERROR: no rules expected the token `_` + m2021!(_); //~ ERROR: no rules expected reserved identifier `_` + m2024!(_); //[edi2021]~ ERROR: no rules expected reserved identifier `_` } diff --git a/tests/ui/macros/issue-118786.rs b/tests/ui/macros/issue-118786.rs index a41372e4ea8..a73b737fe07 100644 --- a/tests/ui/macros/issue-118786.rs +++ b/tests/ui/macros/issue-118786.rs @@ -5,7 +5,7 @@ macro_rules! make_macro { ($macro_name:tt) => { macro_rules! $macro_name { - //~^ ERROR macro expansion ignores token `{` and any following + //~^ ERROR macro expansion ignores `{` and any tokens following //~| ERROR cannot find macro `macro_rules` in this scope //~| put a macro name here () => {} diff --git a/tests/ui/macros/issue-118786.stderr b/tests/ui/macros/issue-118786.stderr index 256b742ee16..7fa5c2b83dd 100644 --- a/tests/ui/macros/issue-118786.stderr +++ b/tests/ui/macros/issue-118786.stderr @@ -13,7 +13,7 @@ help: add a semicolon LL | macro_rules! $macro_name; { | + -error: macro expansion ignores token `{` and any following +error: macro expansion ignores `{` and any tokens following --> $DIR/issue-118786.rs:7:34 | LL | macro_rules! $macro_name { diff --git a/tests/ui/macros/issue-30007.rs b/tests/ui/macros/issue-30007.rs index 918a821bae9..e36e47a3e7c 100644 --- a/tests/ui/macros/issue-30007.rs +++ b/tests/ui/macros/issue-30007.rs @@ -1,5 +1,5 @@ macro_rules! t { - () => ( String ; ); //~ ERROR macro expansion ignores token `;` + () => ( String ; ); //~ ERROR macro expansion ignores `;` } fn main() { diff --git a/tests/ui/macros/issue-30007.stderr b/tests/ui/macros/issue-30007.stderr index f303221cf8a..129733ed69a 100644 --- a/tests/ui/macros/issue-30007.stderr +++ b/tests/ui/macros/issue-30007.stderr @@ -1,4 +1,4 @@ -error: macro expansion ignores token `;` and any following +error: macro expansion ignores `;` and any tokens following --> $DIR/issue-30007.rs:2:20 | LL | () => ( String ; ); diff --git a/tests/ui/macros/issue-54441.rs b/tests/ui/macros/issue-54441.rs index b24d7e1f6be..37ab4e63647 100644 --- a/tests/ui/macros/issue-54441.rs +++ b/tests/ui/macros/issue-54441.rs @@ -1,6 +1,6 @@ macro_rules! m { () => { - let //~ ERROR macro expansion ignores token `let` and any following + let //~ ERROR macro expansion ignores keyword `let` and any tokens following }; } diff --git a/tests/ui/macros/issue-54441.stderr b/tests/ui/macros/issue-54441.stderr index fb2c103139b..f5f8b8ca2b2 100644 --- a/tests/ui/macros/issue-54441.stderr +++ b/tests/ui/macros/issue-54441.stderr @@ -1,4 +1,4 @@ -error: macro expansion ignores token `let` and any following +error: macro expansion ignores keyword `let` and any tokens following --> $DIR/issue-54441.rs:3:9 | LL | let diff --git a/tests/ui/macros/macro-at-most-once-rep-2015.rs b/tests/ui/macros/macro-at-most-once-rep-2015.rs index 8f2531a25ae..08967b82531 100644 --- a/tests/ui/macros/macro-at-most-once-rep-2015.rs +++ b/tests/ui/macros/macro-at-most-once-rep-2015.rs @@ -22,21 +22,21 @@ macro_rules! barstar { pub fn main() { foo!(); foo!(a); - foo!(a?); //~ ERROR no rules expected the token `?` - foo!(a?a); //~ ERROR no rules expected the token `?` - foo!(a?a?a); //~ ERROR no rules expected the token `?` + foo!(a?); //~ ERROR no rules expected `?` + foo!(a?a); //~ ERROR no rules expected `?` + foo!(a?a?a); //~ ERROR no rules expected `?` barplus!(); //~ERROR unexpected end of macro invocation barplus!(a); //~ERROR unexpected end of macro invocation - barplus!(a?); //~ ERROR no rules expected the token `?` - barplus!(a?a); //~ ERROR no rules expected the token `?` + barplus!(a?); //~ ERROR no rules expected `?` + barplus!(a?a); //~ ERROR no rules expected `?` barplus!(a+); barplus!(+); barstar!(); //~ERROR unexpected end of macro invocation barstar!(a); //~ERROR unexpected end of macro invocation - barstar!(a?); //~ ERROR no rules expected the token `?` - barstar!(a?a); //~ ERROR no rules expected the token `?` + barstar!(a?); //~ ERROR no rules expected `?` + barstar!(a?a); //~ ERROR no rules expected `?` barstar!(a*); barstar!(*); } diff --git a/tests/ui/macros/macro-at-most-once-rep-2015.stderr b/tests/ui/macros/macro-at-most-once-rep-2015.stderr index 7c45b85bc8d..7f161cdc8d0 100644 --- a/tests/ui/macros/macro-at-most-once-rep-2015.stderr +++ b/tests/ui/macros/macro-at-most-once-rep-2015.stderr @@ -4,7 +4,7 @@ error: the `?` macro repetition operator does not take a separator LL | ($(a),?) => {}; | ^ -error: no rules expected the token `?` +error: no rules expected `?` --> $DIR/macro-at-most-once-rep-2015.rs:25:11 | LL | macro_rules! foo { @@ -15,7 +15,7 @@ LL | foo!(a?); | = note: while trying to match sequence end -error: no rules expected the token `?` +error: no rules expected `?` --> $DIR/macro-at-most-once-rep-2015.rs:26:11 | LL | macro_rules! foo { @@ -26,7 +26,7 @@ LL | foo!(a?a); | = note: while trying to match sequence end -error: no rules expected the token `?` +error: no rules expected `?` --> $DIR/macro-at-most-once-rep-2015.rs:27:11 | LL | macro_rules! foo { @@ -67,7 +67,7 @@ note: while trying to match `+` LL | ($(a)?+) => {}; // ok. matches "a+" and "+" | ^ -error: no rules expected the token `?` +error: no rules expected `?` --> $DIR/macro-at-most-once-rep-2015.rs:31:15 | LL | macro_rules! barplus { @@ -82,7 +82,7 @@ note: while trying to match `+` LL | ($(a)?+) => {}; // ok. matches "a+" and "+" | ^ -error: no rules expected the token `?` +error: no rules expected `?` --> $DIR/macro-at-most-once-rep-2015.rs:32:15 | LL | macro_rules! barplus { @@ -127,7 +127,7 @@ note: while trying to match `*` LL | ($(a)?*) => {}; // ok. matches "a*" and "*" | ^ -error: no rules expected the token `?` +error: no rules expected `?` --> $DIR/macro-at-most-once-rep-2015.rs:38:15 | LL | macro_rules! barstar { @@ -142,7 +142,7 @@ note: while trying to match `*` LL | ($(a)?*) => {}; // ok. matches "a*" and "*" | ^ -error: no rules expected the token `?` +error: no rules expected `?` --> $DIR/macro-at-most-once-rep-2015.rs:39:15 | LL | macro_rules! barstar { diff --git a/tests/ui/macros/macro-at-most-once-rep-2018.rs b/tests/ui/macros/macro-at-most-once-rep-2018.rs index 7f43055ded6..98fbb2ad207 100644 --- a/tests/ui/macros/macro-at-most-once-rep-2018.rs +++ b/tests/ui/macros/macro-at-most-once-rep-2018.rs @@ -22,21 +22,21 @@ macro_rules! barstar { pub fn main() { foo!(); foo!(a); - foo!(a?); //~ ERROR no rules expected the token `?` - foo!(a?a); //~ ERROR no rules expected the token `?` - foo!(a?a?a); //~ ERROR no rules expected the token `?` + foo!(a?); //~ ERROR no rules expected `?` + foo!(a?a); //~ ERROR no rules expected `?` + foo!(a?a?a); //~ ERROR no rules expected `?` barplus!(); //~ERROR unexpected end of macro invocation barplus!(a); //~ERROR unexpected end of macro invocation - barplus!(a?); //~ ERROR no rules expected the token `?` - barplus!(a?a); //~ ERROR no rules expected the token `?` + barplus!(a?); //~ ERROR no rules expected `?` + barplus!(a?a); //~ ERROR no rules expected `?` barplus!(a+); barplus!(+); barstar!(); //~ERROR unexpected end of macro invocation barstar!(a); //~ERROR unexpected end of macro invocation - barstar!(a?); //~ ERROR no rules expected the token `?` - barstar!(a?a); //~ ERROR no rules expected the token `?` + barstar!(a?); //~ ERROR no rules expected `?` + barstar!(a?a); //~ ERROR no rules expected `?` barstar!(a*); barstar!(*); } diff --git a/tests/ui/macros/macro-at-most-once-rep-2018.stderr b/tests/ui/macros/macro-at-most-once-rep-2018.stderr index 696520b2826..f165a199b10 100644 --- a/tests/ui/macros/macro-at-most-once-rep-2018.stderr +++ b/tests/ui/macros/macro-at-most-once-rep-2018.stderr @@ -4,7 +4,7 @@ error: the `?` macro repetition operator does not take a separator LL | ($(a),?) => {}; | ^ -error: no rules expected the token `?` +error: no rules expected `?` --> $DIR/macro-at-most-once-rep-2018.rs:25:11 | LL | macro_rules! foo { @@ -15,7 +15,7 @@ LL | foo!(a?); | = note: while trying to match sequence end -error: no rules expected the token `?` +error: no rules expected `?` --> $DIR/macro-at-most-once-rep-2018.rs:26:11 | LL | macro_rules! foo { @@ -26,7 +26,7 @@ LL | foo!(a?a); | = note: while trying to match sequence end -error: no rules expected the token `?` +error: no rules expected `?` --> $DIR/macro-at-most-once-rep-2018.rs:27:11 | LL | macro_rules! foo { @@ -67,7 +67,7 @@ note: while trying to match `+` LL | ($(a)?+) => {}; // ok. matches "a+" and "+" | ^ -error: no rules expected the token `?` +error: no rules expected `?` --> $DIR/macro-at-most-once-rep-2018.rs:31:15 | LL | macro_rules! barplus { @@ -82,7 +82,7 @@ note: while trying to match `+` LL | ($(a)?+) => {}; // ok. matches "a+" and "+" | ^ -error: no rules expected the token `?` +error: no rules expected `?` --> $DIR/macro-at-most-once-rep-2018.rs:32:15 | LL | macro_rules! barplus { @@ -127,7 +127,7 @@ note: while trying to match `*` LL | ($(a)?*) => {}; // ok. matches "a*" and "*" | ^ -error: no rules expected the token `?` +error: no rules expected `?` --> $DIR/macro-at-most-once-rep-2018.rs:38:15 | LL | macro_rules! barstar { @@ -142,7 +142,7 @@ note: while trying to match `*` LL | ($(a)?*) => {}; // ok. matches "a*" and "*" | ^ -error: no rules expected the token `?` +error: no rules expected `?` --> $DIR/macro-at-most-once-rep-2018.rs:39:15 | LL | macro_rules! barstar { diff --git a/tests/ui/macros/macro-context.rs b/tests/ui/macros/macro-context.rs index d09fdf118e6..a31470263a0 100644 --- a/tests/ui/macros/macro-context.rs +++ b/tests/ui/macros/macro-context.rs @@ -1,9 +1,9 @@ // (typeof used because it's surprisingly hard to find an unparsed token after a stmt) macro_rules! m { () => ( i ; typeof ); //~ ERROR expected expression, found reserved keyword `typeof` - //~| ERROR macro expansion ignores token `typeof` - //~| ERROR macro expansion ignores token `;` - //~| ERROR macro expansion ignores token `;` + //~| ERROR macro expansion ignores reserved keyword `typeof` + //~| ERROR macro expansion ignores `;` + //~| ERROR macro expansion ignores `;` //~| ERROR cannot find type `i` in this scope //~| ERROR cannot find value `i` in this scope //~| WARN trailing semicolon in macro diff --git a/tests/ui/macros/macro-context.stderr b/tests/ui/macros/macro-context.stderr index 7785f415946..4820a43f00c 100644 --- a/tests/ui/macros/macro-context.stderr +++ b/tests/ui/macros/macro-context.stderr @@ -1,4 +1,4 @@ -error: macro expansion ignores token `;` and any following +error: macro expansion ignores `;` and any tokens following --> $DIR/macro-context.rs:3:15 | LL | () => ( i ; typeof ); @@ -9,7 +9,7 @@ LL | let a: m!(); | = note: the usage of `m!` is likely invalid in type context -error: macro expansion ignores token `typeof` and any following +error: macro expansion ignores reserved keyword `typeof` and any tokens following --> $DIR/macro-context.rs:3:17 | LL | () => ( i ; typeof ); @@ -20,7 +20,7 @@ LL | let i = m!(); | = note: the usage of `m!` is likely invalid in expression context -error: macro expansion ignores token `;` and any following +error: macro expansion ignores `;` and any tokens following --> $DIR/macro-context.rs:3:15 | LL | () => ( i ; typeof ); diff --git a/tests/ui/macros/macro-in-expression-context.fixed b/tests/ui/macros/macro-in-expression-context.fixed index f4d04ca37bf..7c830707ffd 100644 --- a/tests/ui/macros/macro-in-expression-context.fixed +++ b/tests/ui/macros/macro-in-expression-context.fixed @@ -11,7 +11,7 @@ macro_rules! foo { //~| NOTE `#[warn(semicolon_in_expressions_from_macros)]` on by default assert_eq!("B", "B"); } - //~^^ ERROR macro expansion ignores token `assert_eq` and any following + //~^^ ERROR macro expansion ignores `assert_eq` and any tokens following //~| NOTE the usage of `foo!` is likely invalid in expression context } diff --git a/tests/ui/macros/macro-in-expression-context.rs b/tests/ui/macros/macro-in-expression-context.rs index 8921a056377..da95017aa5f 100644 --- a/tests/ui/macros/macro-in-expression-context.rs +++ b/tests/ui/macros/macro-in-expression-context.rs @@ -11,7 +11,7 @@ macro_rules! foo { //~| NOTE `#[warn(semicolon_in_expressions_from_macros)]` on by default assert_eq!("B", "B"); } - //~^^ ERROR macro expansion ignores token `assert_eq` and any following + //~^^ ERROR macro expansion ignores `assert_eq` and any tokens following //~| NOTE the usage of `foo!` is likely invalid in expression context } diff --git a/tests/ui/macros/macro-in-expression-context.stderr b/tests/ui/macros/macro-in-expression-context.stderr index 2eee63f307a..43419f2678c 100644 --- a/tests/ui/macros/macro-in-expression-context.stderr +++ b/tests/ui/macros/macro-in-expression-context.stderr @@ -1,4 +1,4 @@ -error: macro expansion ignores token `assert_eq` and any following +error: macro expansion ignores `assert_eq` and any tokens following --> $DIR/macro-in-expression-context.rs:12:9 | LL | assert_eq!("B", "B"); diff --git a/tests/ui/macros/macro-non-lifetime.rs b/tests/ui/macros/macro-non-lifetime.rs index 26e1f2afa91..3defffd2960 100644 --- a/tests/ui/macros/macro-non-lifetime.rs +++ b/tests/ui/macros/macro-non-lifetime.rs @@ -4,5 +4,5 @@ macro_rules! m { ($x:lifetime) => { } } fn main() { m!(a); - //~^ ERROR no rules expected the token `a` + //~^ ERROR no rules expected `a` } diff --git a/tests/ui/macros/macro-non-lifetime.stderr b/tests/ui/macros/macro-non-lifetime.stderr index 9ff3d741c01..35040a2229b 100644 --- a/tests/ui/macros/macro-non-lifetime.stderr +++ b/tests/ui/macros/macro-non-lifetime.stderr @@ -1,4 +1,4 @@ -error: no rules expected the token `a` +error: no rules expected `a` --> $DIR/macro-non-lifetime.rs:6:8 | LL | macro_rules! m { ($x:lifetime) => { } } diff --git a/tests/ui/macros/missing-comma.rs b/tests/ui/macros/missing-comma.rs index 92f8a779505..64cfb0db31a 100644 --- a/tests/ui/macros/missing-comma.rs +++ b/tests/ui/macros/missing-comma.rs @@ -19,16 +19,16 @@ fn main() { println!("{}" a); //~^ ERROR expected `,`, found `a` foo!(a b); - //~^ ERROR no rules expected the token `b` + //~^ ERROR no rules expected `b` foo!(a, b, c, d e); - //~^ ERROR no rules expected the token `e` + //~^ ERROR no rules expected `e` foo!(a, b, c d, e); - //~^ ERROR no rules expected the token `d` + //~^ ERROR no rules expected `d` foo!(a, b, c d e); - //~^ ERROR no rules expected the token `d` + //~^ ERROR no rules expected `d` bar!(Level::Error, ); //~^ ERROR unexpected end of macro invocation check!(<str as Debug>::fmt, "fmt"); check!(<str as Debug>::fmt, "fmt",); - //~^ ERROR no rules expected the token `,` + //~^ ERROR no rules expected `,` } diff --git a/tests/ui/macros/missing-comma.stderr b/tests/ui/macros/missing-comma.stderr index 81877a29ed8..9913ba34919 100644 --- a/tests/ui/macros/missing-comma.stderr +++ b/tests/ui/macros/missing-comma.stderr @@ -4,7 +4,7 @@ error: expected `,`, found `a` LL | println!("{}" a); | ^ expected `,` -error: no rules expected the token `b` +error: no rules expected `b` --> $DIR/missing-comma.rs:21:12 | LL | macro_rules! foo { @@ -21,7 +21,7 @@ note: while trying to match meta-variable `$a:ident` LL | ($a:ident) => (); | ^^^^^^^^ -error: no rules expected the token `e` +error: no rules expected `e` --> $DIR/missing-comma.rs:23:21 | LL | macro_rules! foo { @@ -38,7 +38,7 @@ note: while trying to match meta-variable `$d:ident` LL | ($a:ident, $b:ident, $c:ident, $d:ident) => (); | ^^^^^^^^ -error: no rules expected the token `d` +error: no rules expected `d` --> $DIR/missing-comma.rs:25:18 | LL | macro_rules! foo { @@ -55,7 +55,7 @@ note: while trying to match meta-variable `$c:ident` LL | ($a:ident, $b:ident, $c:ident) => (); | ^^^^^^^^ -error: no rules expected the token `d` +error: no rules expected `d` --> $DIR/missing-comma.rs:27:18 | LL | macro_rules! foo { @@ -85,7 +85,7 @@ note: while trying to match meta-variable `$arg:tt` LL | ($lvl:expr, $($arg:tt)+) => {} | ^^^^^^^ -error: no rules expected the token `,` +error: no rules expected `,` --> $DIR/missing-comma.rs:32:38 | LL | macro_rules! check { diff --git a/tests/ui/macros/nonterminal-matching.rs b/tests/ui/macros/nonterminal-matching.rs index 5f0d6b2f90e..a655b665103 100644 --- a/tests/ui/macros/nonterminal-matching.rs +++ b/tests/ui/macros/nonterminal-matching.rs @@ -16,7 +16,7 @@ macro complex_nonterminal($nt_item: item) { struct S; } - n!(a $nt_item b); //~ ERROR no rules expected the token `enum E {}` + n!(a $nt_item b); //~ ERROR no rules expected item `enum E {}` } simple_nonterminal!(a, 'a, (x, y, z)); // OK @@ -29,10 +29,10 @@ macro_rules! foo { (ident $x:ident) => { bar!(ident $x); }; (lifetime $x:lifetime) => { bar!(lifetime $x); }; (tt $x:tt) => { bar!(tt $x); }; - (expr $x:expr) => { bar!(expr $x); }; //~ ERROR: no rules expected the token `3` - (literal $x:literal) => { bar!(literal $x); }; //~ ERROR: no rules expected the token `4` - (path $x:path) => { bar!(path $x); }; //~ ERROR: no rules expected the token `a::b::c` - (stmt $x:stmt) => { bar!(stmt $x); }; //~ ERROR: no rules expected the token `let abc = 0` + (expr $x:expr) => { bar!(expr $x); }; //~ ERROR: no rules expected expression `3` + (literal $x:literal) => { bar!(literal $x); }; //~ ERROR: no rules expected literal `4` + (path $x:path) => { bar!(path $x); }; //~ ERROR: no rules expected path `a::b::c` + (stmt $x:stmt) => { bar!(stmt $x); }; //~ ERROR: no rules expected statement `let abc = 0` } macro_rules! bar { diff --git a/tests/ui/macros/nonterminal-matching.stderr b/tests/ui/macros/nonterminal-matching.stderr index 3ee88b5f52e..e283dfcb8fd 100644 --- a/tests/ui/macros/nonterminal-matching.stderr +++ b/tests/ui/macros/nonterminal-matching.stderr @@ -1,4 +1,4 @@ -error: no rules expected the token `enum E {}` +error: no rules expected item `enum E {}` --> $DIR/nonterminal-matching.rs:19:10 | LL | macro n(a $nt_item b) { @@ -10,7 +10,7 @@ LL | n!(a $nt_item b); LL | complex_nonterminal!(enum E {}); | ------------------------------- in this macro invocation | -note: while trying to match `enum E {}` +note: while trying to match item `enum E {}` --> $DIR/nonterminal-matching.rs:15:15 | LL | macro n(a $nt_item b) { @@ -23,7 +23,7 @@ LL | complex_nonterminal!(enum E {}); = help: try using `:tt` instead in the macro definition = note: this error originates in the macro `complex_nonterminal` (in Nightly builds, run with -Z macro-backtrace for more info) -error: no rules expected the token `3` +error: no rules expected expression `3` --> $DIR/nonterminal-matching.rs:32:35 | LL | (expr $x:expr) => { bar!(expr $x); }; @@ -45,7 +45,7 @@ LL | (expr 3) => {}; = help: try using `:tt` instead in the macro definition = note: this error originates in the macro `foo` (in Nightly builds, run with -Z macro-backtrace for more info) -error: no rules expected the token `4` +error: no rules expected literal `4` --> $DIR/nonterminal-matching.rs:33:44 | LL | (literal $x:literal) => { bar!(literal $x); }; @@ -67,7 +67,7 @@ LL | (literal 4) => {}; = help: try using `:tt` instead in the macro definition = note: this error originates in the macro `foo` (in Nightly builds, run with -Z macro-backtrace for more info) -error: no rules expected the token `a::b::c` +error: no rules expected path `a::b::c` --> $DIR/nonterminal-matching.rs:34:35 | LL | (path $x:path) => { bar!(path $x); }; @@ -89,7 +89,7 @@ LL | (path a::b::c) => {}; = help: try using `:tt` instead in the macro definition = note: this error originates in the macro `foo` (in Nightly builds, run with -Z macro-backtrace for more info) -error: no rules expected the token `let abc = 0` +error: no rules expected statement `let abc = 0` --> $DIR/nonterminal-matching.rs:35:35 | LL | (stmt $x:stmt) => { bar!(stmt $x); }; @@ -101,7 +101,7 @@ LL | macro_rules! bar { LL | foo!(stmt let abc = 0); | ---------------------- in this macro invocation | -note: while trying to match `let` +note: while trying to match keyword `let` --> $DIR/nonterminal-matching.rs:45:11 | LL | (stmt let abc = 0) => {}; diff --git a/tests/ui/macros/syntax-error-recovery.rs b/tests/ui/macros/syntax-error-recovery.rs index f6178c137db..016e4def284 100644 --- a/tests/ui/macros/syntax-error-recovery.rs +++ b/tests/ui/macros/syntax-error-recovery.rs @@ -10,7 +10,7 @@ macro_rules! values { }; } //~^^^^^ ERROR expected one of `(`, `,`, `=`, `{`, or `}`, found type `(String)` -//~| ERROR macro expansion ignores token `(String)` and any following +//~| ERROR macro expansion ignores type `(String)` and any tokens following values!(STRING(1) as (String) => cfg(test),); //~^ ERROR expected one of `!` or `::`, found `<eof>` diff --git a/tests/ui/macros/syntax-error-recovery.stderr b/tests/ui/macros/syntax-error-recovery.stderr index 6218bf43a1e..3cfbd8ce82b 100644 --- a/tests/ui/macros/syntax-error-recovery.stderr +++ b/tests/ui/macros/syntax-error-recovery.stderr @@ -10,7 +10,7 @@ LL | values!(STRING(1) as (String) => cfg(test),); = help: enum variants can be `Variant`, `Variant = <integer>`, `Variant(Type, ..., TypeN)` or `Variant { fields: Types }` = note: this error originates in the macro `values` (in Nightly builds, run with -Z macro-backtrace for more info) -error: macro expansion ignores token `(String)` and any following +error: macro expansion ignores type `(String)` and any tokens following --> $DIR/syntax-error-recovery.rs:7:26 | LL | $token $($inner)? = $value, diff --git a/tests/ui/macros/trace_faulty_macros.stderr b/tests/ui/macros/trace_faulty_macros.stderr index 66d7b76bb07..10ad3faab16 100644 --- a/tests/ui/macros/trace_faulty_macros.stderr +++ b/tests/ui/macros/trace_faulty_macros.stderr @@ -1,4 +1,4 @@ -error: no rules expected the token `bcd` +error: no rules expected `bcd` --> $DIR/trace_faulty_macros.rs:7:26 | LL | macro_rules! my_faulty_macro { diff --git a/tests/ui/mir/mir_let_chains_drop_order.rs b/tests/ui/mir/mir_let_chains_drop_order.rs index daf0a62fc85..92199625207 100644 --- a/tests/ui/mir/mir_let_chains_drop_order.rs +++ b/tests/ui/mir/mir_let_chains_drop_order.rs @@ -8,7 +8,6 @@ // See `mir_drop_order.rs` for more information #![feature(let_chains)] -#![cfg_attr(edition2024, feature(if_let_rescope))] #![allow(irrefutable_let_patterns)] use std::cell::RefCell; diff --git a/tests/ui/modules/issue-107649.stderr b/tests/ui/modules/issue-107649.stderr index d5405c6576a..0d203c1aacb 100644 --- a/tests/ui/modules/issue-107649.stderr +++ b/tests/ui/modules/issue-107649.stderr @@ -4,7 +4,7 @@ error[E0277]: `Dummy` doesn't implement `Debug` 105 | dbg!(lib::Dummy); | ^^^^^^^^^^^^^^^^ `Dummy` cannot be formatted using `{:?}` | - = help: the trait `Debug` is not implemented for `Dummy`, which is required by `&Dummy: Debug` + = help: the trait `Debug` is not implemented for `Dummy` = note: add `#[derive(Debug)]` to `Dummy` or manually `impl Debug for Dummy` = note: this error originates in the macro `$crate::format_args_nl` which comes from the expansion of the macro `dbg` (in Nightly builds, run with -Z macro-backtrace for more info) help: consider annotating `Dummy` with `#[derive(Debug)]` diff --git a/tests/ui/mut/mutable-enum-indirect.stderr b/tests/ui/mut/mutable-enum-indirect.stderr index d7af327df5a..0b7783b3318 100644 --- a/tests/ui/mut/mutable-enum-indirect.stderr +++ b/tests/ui/mut/mutable-enum-indirect.stderr @@ -6,7 +6,7 @@ LL | bar(&x); | | | required by a bound introduced by this call | - = help: within `&Foo`, the trait `Sync` is not implemented for `NoSync`, which is required by `&Foo: Sync` + = help: within `&Foo`, the trait `Sync` is not implemented for `NoSync` note: required because it appears within the type `Foo` --> $DIR/mutable-enum-indirect.rs:11:6 | diff --git a/tests/ui/nll/issue-54556-niconii.edition2021.stderr b/tests/ui/nll/issue-54556-niconii.edition2021.stderr index 31a03abbc98..abee09ed950 100644 --- a/tests/ui/nll/issue-54556-niconii.edition2021.stderr +++ b/tests/ui/nll/issue-54556-niconii.edition2021.stderr @@ -1,5 +1,5 @@ error[E0597]: `counter` does not live long enough - --> $DIR/issue-54556-niconii.rs:30:20 + --> $DIR/issue-54556-niconii.rs:28:20 | LL | let counter = Mutex; | ------- binding `counter` declared here diff --git a/tests/ui/nll/issue-54556-niconii.rs b/tests/ui/nll/issue-54556-niconii.rs index 1a7ad17cc84..f01e0523cbf 100644 --- a/tests/ui/nll/issue-54556-niconii.rs +++ b/tests/ui/nll/issue-54556-niconii.rs @@ -12,8 +12,6 @@ //@ [edition2024] compile-flags: -Z unstable-options //@ [edition2024] check-pass -#![cfg_attr(edition2024, feature(if_let_rescope))] - struct Mutex; struct MutexGuard<'a>(&'a Mutex); diff --git a/tests/ui/no-send-res-ports.stderr b/tests/ui/no-send-res-ports.stderr index c71d8ecba37..9c30261e5cb 100644 --- a/tests/ui/no-send-res-ports.stderr +++ b/tests/ui/no-send-res-ports.stderr @@ -13,7 +13,7 @@ LL | | println!("{:?}", y); LL | | }); | |_____^ `Rc<()>` cannot be sent between threads safely | - = help: within `{closure@$DIR/no-send-res-ports.rs:25:19: 25:25}`, the trait `Send` is not implemented for `Rc<()>`, which is required by `{closure@$DIR/no-send-res-ports.rs:25:19: 25:25}: Send` + = help: within `{closure@$DIR/no-send-res-ports.rs:25:19: 25:25}`, the trait `Send` is not implemented for `Rc<()>` note: required because it appears within the type `Port<()>` --> $DIR/no-send-res-ports.rs:5:8 | diff --git a/tests/ui/no_send-enum.stderr b/tests/ui/no_send-enum.stderr index e24f79c7dd6..3b66c7db545 100644 --- a/tests/ui/no_send-enum.stderr +++ b/tests/ui/no_send-enum.stderr @@ -6,7 +6,7 @@ LL | bar(x); | | | required by a bound introduced by this call | - = help: within `Foo`, the trait `Send` is not implemented for `NoSend`, which is required by `Foo: Send` + = help: within `Foo`, the trait `Send` is not implemented for `NoSend` note: required because it appears within the type `Foo` --> $DIR/no_send-enum.rs:8:6 | diff --git a/tests/ui/no_share-enum.stderr b/tests/ui/no_share-enum.stderr index 5b6c8bf0b4f..89939216d5b 100644 --- a/tests/ui/no_share-enum.stderr +++ b/tests/ui/no_share-enum.stderr @@ -6,7 +6,7 @@ LL | bar(x); | | | required by a bound introduced by this call | - = help: within `Foo`, the trait `Sync` is not implemented for `NoSync`, which is required by `Foo: Sync` + = help: within `Foo`, the trait `Sync` is not implemented for `NoSync` note: required because it appears within the type `Foo` --> $DIR/no_share-enum.rs:8:6 | diff --git a/tests/ui/not-clone-closure.stderr b/tests/ui/not-clone-closure.stderr index 9b557b15582..783c165eeb2 100644 --- a/tests/ui/not-clone-closure.stderr +++ b/tests/ui/not-clone-closure.stderr @@ -5,7 +5,7 @@ LL | let hello = move || { | ------- within this `{closure@$DIR/not-clone-closure.rs:7:17: 7:24}` ... LL | let hello = hello.clone(); - | ^^^^^ within `{closure@$DIR/not-clone-closure.rs:7:17: 7:24}`, the trait `Clone` is not implemented for `S`, which is required by `{closure@$DIR/not-clone-closure.rs:7:17: 7:24}: Clone` + | ^^^^^ within `{closure@$DIR/not-clone-closure.rs:7:17: 7:24}`, the trait `Clone` is not implemented for `S` | note: required because it's used within this closure --> $DIR/not-clone-closure.rs:7:17 diff --git a/tests/ui/not-panic/not-panic-safe-2.stderr b/tests/ui/not-panic/not-panic-safe-2.stderr index 8c4cf9c98ed..0c399f15a25 100644 --- a/tests/ui/not-panic/not-panic-safe-2.stderr +++ b/tests/ui/not-panic/not-panic-safe-2.stderr @@ -4,7 +4,7 @@ error[E0277]: the type `UnsafeCell<i32>` may contain interior mutability and a r LL | assert::<Rc<RefCell<i32>>>(); | ^^^^^^^^^^^^^^^^ `UnsafeCell<i32>` may contain interior mutability and a reference may not be safely transferrable across a catch_unwind boundary | - = help: within `RefCell<i32>`, the trait `RefUnwindSafe` is not implemented for `UnsafeCell<i32>`, which is required by `Rc<RefCell<i32>>: UnwindSafe` + = help: within `RefCell<i32>`, the trait `RefUnwindSafe` is not implemented for `UnsafeCell<i32>` note: required because it appears within the type `RefCell<i32>` --> $SRC_DIR/core/src/cell.rs:LL:COL = note: required for `Rc<RefCell<i32>>` to implement `UnwindSafe` @@ -20,7 +20,7 @@ error[E0277]: the type `UnsafeCell<isize>` may contain interior mutability and a LL | assert::<Rc<RefCell<i32>>>(); | ^^^^^^^^^^^^^^^^ `UnsafeCell<isize>` may contain interior mutability and a reference may not be safely transferrable across a catch_unwind boundary | - = help: within `RefCell<i32>`, the trait `RefUnwindSafe` is not implemented for `UnsafeCell<isize>`, which is required by `Rc<RefCell<i32>>: UnwindSafe` + = help: within `RefCell<i32>`, the trait `RefUnwindSafe` is not implemented for `UnsafeCell<isize>` note: required because it appears within the type `Cell<isize>` --> $SRC_DIR/core/src/cell.rs:LL:COL note: required because it appears within the type `RefCell<i32>` diff --git a/tests/ui/not-panic/not-panic-safe-3.stderr b/tests/ui/not-panic/not-panic-safe-3.stderr index 2373ada63f6..53028d6a337 100644 --- a/tests/ui/not-panic/not-panic-safe-3.stderr +++ b/tests/ui/not-panic/not-panic-safe-3.stderr @@ -4,7 +4,7 @@ error[E0277]: the type `UnsafeCell<i32>` may contain interior mutability and a r LL | assert::<Arc<RefCell<i32>>>(); | ^^^^^^^^^^^^^^^^^ `UnsafeCell<i32>` may contain interior mutability and a reference may not be safely transferrable across a catch_unwind boundary | - = help: within `RefCell<i32>`, the trait `RefUnwindSafe` is not implemented for `UnsafeCell<i32>`, which is required by `Arc<RefCell<i32>>: UnwindSafe` + = help: within `RefCell<i32>`, the trait `RefUnwindSafe` is not implemented for `UnsafeCell<i32>` note: required because it appears within the type `RefCell<i32>` --> $SRC_DIR/core/src/cell.rs:LL:COL = note: required for `Arc<RefCell<i32>>` to implement `UnwindSafe` @@ -20,7 +20,7 @@ error[E0277]: the type `UnsafeCell<isize>` may contain interior mutability and a LL | assert::<Arc<RefCell<i32>>>(); | ^^^^^^^^^^^^^^^^^ `UnsafeCell<isize>` may contain interior mutability and a reference may not be safely transferrable across a catch_unwind boundary | - = help: within `RefCell<i32>`, the trait `RefUnwindSafe` is not implemented for `UnsafeCell<isize>`, which is required by `Arc<RefCell<i32>>: UnwindSafe` + = help: within `RefCell<i32>`, the trait `RefUnwindSafe` is not implemented for `UnsafeCell<isize>` note: required because it appears within the type `Cell<isize>` --> $SRC_DIR/core/src/cell.rs:LL:COL note: required because it appears within the type `RefCell<i32>` diff --git a/tests/ui/not-panic/not-panic-safe-4.stderr b/tests/ui/not-panic/not-panic-safe-4.stderr index d77cac8f272..b1361cfd87e 100644 --- a/tests/ui/not-panic/not-panic-safe-4.stderr +++ b/tests/ui/not-panic/not-panic-safe-4.stderr @@ -4,7 +4,7 @@ error[E0277]: the type `UnsafeCell<i32>` may contain interior mutability and a r LL | assert::<&RefCell<i32>>(); | ^^^^^^^^^^^^^ `UnsafeCell<i32>` may contain interior mutability and a reference may not be safely transferrable across a catch_unwind boundary | - = help: within `RefCell<i32>`, the trait `RefUnwindSafe` is not implemented for `UnsafeCell<i32>`, which is required by `&RefCell<i32>: UnwindSafe` + = help: within `RefCell<i32>`, the trait `RefUnwindSafe` is not implemented for `UnsafeCell<i32>` note: required because it appears within the type `RefCell<i32>` --> $SRC_DIR/core/src/cell.rs:LL:COL = note: required for `&RefCell<i32>` to implement `UnwindSafe` @@ -25,7 +25,7 @@ error[E0277]: the type `UnsafeCell<isize>` may contain interior mutability and a LL | assert::<&RefCell<i32>>(); | ^^^^^^^^^^^^^ `UnsafeCell<isize>` may contain interior mutability and a reference may not be safely transferrable across a catch_unwind boundary | - = help: within `RefCell<i32>`, the trait `RefUnwindSafe` is not implemented for `UnsafeCell<isize>`, which is required by `&RefCell<i32>: UnwindSafe` + = help: within `RefCell<i32>`, the trait `RefUnwindSafe` is not implemented for `UnsafeCell<isize>` note: required because it appears within the type `Cell<isize>` --> $SRC_DIR/core/src/cell.rs:LL:COL note: required because it appears within the type `RefCell<i32>` diff --git a/tests/ui/not-panic/not-panic-safe-5.stderr b/tests/ui/not-panic/not-panic-safe-5.stderr index 0de9a2cc0cd..fbbd81d6d4c 100644 --- a/tests/ui/not-panic/not-panic-safe-5.stderr +++ b/tests/ui/not-panic/not-panic-safe-5.stderr @@ -4,7 +4,7 @@ error[E0277]: the type `UnsafeCell<i32>` may contain interior mutability and a r LL | assert::<*const UnsafeCell<i32>>(); | ^^^^^^^^^^^^^^^^^^^^^^ `UnsafeCell<i32>` may contain interior mutability and a reference may not be safely transferrable across a catch_unwind boundary | - = help: the trait `RefUnwindSafe` is not implemented for `UnsafeCell<i32>`, which is required by `*const UnsafeCell<i32>: UnwindSafe` + = help: the trait `RefUnwindSafe` is not implemented for `UnsafeCell<i32>` = note: required for `*const UnsafeCell<i32>` to implement `UnwindSafe` note: required by a bound in `assert` --> $DIR/not-panic-safe-5.rs:6:14 diff --git a/tests/ui/not-panic/not-panic-safe-6.stderr b/tests/ui/not-panic/not-panic-safe-6.stderr index 7714a577f8a..47f28257409 100644 --- a/tests/ui/not-panic/not-panic-safe-6.stderr +++ b/tests/ui/not-panic/not-panic-safe-6.stderr @@ -4,7 +4,7 @@ error[E0277]: the type `UnsafeCell<i32>` may contain interior mutability and a r LL | assert::<*mut RefCell<i32>>(); | ^^^^^^^^^^^^^^^^^ `UnsafeCell<i32>` may contain interior mutability and a reference may not be safely transferrable across a catch_unwind boundary | - = help: within `RefCell<i32>`, the trait `RefUnwindSafe` is not implemented for `UnsafeCell<i32>`, which is required by `*mut RefCell<i32>: UnwindSafe` + = help: within `RefCell<i32>`, the trait `RefUnwindSafe` is not implemented for `UnsafeCell<i32>` note: required because it appears within the type `RefCell<i32>` --> $SRC_DIR/core/src/cell.rs:LL:COL = note: required for `*mut RefCell<i32>` to implement `UnwindSafe` @@ -20,7 +20,7 @@ error[E0277]: the type `UnsafeCell<isize>` may contain interior mutability and a LL | assert::<*mut RefCell<i32>>(); | ^^^^^^^^^^^^^^^^^ `UnsafeCell<isize>` may contain interior mutability and a reference may not be safely transferrable across a catch_unwind boundary | - = help: within `RefCell<i32>`, the trait `RefUnwindSafe` is not implemented for `UnsafeCell<isize>`, which is required by `*mut RefCell<i32>: UnwindSafe` + = help: within `RefCell<i32>`, the trait `RefUnwindSafe` is not implemented for `UnsafeCell<isize>` note: required because it appears within the type `Cell<isize>` --> $SRC_DIR/core/src/cell.rs:LL:COL note: required because it appears within the type `RefCell<i32>` diff --git a/tests/ui/offset-of/offset-of-arg-count.rs b/tests/ui/offset-of/offset-of-arg-count.rs index c86e61a61a7..f4c8b91d7da 100644 --- a/tests/ui/offset-of/offset-of-arg-count.rs +++ b/tests/ui/offset-of/offset-of-arg-count.rs @@ -3,7 +3,7 @@ use std::mem::offset_of; fn main() { offset_of!(NotEnoughArguments); //~ ERROR unexpected end of macro invocation offset_of!(NotEnoughArgumentsWithAComma, ); //~ ERROR unexpected end of macro invocation - offset_of!(Container, field, too many arguments); //~ ERROR no rules expected the token `too` + offset_of!(Container, field, too many arguments); //~ ERROR no rules expected `too` offset_of!(S, f); // compiles fine offset_of!(S, f,); // also compiles fine offset_of!(S, f.); //~ ERROR unexpected token: `)` diff --git a/tests/ui/offset-of/offset-of-arg-count.stderr b/tests/ui/offset-of/offset-of-arg-count.stderr index 4cb24b3d034..0772bb18e0c 100644 --- a/tests/ui/offset-of/offset-of-arg-count.stderr +++ b/tests/ui/offset-of/offset-of-arg-count.stderr @@ -16,7 +16,7 @@ LL | offset_of!(NotEnoughArgumentsWithAComma, ); note: while trying to match meta-variable `$fields:expr` --> $SRC_DIR/core/src/mem/mod.rs:LL:COL -error: no rules expected the token `too` +error: no rules expected `too` --> $DIR/offset-of-arg-count.rs:6:34 | LL | offset_of!(Container, field, too many arguments); diff --git a/tests/ui/offset-of/offset-of-dst-field.stderr b/tests/ui/offset-of/offset-of-dst-field.stderr index bcfe796897e..714bf7a0266 100644 --- a/tests/ui/offset-of/offset-of-dst-field.stderr +++ b/tests/ui/offset-of/offset-of-dst-field.stderr @@ -58,7 +58,7 @@ error[E0277]: the size for values of type `[u8]` cannot be known at compilation LL | offset_of!(Delta<Alpha>, z); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^ doesn't have a size known at compile-time | - = help: within `Alpha`, the trait `Sized` is not implemented for `[u8]`, which is required by `Alpha: Sized` + = help: within `Alpha`, the trait `Sized` is not implemented for `[u8]` note: required because it appears within the type `Alpha` --> $DIR/offset-of-dst-field.rs:5:8 | diff --git a/tests/ui/offset-of/offset-of-tuple.stderr b/tests/ui/offset-of/offset-of-tuple.stderr index dd20859e04e..38ce49c9179 100644 --- a/tests/ui/offset-of/offset-of-tuple.stderr +++ b/tests/ui/offset-of/offset-of-tuple.stderr @@ -76,7 +76,7 @@ error: suffixes on a tuple index are invalid LL | offset_of!((u8, u8), 1_u8); | ^^^^ invalid suffix `u8` -error: no rules expected the token `+` +error: no rules expected `+` --> $DIR/offset-of-tuple.rs:11:26 | LL | offset_of!((u8, u8), +1); diff --git a/tests/ui/on-unimplemented/slice-index.stderr b/tests/ui/on-unimplemented/slice-index.stderr index 0f8d105abef..d53ecb9db0c 100644 --- a/tests/ui/on-unimplemented/slice-index.stderr +++ b/tests/ui/on-unimplemented/slice-index.stderr @@ -4,7 +4,7 @@ error[E0277]: the type `[i32]` cannot be indexed by `i32` LL | x[1i32]; | ^^^^ slice indices are of type `usize` or ranges of `usize` | - = help: the trait `SliceIndex<[i32]>` is not implemented for `i32`, which is required by `[i32]: Index<_>` + = help: the trait `SliceIndex<[i32]>` is not implemented for `i32` = help: the trait `SliceIndex<[i32]>` is implemented for `usize` = help: for that trait implementation, expected `usize`, found `i32` = note: required for `[i32]` to implement `Index<i32>` @@ -15,7 +15,7 @@ error[E0277]: the type `[i32]` cannot be indexed by `RangeTo<i32>` LL | x[..1i32]; | ^^^^^^ slice indices are of type `usize` or ranges of `usize` | - = help: the trait `SliceIndex<[i32]>` is not implemented for `RangeTo<i32>`, which is required by `[i32]: Index<_>` + = help: the trait `SliceIndex<[i32]>` is not implemented for `RangeTo<i32>` = help: the following other types implement trait `SliceIndex<T>`: `RangeTo<usize>` implements `SliceIndex<[T]>` `RangeTo<usize>` implements `SliceIndex<str>` diff --git a/tests/ui/or-patterns/or-patterns-syntactic-fail-2018.rs b/tests/ui/or-patterns/or-patterns-syntactic-fail-2018.rs index 7a94c96b79d..fb227bf0e91 100644 --- a/tests/ui/or-patterns/or-patterns-syntactic-fail-2018.rs +++ b/tests/ui/or-patterns/or-patterns-syntactic-fail-2018.rs @@ -9,5 +9,5 @@ macro_rules! accept_pat { ($p:pat) => {}; } -accept_pat!(p | q); //~ ERROR no rules expected the token `|` -accept_pat!(|p| q); //~ ERROR no rules expected the token `|` +accept_pat!(p | q); //~ ERROR no rules expected `|` +accept_pat!(|p| q); //~ ERROR no rules expected `|` diff --git a/tests/ui/or-patterns/or-patterns-syntactic-fail-2018.stderr b/tests/ui/or-patterns/or-patterns-syntactic-fail-2018.stderr index acc2099bbc6..47dac84ee49 100644 --- a/tests/ui/or-patterns/or-patterns-syntactic-fail-2018.stderr +++ b/tests/ui/or-patterns/or-patterns-syntactic-fail-2018.stderr @@ -1,4 +1,4 @@ -error: no rules expected the token `|` +error: no rules expected `|` --> $DIR/or-patterns-syntactic-fail-2018.rs:12:15 | LL | macro_rules! accept_pat { @@ -13,7 +13,7 @@ note: while trying to match meta-variable `$p:pat` LL | ($p:pat) => {}; | ^^^^^^ -error: no rules expected the token `|` +error: no rules expected `|` --> $DIR/or-patterns-syntactic-fail-2018.rs:13:13 | LL | macro_rules! accept_pat { diff --git a/tests/ui/parser/macro/macro-doc-comments-1.rs b/tests/ui/parser/macro/macro-doc-comments-1.rs index 8d8103bb1e0..1aaa993e072 100644 --- a/tests/ui/parser/macro/macro-doc-comments-1.rs +++ b/tests/ui/parser/macro/macro-doc-comments-1.rs @@ -4,6 +4,6 @@ macro_rules! outer { outer! { //! Inner -} //~^ ERROR no rules expected the token `!` +} //~^ ERROR no rules expected `!` fn main() { } diff --git a/tests/ui/parser/macro/macro-doc-comments-1.stderr b/tests/ui/parser/macro/macro-doc-comments-1.stderr index 9d2d1bc0072..6b7e758980c 100644 --- a/tests/ui/parser/macro/macro-doc-comments-1.stderr +++ b/tests/ui/parser/macro/macro-doc-comments-1.stderr @@ -1,4 +1,4 @@ -error: no rules expected the token `!` +error: no rules expected `!` --> $DIR/macro-doc-comments-1.rs:6:5 | LL | macro_rules! outer { diff --git a/tests/ui/parser/macro/macro-doc-comments-2.rs b/tests/ui/parser/macro/macro-doc-comments-2.rs index 8f33720ae80..2bee2435ef8 100644 --- a/tests/ui/parser/macro/macro-doc-comments-2.rs +++ b/tests/ui/parser/macro/macro-doc-comments-2.rs @@ -4,6 +4,6 @@ macro_rules! inner { inner! { /// Outer -} //~^ ERROR no rules expected the token `[` +} //~^ ERROR no rules expected `[` fn main() { } diff --git a/tests/ui/parser/macro/macro-doc-comments-2.stderr b/tests/ui/parser/macro/macro-doc-comments-2.stderr index 22efd995b46..02c12bf9591 100644 --- a/tests/ui/parser/macro/macro-doc-comments-2.stderr +++ b/tests/ui/parser/macro/macro-doc-comments-2.stderr @@ -1,4 +1,4 @@ -error: no rules expected the token `[` +error: no rules expected `[` --> $DIR/macro-doc-comments-2.rs:6:5 | LL | macro_rules! inner { diff --git a/tests/ui/parser/macro/macro-expand-to-match-arm.rs b/tests/ui/parser/macro/macro-expand-to-match-arm.rs index db38fa0d7bc..0e27836b718 100644 --- a/tests/ui/parser/macro/macro-expand-to-match-arm.rs +++ b/tests/ui/parser/macro/macro-expand-to-match-arm.rs @@ -1,7 +1,7 @@ macro_rules! arm { ($pattern:pat => $block:block) => { $pattern => $block - //~^ ERROR macro expansion ignores token `=>` and any following + //~^ ERROR macro expansion ignores `=>` and any tokens following //~| NOTE the usage of `arm!` is likely invalid in pattern context //~| NOTE macros cannot expand to match arms }; diff --git a/tests/ui/parser/macro/macro-expand-to-match-arm.stderr b/tests/ui/parser/macro/macro-expand-to-match-arm.stderr index e3e7ff89c81..1927d80fd72 100644 --- a/tests/ui/parser/macro/macro-expand-to-match-arm.stderr +++ b/tests/ui/parser/macro/macro-expand-to-match-arm.stderr @@ -1,4 +1,4 @@ -error: macro expansion ignores token `=>` and any following +error: macro expansion ignores `=>` and any tokens following --> $DIR/macro-expand-to-match-arm.rs:3:18 | LL | $pattern => $block diff --git a/tests/ui/parser/macro/macro-incomplete-parse.rs b/tests/ui/parser/macro/macro-incomplete-parse.rs index 544e4aa7b1b..612196aa4b2 100644 --- a/tests/ui/parser/macro/macro-incomplete-parse.rs +++ b/tests/ui/parser/macro/macro-incomplete-parse.rs @@ -2,7 +2,7 @@ macro_rules! ignored_item { () => { fn foo() {} fn bar() {} - , //~ ERROR macro expansion ignores token `,` + , //~ ERROR macro expansion ignores `,` } } @@ -13,7 +13,7 @@ macro_rules! ignored_expr { } macro_rules! ignored_pat { - () => ( 1, 2 ) //~ ERROR macro expansion ignores token `,` + () => ( 1, 2 ) //~ ERROR macro expansion ignores `,` } ignored_item!(); diff --git a/tests/ui/parser/macro/macro-incomplete-parse.stderr b/tests/ui/parser/macro/macro-incomplete-parse.stderr index 707417b725e..096b5f718ae 100644 --- a/tests/ui/parser/macro/macro-incomplete-parse.stderr +++ b/tests/ui/parser/macro/macro-incomplete-parse.stderr @@ -1,4 +1,4 @@ -error: macro expansion ignores token `,` and any following +error: macro expansion ignores `,` and any tokens following --> $DIR/macro-incomplete-parse.rs:5:9 | LL | , @@ -20,7 +20,7 @@ LL | ignored_expr!(); | = note: this error originates in the macro `ignored_expr` (in Nightly builds, run with -Z macro-backtrace for more info) -error: macro expansion ignores token `,` and any following +error: macro expansion ignores `,` and any tokens following --> $DIR/macro-incomplete-parse.rs:16:14 | LL | () => ( 1, 2 ) diff --git a/tests/ui/parser/macro/trait-non-item-macros.rs b/tests/ui/parser/macro/trait-non-item-macros.rs index 97fb564bf64..e93000193b6 100644 --- a/tests/ui/parser/macro/trait-non-item-macros.rs +++ b/tests/ui/parser/macro/trait-non-item-macros.rs @@ -1,7 +1,7 @@ macro_rules! bah { ($a:expr) => { $a - }; //~^ ERROR macro expansion ignores token `2` and any following + }; //~^ ERROR macro expansion ignores expression `2` and any tokens following } trait Bar { diff --git a/tests/ui/parser/macro/trait-non-item-macros.stderr b/tests/ui/parser/macro/trait-non-item-macros.stderr index db20e6b24aa..1a828483778 100644 --- a/tests/ui/parser/macro/trait-non-item-macros.stderr +++ b/tests/ui/parser/macro/trait-non-item-macros.stderr @@ -1,4 +1,4 @@ -error: macro expansion ignores token `2` and any following +error: macro expansion ignores expression `2` and any tokens following --> $DIR/trait-non-item-macros.rs:3:9 | LL | $a diff --git a/tests/ui/parser/struct-literal-in-for.stderr b/tests/ui/parser/struct-literal-in-for.stderr index d2ef2ad7b5a..1c91eba68e3 100644 --- a/tests/ui/parser/struct-literal-in-for.stderr +++ b/tests/ui/parser/struct-literal-in-for.stderr @@ -23,7 +23,7 @@ LL | | x: 3 LL | | }.hi() { | |__________^ `bool` is not an iterator | - = help: the trait `Iterator` is not implemented for `bool`, which is required by `bool: IntoIterator` + = help: the trait `Iterator` is not implemented for `bool` = note: required for `bool` to implement `IntoIterator` error: aborting due to 2 previous errors diff --git a/tests/ui/proc-macro/attr-invalid-exprs.rs b/tests/ui/proc-macro/attr-invalid-exprs.rs index 3d8806ee800..ec0b79469a4 100644 --- a/tests/ui/proc-macro/attr-invalid-exprs.rs +++ b/tests/ui/proc-macro/attr-invalid-exprs.rs @@ -13,7 +13,7 @@ fn main() { //~^ ERROR expected expression, found end of macro arguments let _ = #[duplicate] "Hello, world!"; - //~^ ERROR macro expansion ignores token `,` and any following + //~^ ERROR macro expansion ignores `,` and any tokens following let _ = { #[no_output] @@ -22,7 +22,7 @@ fn main() { let _ = { #[duplicate] - //~^ ERROR macro expansion ignores token `,` and any following + //~^ ERROR macro expansion ignores `,` and any tokens following "Hello, world!" }; } diff --git a/tests/ui/proc-macro/attr-invalid-exprs.stderr b/tests/ui/proc-macro/attr-invalid-exprs.stderr index f96939bb6ef..0d500c87145 100644 --- a/tests/ui/proc-macro/attr-invalid-exprs.stderr +++ b/tests/ui/proc-macro/attr-invalid-exprs.stderr @@ -4,7 +4,7 @@ error: expected expression, found end of macro arguments LL | let _ = #[no_output] "Hello, world!"; | ^^^^^^^^^^^^ -error: macro expansion ignores token `,` and any following +error: macro expansion ignores `,` and any tokens following --> $DIR/attr-invalid-exprs.rs:15:13 | LL | let _ = #[duplicate] "Hello, world!"; @@ -16,7 +16,7 @@ help: you might be missing a semicolon here LL | let _ = #[duplicate]; "Hello, world!"; | + -error: macro expansion ignores token `,` and any following +error: macro expansion ignores `,` and any tokens following --> $DIR/attr-invalid-exprs.rs:24:9 | LL | #[duplicate] diff --git a/tests/ui/proc-macro/expand-expr.rs b/tests/ui/proc-macro/expand-expr.rs index 5f7375d7450..e06ddc51a29 100644 --- a/tests/ui/proc-macro/expand-expr.rs +++ b/tests/ui/proc-macro/expand-expr.rs @@ -114,8 +114,8 @@ expand_expr_fail!(echo_pm!($)); //~ ERROR: expected expression, found `$` // We get errors reported and recover during macro expansion if the macro // doesn't produce a valid expression. -expand_expr_is!("string", echo_tts!("string"; hello)); //~ ERROR: macro expansion ignores token `hello` and any following -expand_expr_is!("string", echo_pm!("string"; hello)); //~ ERROR: macro expansion ignores token `;` and any following +expand_expr_is!("string", echo_tts!("string"; hello)); //~ ERROR: macro expansion ignores `hello` and any tokens following +expand_expr_is!("string", echo_pm!("string"; hello)); //~ ERROR: macro expansion ignores `;` and any tokens following // For now, fail if a non-literal expression is expanded. expand_expr_fail!(arbitrary_expression() + "etc"); diff --git a/tests/ui/proc-macro/expand-expr.stderr b/tests/ui/proc-macro/expand-expr.stderr index 2b92472e5ab..8b1df177cfa 100644 --- a/tests/ui/proc-macro/expand-expr.stderr +++ b/tests/ui/proc-macro/expand-expr.stderr @@ -22,7 +22,7 @@ error: expected expression, found `$` LL | expand_expr_fail!(echo_pm!($)); | ^ expected expression -error: macro expansion ignores token `hello` and any following +error: macro expansion ignores `hello` and any tokens following --> $DIR/expand-expr.rs:117:47 | LL | expand_expr_is!("string", echo_tts!("string"; hello)); @@ -34,7 +34,7 @@ help: you might be missing a semicolon here LL | expand_expr_is!("string", echo_tts!("string"; hello);); | + -error: macro expansion ignores token `;` and any following +error: macro expansion ignores `;` and any tokens following --> $DIR/expand-expr.rs:118:44 | LL | expand_expr_is!("string", echo_pm!("string"; hello)); diff --git a/tests/ui/range/range-1.stderr b/tests/ui/range/range-1.stderr index f98420557c6..f77601bc43c 100644 --- a/tests/ui/range/range-1.stderr +++ b/tests/ui/range/range-1.stderr @@ -8,7 +8,7 @@ error[E0277]: the trait bound `bool: Step` is not satisfied --> $DIR/range-1.rs:9:14 | LL | for i in false..true {} - | ^^^^^^^^^^^ the trait `Step` is not implemented for `bool`, which is required by `std::ops::Range<bool>: IntoIterator` + | ^^^^^^^^^^^ the trait `Step` is not implemented for `bool` | = help: the following other types implement trait `Step`: Char diff --git a/tests/ui/recursion/recursive-requirements.stderr b/tests/ui/recursion/recursive-requirements.stderr index f5cbed0ce34..bb63f7cd0dc 100644 --- a/tests/ui/recursion/recursive-requirements.stderr +++ b/tests/ui/recursion/recursive-requirements.stderr @@ -4,7 +4,7 @@ error[E0277]: `*const Bar` cannot be shared between threads safely LL | let _: AssertSync<Foo> = unimplemented!(); | ^^^^^^^^^^^^^^^ `*const Bar` cannot be shared between threads safely | - = help: within `Foo`, the trait `Sync` is not implemented for `*const Bar`, which is required by `Foo: Sync` + = help: within `Foo`, the trait `Sync` is not implemented for `*const Bar` note: required because it appears within the type `Foo` --> $DIR/recursive-requirements.rs:5:12 | @@ -22,7 +22,7 @@ error[E0277]: `*const Foo` cannot be shared between threads safely LL | let _: AssertSync<Foo> = unimplemented!(); | ^^^^^^^^^^^^^^^ `*const Foo` cannot be shared between threads safely | - = help: within `Foo`, the trait `Sync` is not implemented for `*const Foo`, which is required by `Foo: Sync` + = help: within `Foo`, the trait `Sync` is not implemented for `*const Foo` note: required because it appears within the type `Bar` --> $DIR/recursive-requirements.rs:10:12 | diff --git a/tests/ui/repr/repr_align_greater_usize.msp430.stderr b/tests/ui/repr/repr_align_greater_usize.msp430.stderr new file mode 100644 index 00000000000..7c85249c009 --- /dev/null +++ b/tests/ui/repr/repr_align_greater_usize.msp430.stderr @@ -0,0 +1,19 @@ +error[E0589]: alignment must not be greater than `isize::MAX` bytes + --> $DIR/repr_align_greater_usize.rs:21:8 + | +LL | #[repr(align(32768))] + | ^^^^^^^^^^^^ + | + = note: `isize::MAX` is 32767 for the current target + +error[E0589]: alignment must not be greater than `isize::MAX` bytes + --> $DIR/repr_align_greater_usize.rs:24:8 + | +LL | #[repr(align(65536))] + | ^^^^^^^^^^^^ + | + = note: `isize::MAX` is 32767 for the current target + +error: aborting due to 2 previous errors + +For more information about this error, try `rustc --explain E0589`. diff --git a/tests/ui/repr/repr_align_greater_usize.rs b/tests/ui/repr/repr_align_greater_usize.rs new file mode 100644 index 00000000000..b47320b6d9b --- /dev/null +++ b/tests/ui/repr/repr_align_greater_usize.rs @@ -0,0 +1,25 @@ +//@ revisions: msp430 aarch32 +//@[msp430] needs-llvm-components: msp430 +//@[msp430] compile-flags: --target=msp430-none-elf +//@[aarch32] build-pass +//@[aarch32] needs-llvm-components: arm +//@[aarch32] compile-flags: --target=thumbv7m-none-eabi + +// We should fail to compute alignment for types aligned higher than usize::MAX. +// We can't handle alignments that require all 32 bits, so this only affects 16-bit. + +#![feature(lang_items, no_core)] +#![no_core] +#![crate_type = "lib"] + +#[lang = "sized"] +trait Sized {} + +#[repr(align(16384))] +struct Kitten; + +#[repr(align(32768))] //[msp430]~ ERROR alignment must not be greater than `isize::MAX` +struct Cat; + +#[repr(align(65536))] //[msp430]~ ERROR alignment must not be greater than `isize::MAX` +struct BigCat; diff --git a/tests/ui/rfcs/rfc-1937-termination-trait/termination-trait-test-wrong-type.stderr b/tests/ui/rfcs/rfc-1937-termination-trait/termination-trait-test-wrong-type.stderr index 4d23922892e..0a703367d96 100644 --- a/tests/ui/rfcs/rfc-1937-termination-trait/termination-trait-test-wrong-type.stderr +++ b/tests/ui/rfcs/rfc-1937-termination-trait/termination-trait-test-wrong-type.stderr @@ -4,7 +4,7 @@ error[E0277]: the trait bound `f32: Termination` is not satisfied LL | #[test] | ------- in this procedural macro expansion LL | fn can_parse_zero_as_f32() -> Result<f32, ParseFloatError> { - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^ the trait `Termination` is not implemented for `f32`, which is required by `Result<f32, ParseFloatError>: Termination` + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^ the trait `Termination` is not implemented for `f32` | = note: required for `Result<f32, ParseFloatError>` to implement `Termination` note: required by a bound in `assert_test_result` diff --git a/tests/ui/rfcs/rfc-2294-if-let-guard/feature-gate.rs b/tests/ui/rfcs/rfc-2294-if-let-guard/feature-gate.rs index b8c0eb3e6d6..4b2fc4a03b6 100644 --- a/tests/ui/rfcs/rfc-2294-if-let-guard/feature-gate.rs +++ b/tests/ui/rfcs/rfc-2294-if-let-guard/feature-gate.rs @@ -68,7 +68,7 @@ fn _macros() { _ => {} } use_expr!(let 0 = 1); - //~^ ERROR no rules expected the token `let` + //~^ ERROR no rules expected keyword `let` } fn main() {} diff --git a/tests/ui/rfcs/rfc-2294-if-let-guard/feature-gate.stderr b/tests/ui/rfcs/rfc-2294-if-let-guard/feature-gate.stderr index 2341dbbbdbd..1c710b04897 100644 --- a/tests/ui/rfcs/rfc-2294-if-let-guard/feature-gate.stderr +++ b/tests/ui/rfcs/rfc-2294-if-let-guard/feature-gate.stderr @@ -131,7 +131,7 @@ LL | use_expr!((let 0 = 1)); | = note: only supported directly in conditions of `if` and `while` expressions -error: no rules expected the token `let` +error: no rules expected keyword `let` --> $DIR/feature-gate.rs:70:15 | LL | macro_rules! use_expr { diff --git a/tests/ui/rfcs/rfc-2361-dbg-macro/dbg-macro-requires-debug.stderr b/tests/ui/rfcs/rfc-2361-dbg-macro/dbg-macro-requires-debug.stderr index eb6abbf8045..7ec018a95cc 100644 --- a/tests/ui/rfcs/rfc-2361-dbg-macro/dbg-macro-requires-debug.stderr +++ b/tests/ui/rfcs/rfc-2361-dbg-macro/dbg-macro-requires-debug.stderr @@ -4,7 +4,7 @@ error[E0277]: `NotDebug` doesn't implement `Debug` LL | let _: NotDebug = dbg!(NotDebug); | ^^^^^^^^^^^^^^ `NotDebug` cannot be formatted using `{:?}` | - = help: the trait `Debug` is not implemented for `NotDebug`, which is required by `&NotDebug: Debug` + = help: the trait `Debug` is not implemented for `NotDebug` = note: add `#[derive(Debug)]` to `NotDebug` or manually `impl Debug for NotDebug` = note: this error originates in the macro `$crate::format_args_nl` which comes from the expansion of the macro `dbg` (in Nightly builds, run with -Z macro-backtrace for more info) help: consider annotating `NotDebug` with `#[derive(Debug)]` diff --git a/tests/ui/rfcs/rfc-2497-if-let-chains/feature-gate.rs b/tests/ui/rfcs/rfc-2497-if-let-chains/feature-gate.rs index bca7564efd8..2087fc42cf1 100644 --- a/tests/ui/rfcs/rfc-2497-if-let-chains/feature-gate.rs +++ b/tests/ui/rfcs/rfc-2497-if-let-chains/feature-gate.rs @@ -54,7 +54,7 @@ fn _macros() { #[cfg(FALSE)] (let 0 = 1); //~^ ERROR expected expression, found `let` statement use_expr!(let 0 = 1); - //~^ ERROR no rules expected the token `let` + //~^ ERROR no rules expected keyword `let` } fn main() {} diff --git a/tests/ui/rfcs/rfc-2497-if-let-chains/feature-gate.stderr b/tests/ui/rfcs/rfc-2497-if-let-chains/feature-gate.stderr index 2b1a49be3da..7c874ae78a8 100644 --- a/tests/ui/rfcs/rfc-2497-if-let-chains/feature-gate.stderr +++ b/tests/ui/rfcs/rfc-2497-if-let-chains/feature-gate.stderr @@ -14,7 +14,7 @@ LL | noop_expr!((let 0 = 1)); | = note: only supported directly in conditions of `if` and `while` expressions -error: no rules expected the token `let` +error: no rules expected keyword `let` --> $DIR/feature-gate.rs:56:15 | LL | macro_rules! use_expr { diff --git a/tests/ui/rfcs/rfc-2497-if-let-chains/irrefutable-lets.disallowed.stderr b/tests/ui/rfcs/rfc-2497-if-let-chains/irrefutable-lets.disallowed.stderr index be4a5231558..130d0296c5e 100644 --- a/tests/ui/rfcs/rfc-2497-if-let-chains/irrefutable-lets.disallowed.stderr +++ b/tests/ui/rfcs/rfc-2497-if-let-chains/irrefutable-lets.disallowed.stderr @@ -111,5 +111,23 @@ LL | while let Some(ref first) = opt && let second = first && let _third = s = note: these patterns will always match = help: consider moving them into the body -error: aborting due to 12 previous errors +error: trailing irrefutable pattern in let chain + --> $DIR/irrefutable-lets.rs:87:12 + | +LL | && let x = &opt + | ^^^^^^^^^^^^ + | + = note: this pattern will always match + = help: consider moving it into the body + +error: leading irrefutable pattern in let chain + --> $DIR/irrefutable-lets.rs:93:12 + | +LL | if let x = opt.clone().map(|_| 1) + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + | + = note: this pattern will always match + = help: consider moving it outside of the construct + +error: aborting due to 14 previous errors diff --git a/tests/ui/rfcs/rfc-2497-if-let-chains/irrefutable-lets.rs b/tests/ui/rfcs/rfc-2497-if-let-chains/irrefutable-lets.rs index bd4df337614..e7d69f89773 100644 --- a/tests/ui/rfcs/rfc-2497-if-let-chains/irrefutable-lets.rs +++ b/tests/ui/rfcs/rfc-2497-if-let-chains/irrefutable-lets.rs @@ -75,4 +75,24 @@ fn main() { && let Range { start: local_start, end: _ } = first && let None = local_start { } + + // No error. An extra nesting level would be required for the `else if`. + if opt == Some(None..None) { + } else if let x = opt.clone().map(|_| 1) + && x == Some(1) + {} + + if opt == Some(None..None) { + } else if opt.is_some() + && let x = &opt + //[disallowed]~^ ERROR trailing irrefutable pattern in let chain + {} + + if opt == Some(None..None) { + } else { + if let x = opt.clone().map(|_| 1) + //[disallowed]~^ ERROR leading irrefutable pattern in let chain + && x == Some(1) + {} + } } diff --git a/tests/ui/self/arbitrary-self-from-method-substs-ice.rs b/tests/ui/self/arbitrary-self-from-method-substs-ice.rs index a544c8ea0d1..d121a194be6 100644 --- a/tests/ui/self/arbitrary-self-from-method-substs-ice.rs +++ b/tests/ui/self/arbitrary-self-from-method-substs-ice.rs @@ -8,7 +8,7 @@ use std::ops::Deref; struct Foo(u32); impl Foo { const fn get<R: Deref<Target = Self>>(self: R) -> u32 { - //~^ ERROR: `R` cannot be used as the type of `self` + //~^ ERROR invalid generic `self` parameter type //~| ERROR destructor of `R` cannot be evaluated at compile-time self.0 //~^ ERROR cannot call non-const fn `<R as Deref>::deref` in constant function diff --git a/tests/ui/self/arbitrary-self-from-method-substs-ice.stderr b/tests/ui/self/arbitrary-self-from-method-substs-ice.stderr index 6ae60e7af47..7252b5890fd 100644 --- a/tests/ui/self/arbitrary-self-from-method-substs-ice.stderr +++ b/tests/ui/self/arbitrary-self-from-method-substs-ice.stderr @@ -15,18 +15,16 @@ LL | const fn get<R: Deref<Target = Self>>(self: R) -> u32 { LL | } | - value is dropped here -error[E0658]: `R` cannot be used as the type of `self` without the `arbitrary_self_types` feature +error[E0801]: invalid generic `self` parameter type: `R` --> $DIR/arbitrary-self-from-method-substs-ice.rs:10:49 | LL | const fn get<R: Deref<Target = Self>>(self: R) -> u32 { | ^ | - = note: see issue #44874 <https://github.com/rust-lang/rust/issues/44874> for more information - = help: add `#![feature(arbitrary_self_types)]` to the crate attributes to enable - = note: this compiler was built on YYYY-MM-DD; consider upgrading it if it is out of date - = help: consider changing to `self`, `&self`, `&mut self`, `self: Box<Self>`, `self: Rc<Self>`, `self: Arc<Self>`, or `self: Pin<P>` (where P is one of the previous types except `Self`) + = note: type of `self` must not be a method generic parameter type + = help: use a concrete type such as `self`, `&self`, `&mut self`, `self: Box<Self>`, `self: Rc<Self>`, `self: Arc<Self>`, or `self: Pin<P>` (where P is one of the previous types except `Self`) error: aborting due to 3 previous errors -Some errors have detailed explanations: E0015, E0493, E0658. +Some errors have detailed explanations: E0015, E0493, E0801. For more information about an error, try `rustc --explain E0015`. diff --git a/tests/ui/self/arbitrary-self-from-method-substs.default.stderr b/tests/ui/self/arbitrary-self-from-method-substs.default.stderr index 4cc69666b88..5dc3a0b0234 100644 --- a/tests/ui/self/arbitrary-self-from-method-substs.default.stderr +++ b/tests/ui/self/arbitrary-self-from-method-substs.default.stderr @@ -1,14 +1,168 @@ -error[E0658]: `R` cannot be used as the type of `self` without the `arbitrary_self_types` feature - --> $DIR/arbitrary-self-from-method-substs.rs:8:43 +error[E0801]: invalid generic `self` parameter type: `R` + --> $DIR/arbitrary-self-from-method-substs.rs:9:43 | LL | fn get<R: Deref<Target = Self>>(self: R) -> u32 { | ^ | + = note: type of `self` must not be a method generic parameter type + = help: use a concrete type such as `self`, `&self`, `&mut self`, `self: Box<Self>`, `self: Rc<Self>`, `self: Arc<Self>`, or `self: Pin<P>` (where P is one of the previous types except `Self`) + +error[E0801]: invalid generic `self` parameter type: `&R` + --> $DIR/arbitrary-self-from-method-substs.rs:13:44 + | +LL | fn get1<R: Deref<Target = Self>>(self: &R) -> u32 { + | ^^ + | + = note: type of `self` must not be a method generic parameter type + = help: use a concrete type such as `self`, `&self`, `&mut self`, `self: Box<Self>`, `self: Rc<Self>`, `self: Arc<Self>`, or `self: Pin<P>` (where P is one of the previous types except `Self`) + +error[E0801]: invalid generic `self` parameter type: `&mut R` + --> $DIR/arbitrary-self-from-method-substs.rs:17:44 + | +LL | fn get2<R: Deref<Target = Self>>(self: &mut R) -> u32 { + | ^^^^^^ + | + = note: type of `self` must not be a method generic parameter type + = help: use a concrete type such as `self`, `&self`, `&mut self`, `self: Box<Self>`, `self: Rc<Self>`, `self: Arc<Self>`, or `self: Pin<P>` (where P is one of the previous types except `Self`) + +error[E0801]: invalid generic `self` parameter type: `Rc<R>` + --> $DIR/arbitrary-self-from-method-substs.rs:21:44 + | +LL | fn get3<R: Deref<Target = Self>>(self: std::rc::Rc<R>) -> u32 { + | ^^^^^^^^^^^^^^ + | + = note: type of `self` must not be a method generic parameter type + = help: use a concrete type such as `self`, `&self`, `&mut self`, `self: Box<Self>`, `self: Rc<Self>`, `self: Arc<Self>`, or `self: Pin<P>` (where P is one of the previous types except `Self`) + +error[E0801]: invalid generic `self` parameter type: `&Rc<R>` + --> $DIR/arbitrary-self-from-method-substs.rs:25:44 + | +LL | fn get4<R: Deref<Target = Self>>(self: &std::rc::Rc<R>) -> u32 { + | ^^^^^^^^^^^^^^^ + | + = note: type of `self` must not be a method generic parameter type + = help: use a concrete type such as `self`, `&self`, `&mut self`, `self: Box<Self>`, `self: Rc<Self>`, `self: Arc<Self>`, or `self: Pin<P>` (where P is one of the previous types except `Self`) + +error[E0801]: invalid generic `self` parameter type: `Rc<&R>` + --> $DIR/arbitrary-self-from-method-substs.rs:29:44 + | +LL | fn get5<R: Deref<Target = Self>>(self: std::rc::Rc<&R>) -> u32 { + | ^^^^^^^^^^^^^^^ + | + = note: type of `self` must not be a method generic parameter type + = help: use a concrete type such as `self`, `&self`, `&mut self`, `self: Box<Self>`, `self: Rc<Self>`, `self: Arc<Self>`, or `self: Pin<P>` (where P is one of the previous types except `Self`) + +error[E0658]: `<FR as FindReceiver>::Receiver` cannot be used as the type of `self` without the `arbitrary_self_types` feature + --> $DIR/arbitrary-self-from-method-substs.rs:33:37 + | +LL | fn get6<FR: FindReceiver>(self: FR::Receiver, other: FR) -> u32 { + | ^^^^^^^^^^^^ + | = note: see issue #44874 <https://github.com/rust-lang/rust/issues/44874> for more information = help: add `#![feature(arbitrary_self_types)]` to the crate attributes to enable = note: this compiler was built on YYYY-MM-DD; consider upgrading it if it is out of date = help: consider changing to `self`, `&self`, `&mut self`, `self: Box<Self>`, `self: Rc<Self>`, `self: Arc<Self>`, or `self: Pin<P>` (where P is one of the previous types except `Self`) -error: aborting due to 1 previous error +error[E0658]: `R` cannot be used as the type of `self` without the `arbitrary_self_types` feature + --> $DIR/arbitrary-self-from-method-substs.rs:61:18 + | +LL | fn get(self: R) {} + | ^ + | + = note: see issue #44874 <https://github.com/rust-lang/rust/issues/44874> for more information + = help: add `#![feature(arbitrary_self_types)]` to the crate attributes to enable + = note: this compiler was built on YYYY-MM-DD; consider upgrading it if it is out of date + = help: consider changing to `self`, `&self`, `&mut self`, `self: Box<Self>`, `self: Rc<Self>`, `self: Arc<Self>`, or `self: Pin<P>` (where P is one of the previous types except `Self`) + +error[E0271]: type mismatch resolving `<Silly as FindReceiver>::Receiver == Foo` + --> $DIR/arbitrary-self-from-method-substs.rs:92:9 + | +LL | foo.get6(Silly); + | ^^^^ type mismatch resolving `<Silly as FindReceiver>::Receiver == Foo` + | +note: expected this to be `Foo` + --> $DIR/arbitrary-self-from-method-substs.rs:71:21 + | +LL | type Receiver = std::rc::Rc<Foo>; + | ^^^^^^^^^^^^^^^^ + = note: expected struct `Foo` + found struct `Rc<Foo>` + +error[E0271]: type mismatch resolving `<Silly as FindReceiver>::Receiver == &Foo` + --> $DIR/arbitrary-self-from-method-substs.rs:96:9 + | +LL | foo.get6(Silly); + | ^^^^ type mismatch resolving `<Silly as FindReceiver>::Receiver == &Foo` + | +note: expected this to be `&Foo` + --> $DIR/arbitrary-self-from-method-substs.rs:71:21 + | +LL | type Receiver = std::rc::Rc<Foo>; + | ^^^^^^^^^^^^^^^^ + = note: expected reference `&Foo` + found struct `Rc<Foo>` + +error[E0599]: the method `get` exists for struct `Rc<Bar<_>>`, but its trait bounds were not satisfied + --> $DIR/arbitrary-self-from-method-substs.rs:100:7 + | +LL | struct Bar<R>(std::marker::PhantomData<R>); + | ------------- doesn't satisfy `Bar<_>: Deref` +... +LL | t.get(); + | ^^^ method cannot be called on `Rc<Bar<_>>` due to unsatisfied trait bounds + | +note: the following trait bounds were not satisfied: + `<&Bar<_> as Deref>::Target = Bar<&Bar<_>>` + `<&Rc<Bar<_>> as Deref>::Target = Bar<&Rc<Bar<_>>>` + `<&mut Bar<_> as Deref>::Target = Bar<&mut Bar<_>>` + `<&mut Rc<Bar<_>> as Deref>::Target = Bar<&mut Rc<Bar<_>>>` + `<Rc<Bar<_>> as Deref>::Target = Bar<Rc<Bar<_>>>` + `Bar<_>: Deref` + --> $DIR/arbitrary-self-from-method-substs.rs:60:9 + | +LL | impl<R: std::ops::Deref<Target = Self>> Bar<R> { + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ ------ + | | | + | | unsatisfied trait bound introduced here + | unsatisfied trait bound introduced here +note: the trait `Deref` must be implemented + --> $SRC_DIR/core/src/ops/deref.rs:LL:COL + = help: items from traits can only be used if the trait is implemented and in scope + = note: the following trait defines an item `get`, perhaps you need to implement it: + candidate #1: `SliceIndex` + +error[E0599]: the method `get` exists for reference `&Rc<Bar<_>>`, but its trait bounds were not satisfied + --> $DIR/arbitrary-self-from-method-substs.rs:108:7 + | +LL | struct Bar<R>(std::marker::PhantomData<R>); + | ------------- doesn't satisfy `Bar<_>: Deref` +... +LL | t.get(); + | ^^^ method cannot be called on `&Rc<Bar<_>>` due to unsatisfied trait bounds + | +note: the following trait bounds were not satisfied: + `<&&Rc<Bar<_>> as Deref>::Target = Bar<&&Rc<Bar<_>>>` + `<&Bar<_> as Deref>::Target = Bar<&Bar<_>>` + `<&Rc<Bar<_>> as Deref>::Target = Bar<&Rc<Bar<_>>>` + `<&mut &Rc<Bar<_>> as Deref>::Target = Bar<&mut &Rc<Bar<_>>>` + `<&mut Bar<_> as Deref>::Target = Bar<&mut Bar<_>>` + `<&mut Rc<Bar<_>> as Deref>::Target = Bar<&mut Rc<Bar<_>>>` + `<Rc<Bar<_>> as Deref>::Target = Bar<Rc<Bar<_>>>` + `Bar<_>: Deref` + --> $DIR/arbitrary-self-from-method-substs.rs:60:9 + | +LL | impl<R: std::ops::Deref<Target = Self>> Bar<R> { + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ ------ + | | | + | | unsatisfied trait bound introduced here + | unsatisfied trait bound introduced here +note: the trait `Deref` must be implemented + --> $SRC_DIR/core/src/ops/deref.rs:LL:COL + = help: items from traits can only be used if the trait is implemented and in scope + = note: the following trait defines an item `get`, perhaps you need to implement it: + candidate #1: `SliceIndex` + +error: aborting due to 12 previous errors -For more information about this error, try `rustc --explain E0658`. +Some errors have detailed explanations: E0271, E0599, E0658, E0801. +For more information about an error, try `rustc --explain E0271`. diff --git a/tests/ui/self/arbitrary-self-from-method-substs.feature.stderr b/tests/ui/self/arbitrary-self-from-method-substs.feature.stderr index 44e553f1a06..6e864f44aa3 100644 --- a/tests/ui/self/arbitrary-self-from-method-substs.feature.stderr +++ b/tests/ui/self/arbitrary-self-from-method-substs.feature.stderr @@ -1,9 +1,179 @@ +error[E0801]: invalid generic `self` parameter type: `R` + --> $DIR/arbitrary-self-from-method-substs.rs:9:43 + | +LL | fn get<R: Deref<Target = Self>>(self: R) -> u32 { + | ^ + | + = note: type of `self` must not be a method generic parameter type + = help: use a concrete type such as `self`, `&self`, `&mut self`, `self: Box<Self>`, `self: Rc<Self>`, `self: Arc<Self>`, or `self: Pin<P>` (where P is one of the previous types except `Self`) + +error[E0801]: invalid generic `self` parameter type: `&R` + --> $DIR/arbitrary-self-from-method-substs.rs:13:44 + | +LL | fn get1<R: Deref<Target = Self>>(self: &R) -> u32 { + | ^^ + | + = note: type of `self` must not be a method generic parameter type + = help: use a concrete type such as `self`, `&self`, `&mut self`, `self: Box<Self>`, `self: Rc<Self>`, `self: Arc<Self>`, or `self: Pin<P>` (where P is one of the previous types except `Self`) + +error[E0801]: invalid generic `self` parameter type: `&mut R` + --> $DIR/arbitrary-self-from-method-substs.rs:17:44 + | +LL | fn get2<R: Deref<Target = Self>>(self: &mut R) -> u32 { + | ^^^^^^ + | + = note: type of `self` must not be a method generic parameter type + = help: use a concrete type such as `self`, `&self`, `&mut self`, `self: Box<Self>`, `self: Rc<Self>`, `self: Arc<Self>`, or `self: Pin<P>` (where P is one of the previous types except `Self`) + +error[E0801]: invalid generic `self` parameter type: `Rc<R>` + --> $DIR/arbitrary-self-from-method-substs.rs:21:44 + | +LL | fn get3<R: Deref<Target = Self>>(self: std::rc::Rc<R>) -> u32 { + | ^^^^^^^^^^^^^^ + | + = note: type of `self` must not be a method generic parameter type + = help: use a concrete type such as `self`, `&self`, `&mut self`, `self: Box<Self>`, `self: Rc<Self>`, `self: Arc<Self>`, or `self: Pin<P>` (where P is one of the previous types except `Self`) + +error[E0801]: invalid generic `self` parameter type: `&Rc<R>` + --> $DIR/arbitrary-self-from-method-substs.rs:25:44 + | +LL | fn get4<R: Deref<Target = Self>>(self: &std::rc::Rc<R>) -> u32 { + | ^^^^^^^^^^^^^^^ + | + = note: type of `self` must not be a method generic parameter type + = help: use a concrete type such as `self`, `&self`, `&mut self`, `self: Box<Self>`, `self: Rc<Self>`, `self: Arc<Self>`, or `self: Pin<P>` (where P is one of the previous types except `Self`) + +error[E0801]: invalid generic `self` parameter type: `Rc<&R>` + --> $DIR/arbitrary-self-from-method-substs.rs:29:44 + | +LL | fn get5<R: Deref<Target = Self>>(self: std::rc::Rc<&R>) -> u32 { + | ^^^^^^^^^^^^^^^ + | + = note: type of `self` must not be a method generic parameter type + = help: use a concrete type such as `self`, `&self`, `&mut self`, `self: Box<Self>`, `self: Rc<Self>`, `self: Arc<Self>`, or `self: Pin<P>` (where P is one of the previous types except `Self`) + error[E0308]: mismatched types - --> $DIR/arbitrary-self-from-method-substs.rs:16:5 + --> $DIR/arbitrary-self-from-method-substs.rs:76:5 | LL | foo.get::<&Foo>(); | ^^^ expected `&Foo`, found `Foo` -error: aborting due to 1 previous error +error[E0308]: mismatched types + --> $DIR/arbitrary-self-from-method-substs.rs:78:5 + | +LL | foo.get::<std::rc::Rc<Foo>>(); + | ^^^ expected `Rc<Foo>`, found `Foo` + | + = note: expected struct `Rc<Foo>` + found struct `Foo` + +error[E0308]: mismatched types + --> $DIR/arbitrary-self-from-method-substs.rs:84:5 + | +LL | smart_ptr.get::<SmartPtr2<Foo>>(); + | ^^^^^^^^^ expected `SmartPtr2<'_, Foo>`, found `SmartPtr<'_, Foo>` + | + = note: expected struct `SmartPtr2<'_, Foo>` + found struct `SmartPtr<'_, Foo>` + +error[E0308]: mismatched types + --> $DIR/arbitrary-self-from-method-substs.rs:86:5 + | +LL | smart_ptr.get::<&Foo>(); + | ^^^^^^^^^ expected `&Foo`, found `SmartPtr<'_, Foo>` + | + = note: expected reference `&Foo` + found struct `SmartPtr<'_, Foo, >` + +error[E0271]: type mismatch resolving `<Silly as FindReceiver>::Receiver == Foo` + --> $DIR/arbitrary-self-from-method-substs.rs:92:9 + | +LL | foo.get6(Silly); + | ^^^^ type mismatch resolving `<Silly as FindReceiver>::Receiver == Foo` + | +note: expected this to be `Foo` + --> $DIR/arbitrary-self-from-method-substs.rs:71:21 + | +LL | type Receiver = std::rc::Rc<Foo>; + | ^^^^^^^^^^^^^^^^ + = note: expected struct `Foo` + found struct `Rc<Foo>` + +error[E0271]: type mismatch resolving `<Silly as FindReceiver>::Receiver == &Foo` + --> $DIR/arbitrary-self-from-method-substs.rs:96:9 + | +LL | foo.get6(Silly); + | ^^^^ type mismatch resolving `<Silly as FindReceiver>::Receiver == &Foo` + | +note: expected this to be `&Foo` + --> $DIR/arbitrary-self-from-method-substs.rs:71:21 + | +LL | type Receiver = std::rc::Rc<Foo>; + | ^^^^^^^^^^^^^^^^ + = note: expected reference `&Foo` + found struct `Rc<Foo>` + +error[E0599]: the method `get` exists for struct `Rc<Bar<_>>`, but its trait bounds were not satisfied + --> $DIR/arbitrary-self-from-method-substs.rs:100:7 + | +LL | struct Bar<R>(std::marker::PhantomData<R>); + | ------------- doesn't satisfy `Bar<_>: Deref` +... +LL | t.get(); + | ^^^ method cannot be called on `Rc<Bar<_>>` due to unsatisfied trait bounds + | +note: the following trait bounds were not satisfied: + `<&Bar<_> as Deref>::Target = Bar<&Bar<_>>` + `<&Rc<Bar<_>> as Deref>::Target = Bar<&Rc<Bar<_>>>` + `<&mut Bar<_> as Deref>::Target = Bar<&mut Bar<_>>` + `<&mut Rc<Bar<_>> as Deref>::Target = Bar<&mut Rc<Bar<_>>>` + `<Rc<Bar<_>> as Deref>::Target = Bar<Rc<Bar<_>>>` + `Bar<_>: Deref` + --> $DIR/arbitrary-self-from-method-substs.rs:60:9 + | +LL | impl<R: std::ops::Deref<Target = Self>> Bar<R> { + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ ------ + | | | + | | unsatisfied trait bound introduced here + | unsatisfied trait bound introduced here +note: the trait `Deref` must be implemented + --> $SRC_DIR/core/src/ops/deref.rs:LL:COL + = help: items from traits can only be used if the trait is implemented and in scope + = note: the following trait defines an item `get`, perhaps you need to implement it: + candidate #1: `SliceIndex` + +error[E0599]: the method `get` exists for reference `&Rc<Bar<_>>`, but its trait bounds were not satisfied + --> $DIR/arbitrary-self-from-method-substs.rs:108:7 + | +LL | struct Bar<R>(std::marker::PhantomData<R>); + | ------------- doesn't satisfy `Bar<_>: Deref` +... +LL | t.get(); + | ^^^ method cannot be called on `&Rc<Bar<_>>` due to unsatisfied trait bounds + | +note: the following trait bounds were not satisfied: + `<&&Rc<Bar<_>> as Deref>::Target = Bar<&&Rc<Bar<_>>>` + `<&Bar<_> as Deref>::Target = Bar<&Bar<_>>` + `<&Rc<Bar<_>> as Deref>::Target = Bar<&Rc<Bar<_>>>` + `<&mut &Rc<Bar<_>> as Deref>::Target = Bar<&mut &Rc<Bar<_>>>` + `<&mut Bar<_> as Deref>::Target = Bar<&mut Bar<_>>` + `<&mut Rc<Bar<_>> as Deref>::Target = Bar<&mut Rc<Bar<_>>>` + `<Rc<Bar<_>> as Deref>::Target = Bar<Rc<Bar<_>>>` + `Bar<_>: Deref` + --> $DIR/arbitrary-self-from-method-substs.rs:60:9 + | +LL | impl<R: std::ops::Deref<Target = Self>> Bar<R> { + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ ------ + | | | + | | unsatisfied trait bound introduced here + | unsatisfied trait bound introduced here +note: the trait `Deref` must be implemented + --> $SRC_DIR/core/src/ops/deref.rs:LL:COL + = help: items from traits can only be used if the trait is implemented and in scope + = note: the following trait defines an item `get`, perhaps you need to implement it: + candidate #1: `SliceIndex` + +error: aborting due to 14 previous errors -For more information about this error, try `rustc --explain E0308`. +Some errors have detailed explanations: E0271, E0308, E0599, E0801. +For more information about an error, try `rustc --explain E0271`. diff --git a/tests/ui/self/arbitrary-self-from-method-substs.rs b/tests/ui/self/arbitrary-self-from-method-substs.rs index 99977ed9b8c..f2d65859615 100644 --- a/tests/ui/self/arbitrary-self-from-method-substs.rs +++ b/tests/ui/self/arbitrary-self-from-method-substs.rs @@ -2,17 +2,109 @@ #![cfg_attr(feature, feature(arbitrary_self_types))] use std::ops::Deref; +use std::marker::PhantomData; struct Foo(u32); impl Foo { fn get<R: Deref<Target = Self>>(self: R) -> u32 { - //[default]~^ ERROR: `R` cannot be used as the type of `self` + //~^ ERROR: invalid generic `self` parameter type self.0 } + fn get1<R: Deref<Target = Self>>(self: &R) -> u32 { + //~^ ERROR: invalid generic `self` parameter type + self.0 + } + fn get2<R: Deref<Target = Self>>(self: &mut R) -> u32 { + //~^ ERROR: invalid generic `self` parameter type + self.0 + } + fn get3<R: Deref<Target = Self>>(self: std::rc::Rc<R>) -> u32 { + //~^ ERROR: invalid generic `self` parameter type + self.0 + } + fn get4<R: Deref<Target = Self>>(self: &std::rc::Rc<R>) -> u32 { + //~^ ERROR: invalid generic `self` parameter type + self.0 + } + fn get5<R: Deref<Target = Self>>(self: std::rc::Rc<&R>) -> u32 { + //~^ ERROR: invalid generic `self` parameter type + self.0 + } + fn get6<FR: FindReceiver>(self: FR::Receiver, other: FR) -> u32 { + //[default]~^ ERROR: `<FR as FindReceiver>::Receiver` cannot be used as the type of `self` + 42 + } +} + + +struct SmartPtr<'a, T: ?Sized>(&'a T); + +impl<'a, T: ?Sized> Deref for SmartPtr<'a, T> { + type Target = T; + fn deref(&self) -> &Self::Target { + unimplemented!() + } +} + +struct SmartPtr2<'a, T: ?Sized>(&'a T); + +impl<'a, T: ?Sized> Deref for SmartPtr2<'a, T> { + type Target = T; + fn deref(&self) -> &Self::Target { + unimplemented!() + } +} + +struct Bar<R>(std::marker::PhantomData<R>); + +impl<R: std::ops::Deref<Target = Self>> Bar<R> { + fn get(self: R) {} + //[default]~^ ERROR: `R` cannot be used as the type of `self` +} + +trait FindReceiver { + type Receiver: Deref<Target = Foo>; +} + +struct Silly; +impl FindReceiver for Silly { + type Receiver = std::rc::Rc<Foo>; } fn main() { let mut foo = Foo(1); foo.get::<&Foo>(); //[feature]~^ ERROR mismatched types + foo.get::<std::rc::Rc<Foo>>(); + //[feature]~^ ERROR mismatched types + + let smart_ptr = SmartPtr(&foo); + let smart_ptr2 = SmartPtr2(&foo); + smart_ptr.get(); // this compiles + smart_ptr.get::<SmartPtr2<Foo>>(); + //[feature]~^ ERROR mismatched types + smart_ptr.get::<&Foo>(); + //[feature]~^ ERROR mismatched types + + let mut foo = Foo(1); + // This test is slightly contrived in an attempt to generate a mismatched types + // error for the self type below, without using the turbofish. + foo.get6(Silly); + //~^ ERROR type mismatch + let mut foo = Foo(1); + let foo = &foo; + foo.get6(Silly); + //~^ ERROR type mismatch + + let t = std::rc::Rc::new(Bar(std::marker::PhantomData)); + t.get(); + //~^ ERROR its trait bounds were not satisfied + let t = &t; + // This is a further attempt at triggering 'type mismatch' errors + // from arbitrary self types without resorting to the turbofish. + // Ideally, here, t is Thing<Rc<Target=Self>> while we're going to call + // it with a &t method receiver. However, this doesn't work since that + // type of t becomes recursive and trait bounds can't be satisfied. + t.get(); + //~^ ERROR its trait bounds were not satisfied } diff --git a/tests/ui/specialization/const_trait_impl.stderr b/tests/ui/specialization/const_trait_impl.stderr index 746b08fa710..40ac350980e 100644 --- a/tests/ui/specialization/const_trait_impl.stderr +++ b/tests/ui/specialization/const_trait_impl.stderr @@ -1,42 +1,42 @@ error: `~const` can only be applied to `#[const_trait]` traits - --> $DIR/const_trait_impl.rs:34:16 + --> $DIR/const_trait_impl.rs:34:9 | LL | impl<T: ~const Default> const A for T { - | ^^^^^^^ + | ^^^^^^ error: `~const` can only be applied to `#[const_trait]` traits - --> $DIR/const_trait_impl.rs:40:16 + --> $DIR/const_trait_impl.rs:40:9 | LL | impl<T: ~const Default + ~const Sup> const A for T { - | ^^^^^^^ + | ^^^^^^ error: `~const` can only be applied to `#[const_trait]` traits - --> $DIR/const_trait_impl.rs:46:16 + --> $DIR/const_trait_impl.rs:46:9 | LL | impl<T: ~const Default + ~const Sub> const A for T { - | ^^^^^^^ + | ^^^^^^ error: `~const` can only be applied to `#[const_trait]` traits - --> $DIR/const_trait_impl.rs:40:16 + --> $DIR/const_trait_impl.rs:40:9 | LL | impl<T: ~const Default + ~const Sup> const A for T { - | ^^^^^^^ + | ^^^^^^ | = note: duplicate diagnostic emitted due to `-Z deduplicate-diagnostics=no` error: `~const` can only be applied to `#[const_trait]` traits - --> $DIR/const_trait_impl.rs:34:16 + --> $DIR/const_trait_impl.rs:34:9 | LL | impl<T: ~const Default> const A for T { - | ^^^^^^^ + | ^^^^^^ | = note: duplicate diagnostic emitted due to `-Z deduplicate-diagnostics=no` error: `~const` can only be applied to `#[const_trait]` traits - --> $DIR/const_trait_impl.rs:46:16 + --> $DIR/const_trait_impl.rs:46:9 | LL | impl<T: ~const Default + ~const Sub> const A for T { - | ^^^^^^^ + | ^^^^^^ | = note: duplicate diagnostic emitted due to `-Z deduplicate-diagnostics=no` diff --git a/tests/ui/specialization/min_specialization/issue-79224.stderr b/tests/ui/specialization/min_specialization/issue-79224.stderr index db88be88a81..268fc3a9591 100644 --- a/tests/ui/specialization/min_specialization/issue-79224.stderr +++ b/tests/ui/specialization/min_specialization/issue-79224.stderr @@ -2,7 +2,7 @@ error[E0277]: the trait bound `B: Clone` is not satisfied --> $DIR/issue-79224.rs:18:29 | LL | impl<B: ?Sized> Display for Cow<'_, B> { - | ^^^^^^^^^^ the trait `Clone` is not implemented for `B`, which is required by `B: ToOwned` + | ^^^^^^^^^^ the trait `Clone` is not implemented for `B` | = note: required for `B` to implement `ToOwned` help: consider further restricting this bound @@ -14,7 +14,7 @@ error[E0277]: the trait bound `B: Clone` is not satisfied --> $DIR/issue-79224.rs:20:5 | LL | fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ the trait `Clone` is not implemented for `B`, which is required by `B: ToOwned` + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ the trait `Clone` is not implemented for `B` | = note: required for `B` to implement `ToOwned` help: consider further restricting this bound @@ -26,7 +26,7 @@ error[E0277]: the trait bound `B: Clone` is not satisfied --> $DIR/issue-79224.rs:20:13 | LL | fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { - | ^^^^ the trait `Clone` is not implemented for `B`, which is required by `B: ToOwned` + | ^^^^ the trait `Clone` is not implemented for `B` | = note: required for `B` to implement `ToOwned` help: consider further restricting this bound @@ -44,7 +44,7 @@ LL | | LL | | LL | | write!(f, "foo") LL | | } - | |_____^ the trait `Clone` is not implemented for `B`, which is required by `B: ToOwned` + | |_____^ the trait `Clone` is not implemented for `B` | = note: required for `B` to implement `ToOwned` help: consider further restricting this bound diff --git a/tests/ui/statics/unsized_type2.stderr b/tests/ui/statics/unsized_type2.stderr index 4e47b37afdc..b18a99fab72 100644 --- a/tests/ui/statics/unsized_type2.stderr +++ b/tests/ui/statics/unsized_type2.stderr @@ -4,7 +4,7 @@ error[E0277]: the size for values of type `str` cannot be known at compilation t LL | pub static WITH_ERROR: Foo = Foo { version: 0 }; | ^^^ doesn't have a size known at compile-time | - = help: within `Foo`, the trait `Sized` is not implemented for `str`, which is required by `Foo: Sized` + = help: within `Foo`, the trait `Sized` is not implemented for `str` note: required because it appears within the type `Foo` --> $DIR/unsized_type2.rs:5:12 | @@ -17,7 +17,7 @@ error[E0277]: the size for values of type `str` cannot be known at compilation t LL | pub static WITH_ERROR: Foo = Foo { version: 0 }; | ^^^^^^^^^^^^^^^^^^ doesn't have a size known at compile-time | - = help: within `Foo`, the trait `Sized` is not implemented for `str`, which is required by `Foo: Sized` + = help: within `Foo`, the trait `Sized` is not implemented for `str` note: required because it appears within the type `Foo` --> $DIR/unsized_type2.rs:5:12 | diff --git a/tests/ui/statics/unsizing-wfcheck-issue-127299.stderr b/tests/ui/statics/unsizing-wfcheck-issue-127299.stderr index 59e09e48523..35dd570e91f 100644 --- a/tests/ui/statics/unsizing-wfcheck-issue-127299.stderr +++ b/tests/ui/statics/unsizing-wfcheck-issue-127299.stderr @@ -26,7 +26,7 @@ error[E0277]: `(dyn Qux + 'static)` cannot be shared between threads safely LL | static FOO: &Lint = &Lint { desc: "desc" }; | ^^^^^ `(dyn Qux + 'static)` cannot be shared between threads safely | - = help: within `&'static Lint`, the trait `Sync` is not implemented for `(dyn Qux + 'static)`, which is required by `&'static Lint: Sync` + = help: within `&'static Lint`, the trait `Sync` is not implemented for `(dyn Qux + 'static)` = note: required because it appears within the type `&'static (dyn Qux + 'static)` note: required because it appears within the type `Lint` --> $DIR/unsizing-wfcheck-issue-127299.rs:7:12 diff --git a/tests/ui/str/str-idx.stderr b/tests/ui/str/str-idx.stderr index 84806cbea0d..e8bbb8058fa 100644 --- a/tests/ui/str/str-idx.stderr +++ b/tests/ui/str/str-idx.stderr @@ -4,7 +4,7 @@ error[E0277]: the type `str` cannot be indexed by `{integer}` LL | let _: u8 = s[4]; | ^ string indices are ranges of `usize` | - = help: the trait `SliceIndex<str>` is not implemented for `{integer}`, which is required by `str: Index<_>` + = help: the trait `SliceIndex<str>` is not implemented for `{integer}` = note: you can use `.chars().nth()` or `.bytes().nth()` for more information, see chapter 8 in The Book: <https://doc.rust-lang.org/book/ch08-02-strings.html#indexing-into-strings> = help: the trait `SliceIndex<[_]>` is implemented for `usize` @@ -49,7 +49,7 @@ error[E0277]: the type `str` cannot be indexed by `char` LL | let _: u8 = s['c']; | ^^^ string indices are ranges of `usize` | - = help: the trait `SliceIndex<str>` is not implemented for `char`, which is required by `str: Index<_>` + = help: the trait `SliceIndex<str>` is not implemented for `char` = note: required for `str` to implement `Index<char>` error: aborting due to 4 previous errors diff --git a/tests/ui/str/str-mut-idx.stderr b/tests/ui/str/str-mut-idx.stderr index 679f783126f..9390d689252 100644 --- a/tests/ui/str/str-mut-idx.stderr +++ b/tests/ui/str/str-mut-idx.stderr @@ -30,7 +30,7 @@ error[E0277]: the type `str` cannot be indexed by `usize` LL | s[1usize] = bot(); | ^^^^^^ string indices are ranges of `usize` | - = help: the trait `SliceIndex<str>` is not implemented for `usize`, which is required by `str: Index<_>` + = help: the trait `SliceIndex<str>` is not implemented for `usize` = help: the trait `SliceIndex<[_]>` is implemented for `usize` = help: for that trait implementation, expected `[_]`, found `str` = note: required for `str` to implement `Index<usize>` @@ -73,7 +73,7 @@ error[E0277]: the type `str` cannot be indexed by `char` LL | s['c']; | ^^^ string indices are ranges of `usize` | - = help: the trait `SliceIndex<str>` is not implemented for `char`, which is required by `str: Index<_>` + = help: the trait `SliceIndex<str>` is not implemented for `char` = note: required for `str` to implement `Index<char>` error: aborting due to 6 previous errors diff --git a/tests/ui/suggestions/derive-clone-for-eq.stderr b/tests/ui/suggestions/derive-clone-for-eq.stderr index 6fae6e1316d..680890e880c 100644 --- a/tests/ui/suggestions/derive-clone-for-eq.stderr +++ b/tests/ui/suggestions/derive-clone-for-eq.stderr @@ -2,7 +2,7 @@ error[E0277]: the trait bound `T: Clone` is not satisfied --> $DIR/derive-clone-for-eq.rs:4:17 | LL | #[derive(Clone, Eq)] - | ^^ the trait `Clone` is not implemented for `T`, which is required by `Struct<T>: PartialEq` + | ^^ the trait `Clone` is not implemented for `T` | note: required for `Struct<T>` to implement `PartialEq` --> $DIR/derive-clone-for-eq.rs:7:19 diff --git a/tests/ui/suggestions/derive-macro-missing-bounds.stderr b/tests/ui/suggestions/derive-macro-missing-bounds.stderr index 5da85a9d061..bffcb1af487 100644 --- a/tests/ui/suggestions/derive-macro-missing-bounds.stderr +++ b/tests/ui/suggestions/derive-macro-missing-bounds.stderr @@ -6,7 +6,7 @@ LL | #[derive(Debug)] LL | struct Outer<T>(Inner<T>); | ^^^^^^^^ `a::Inner<T>` cannot be formatted using `{:?}` | - = help: the trait `Debug` is not implemented for `a::Inner<T>`, which is required by `&a::Inner<T>: Debug` + = help: the trait `Debug` is not implemented for `a::Inner<T>` = note: add `#[derive(Debug)]` to `a::Inner<T>` or manually `impl Debug for a::Inner<T>` = note: this error originates in the derive macro `Debug` (in Nightly builds, run with -Z macro-backtrace for more info) help: consider annotating `a::Inner<T>` with `#[derive(Debug)]` @@ -25,7 +25,7 @@ error[E0277]: the trait bound `T: c::Trait` is not satisfied LL | #[derive(Debug)] | ----- in this derive macro expansion LL | struct Outer<T>(Inner<T>); - | ^^^^^^^^ the trait `c::Trait` is not implemented for `T`, which is required by `&c::Inner<T>: Debug` + | ^^^^^^^^ the trait `c::Trait` is not implemented for `T` | note: required for `c::Inner<T>` to implement `Debug` --> $DIR/derive-macro-missing-bounds.rs:34:28 @@ -49,7 +49,7 @@ error[E0277]: the trait bound `T: d::Trait` is not satisfied LL | #[derive(Debug)] | ----- in this derive macro expansion LL | struct Outer<T>(Inner<T>); - | ^^^^^^^^ the trait `d::Trait` is not implemented for `T`, which is required by `&d::Inner<T>: Debug` + | ^^^^^^^^ the trait `d::Trait` is not implemented for `T` | note: required for `d::Inner<T>` to implement `Debug` --> $DIR/derive-macro-missing-bounds.rs:49:13 @@ -71,7 +71,7 @@ error[E0277]: the trait bound `T: e::Trait` is not satisfied LL | #[derive(Debug)] | ----- in this derive macro expansion LL | struct Outer<T>(Inner<T>); - | ^^^^^^^^ the trait `e::Trait` is not implemented for `T`, which is required by `&e::Inner<T>: Debug` + | ^^^^^^^^ the trait `e::Trait` is not implemented for `T` | note: required for `e::Inner<T>` to implement `Debug` --> $DIR/derive-macro-missing-bounds.rs:64:13 @@ -93,7 +93,7 @@ error[E0277]: the trait bound `T: f::Trait` is not satisfied LL | #[derive(Debug)] | ----- in this derive macro expansion LL | struct Outer<T>(Inner<T>); - | ^^^^^^^^ the trait `f::Trait` is not implemented for `T`, which is required by `&f::Inner<T>: Debug` + | ^^^^^^^^ the trait `f::Trait` is not implemented for `T` | note: required for `f::Inner<T>` to implement `Debug` --> $DIR/derive-macro-missing-bounds.rs:79:20 diff --git a/tests/ui/suggestions/into-str.stderr b/tests/ui/suggestions/into-str.stderr index ac6e531fee2..d02d3186082 100644 --- a/tests/ui/suggestions/into-str.stderr +++ b/tests/ui/suggestions/into-str.stderr @@ -2,7 +2,7 @@ error[E0277]: the trait bound `&str: From<String>` is not satisfied --> $DIR/into-str.rs:4:9 | LL | foo(String::new()); - | --- ^^^^^^^^^^^^^ the trait `From<String>` is not implemented for `&str`, which is required by `String: Into<&str>` + | --- ^^^^^^^^^^^^^ the trait `From<String>` is not implemented for `&str` | | | required by a bound introduced by this call | diff --git a/tests/ui/suggestions/issue-71394-no-from-impl.stderr b/tests/ui/suggestions/issue-71394-no-from-impl.stderr index 79f5dcf4b73..31f8f1d455a 100644 --- a/tests/ui/suggestions/issue-71394-no-from-impl.stderr +++ b/tests/ui/suggestions/issue-71394-no-from-impl.stderr @@ -2,7 +2,7 @@ error[E0277]: the trait bound `&[i8]: From<&[u8]>` is not satisfied --> $DIR/issue-71394-no-from-impl.rs:8:25 | LL | let _: &[i8] = data.into(); - | ^^^^ the trait `From<&[u8]>` is not implemented for `&[i8]`, which is required by `&[u8]: Into<_>` + | ^^^^ the trait `From<&[u8]>` is not implemented for `&[i8]` | = help: the following other types implement trait `From<T>`: `[T; 10]` implements `From<(T, T, T, T, T, T, T, T, T, T)>` diff --git a/tests/ui/suggestions/issue-88696.stderr b/tests/ui/suggestions/issue-88696.stderr index a8bc970e055..b4f0793c225 100644 --- a/tests/ui/suggestions/issue-88696.stderr +++ b/tests/ui/suggestions/issue-88696.stderr @@ -2,7 +2,7 @@ error[E0277]: the trait bound `Result<u32, i32>: From<Result<u64, i32>>` is not --> $DIR/issue-88696.rs:9:9 | LL | a().into() - | ^^^^ the trait `From<Result<u64, i32>>` is not implemented for `Result<u32, i32>`, which is required by `Result<u64, i32>: Into<_>` + | ^^^^ the trait `From<Result<u64, i32>>` is not implemented for `Result<u32, i32>` | = note: required for `Result<u64, i32>` to implement `Into<Result<u32, i32>>` diff --git a/tests/ui/suggestions/issue-96223.stderr b/tests/ui/suggestions/issue-96223.stderr index 4a77b240f3e..a54a4e7b3be 100644 --- a/tests/ui/suggestions/issue-96223.stderr +++ b/tests/ui/suggestions/issue-96223.stderr @@ -2,7 +2,7 @@ error[E0277]: the trait bound `for<'de> EmptyBis<'de>: Foo<'_>` is not satisfied --> $DIR/issue-96223.rs:49:17 | LL | icey_bounds(&p); - | ----------- ^^ the trait `for<'de> Foo<'_>` is not implemented for `EmptyBis<'de>`, which is required by `Empty: Dummy<EmptyMarker>` + | ----------- ^^ the trait `for<'de> Foo<'_>` is not implemented for `EmptyBis<'de>` | | | required by a bound introduced by this call | diff --git a/tests/ui/suggestions/issue-96555.stderr b/tests/ui/suggestions/issue-96555.stderr index f77681ae80f..1a1e069f09e 100644 --- a/tests/ui/suggestions/issue-96555.stderr +++ b/tests/ui/suggestions/issue-96555.stderr @@ -6,7 +6,7 @@ LL | m::f1().await; | | | this call returns `()` | - = help: the trait `Future` is not implemented for `()`, which is required by `(): IntoFuture` + = help: the trait `Future` is not implemented for `()` = note: () must be a future or must implement `IntoFuture` to be awaited = note: required for `()` to implement `IntoFuture` help: remove the `.await` @@ -27,7 +27,7 @@ LL | m::f2().await; | | | this call returns `()` | - = help: the trait `Future` is not implemented for `()`, which is required by `(): IntoFuture` + = help: the trait `Future` is not implemented for `()` = note: () must be a future or must implement `IntoFuture` to be awaited = note: required for `()` to implement `IntoFuture` help: remove the `.await` @@ -48,7 +48,7 @@ LL | m::f3().await; | | | this call returns `()` | - = help: the trait `Future` is not implemented for `()`, which is required by `(): IntoFuture` + = help: the trait `Future` is not implemented for `()` = note: () must be a future or must implement `IntoFuture` to be awaited = note: required for `()` to implement `IntoFuture` help: remove the `.await` diff --git a/tests/ui/suggestions/missing-bound-in-derive-copy-impl-2.stderr b/tests/ui/suggestions/missing-bound-in-derive-copy-impl-2.stderr index db16fff826f..d65ad109241 100644 --- a/tests/ui/suggestions/missing-bound-in-derive-copy-impl-2.stderr +++ b/tests/ui/suggestions/missing-bound-in-derive-copy-impl-2.stderr @@ -21,7 +21,7 @@ LL | #[derive(Debug, Copy, Clone)] | ----- in this derive macro expansion LL | pub struct AABB<K: Debug> { LL | pub loc: Vector2<K>, - | ^^^^^^^^^^^^^^^^^^^ the trait `Copy` is not implemented for `K`, which is required by `Vector2<K>: Debug` + | ^^^^^^^^^^^^^^^^^^^ the trait `Copy` is not implemented for `K` | note: required for `Vector2<K>` to implement `Debug` --> $DIR/missing-bound-in-derive-copy-impl-2.rs:4:10 @@ -64,7 +64,7 @@ LL | #[derive(Debug, Copy, Clone)] | ----- in this derive macro expansion ... LL | pub size: Vector2<K>, - | ^^^^^^^^^^^^^^^^^^^^ the trait `Copy` is not implemented for `K`, which is required by `Vector2<K>: Clone` + | ^^^^^^^^^^^^^^^^^^^^ the trait `Copy` is not implemented for `K` | note: required for `Vector2<K>` to implement `Clone` --> $DIR/missing-bound-in-derive-copy-impl-2.rs:4:23 diff --git a/tests/ui/suggestions/missing-bound-in-derive-copy-impl.stderr b/tests/ui/suggestions/missing-bound-in-derive-copy-impl.stderr index cf383b5c8ff..316c2fa0fc9 100644 --- a/tests/ui/suggestions/missing-bound-in-derive-copy-impl.stderr +++ b/tests/ui/suggestions/missing-bound-in-derive-copy-impl.stderr @@ -57,7 +57,7 @@ LL | #[derive(Debug, Copy, Clone)] | ----- in this derive macro expansion LL | pub struct AABB<K> { LL | pub loc: Vector2<K>, - | ^^^^^^^^^^^^^^^^^^^ the trait `Copy` is not implemented for `K`, which is required by `Vector2<K>: Debug` + | ^^^^^^^^^^^^^^^^^^^ the trait `Copy` is not implemented for `K` | note: required for `Vector2<K>` to implement `Debug` --> $DIR/missing-bound-in-derive-copy-impl.rs:3:10 @@ -130,7 +130,7 @@ LL | #[derive(Debug, Copy, Clone)] | ----- in this derive macro expansion ... LL | pub size: Vector2<K>, - | ^^^^^^^^^^^^^^^^^^^^ the trait `Copy` is not implemented for `K`, which is required by `Vector2<K>: Clone` + | ^^^^^^^^^^^^^^^^^^^^ the trait `Copy` is not implemented for `K` | note: required for `Vector2<K>` to implement `Clone` --> $DIR/missing-bound-in-derive-copy-impl.rs:3:23 diff --git a/tests/ui/suggestions/path-by-value.stderr b/tests/ui/suggestions/path-by-value.stderr index 62feafe534d..d870e21043c 100644 --- a/tests/ui/suggestions/path-by-value.stderr +++ b/tests/ui/suggestions/path-by-value.stderr @@ -4,7 +4,7 @@ error[E0277]: the size for values of type `[u8]` cannot be known at compilation LL | fn f(p: Path) { } | ^^^^ doesn't have a size known at compile-time | - = help: within `Path`, the trait `Sized` is not implemented for `[u8]`, which is required by `Path: Sized` + = help: within `Path`, the trait `Sized` is not implemented for `[u8]` note: required because it appears within the type `Path` --> $SRC_DIR/std/src/path.rs:LL:COL = help: unsized fn params are gated as an unstable feature diff --git a/tests/ui/suggestions/path-display.stderr b/tests/ui/suggestions/path-display.stderr index f9159c45030..46d0b35825b 100644 --- a/tests/ui/suggestions/path-display.stderr +++ b/tests/ui/suggestions/path-display.stderr @@ -4,7 +4,7 @@ error[E0277]: `Path` doesn't implement `std::fmt::Display` LL | println!("{}", path); | ^^^^ `Path` cannot be formatted with the default formatter; call `.display()` on it | - = help: the trait `std::fmt::Display` is not implemented for `Path`, which is required by `&Path: std::fmt::Display` + = help: the trait `std::fmt::Display` is not implemented for `Path` = note: in format strings you may be able to use `{:?}` (or {:#?} for pretty-print) instead = note: call `.display()` or `.to_string_lossy()` to safely print paths, as they may contain non-Unicode data = note: this error originates in the macro `$crate::format_args_nl` which comes from the expansion of the macro `println` (in Nightly builds, run with -Z macro-backtrace for more info) diff --git a/tests/ui/suggestions/suggest-dereferencing-index.stderr b/tests/ui/suggestions/suggest-dereferencing-index.stderr index 86487cdcc44..2316acbe9da 100644 --- a/tests/ui/suggestions/suggest-dereferencing-index.stderr +++ b/tests/ui/suggestions/suggest-dereferencing-index.stderr @@ -4,7 +4,7 @@ error[E0277]: the type `[{integer}]` cannot be indexed by `&usize` LL | let one_item_please: i32 = [1, 2, 3][i]; | ^ slice indices are of type `usize` or ranges of `usize` | - = help: the trait `SliceIndex<[{integer}]>` is not implemented for `&usize`, which is required by `[{integer}; 3]: Index<_>` + = help: the trait `SliceIndex<[{integer}]>` is not implemented for `&usize` = help: the trait `SliceIndex<[{integer}]>` is implemented for `usize` = help: for that trait implementation, expected `usize`, found `&usize` = note: required for `[{integer}]` to implement `Index<&usize>` diff --git a/tests/ui/suggestions/suggest-pin-macro.stderr b/tests/ui/suggestions/suggest-pin-macro.stderr index 68f4099a976..a761a454ad5 100644 --- a/tests/ui/suggestions/suggest-pin-macro.stderr +++ b/tests/ui/suggestions/suggest-pin-macro.stderr @@ -2,7 +2,7 @@ error[E0277]: `PhantomPinned` cannot be unpinned --> $DIR/suggest-pin-macro.rs:22:17 | LL | dummy(test1.get_mut()); - | ^^^^^^^ within `Test`, the trait `Unpin` is not implemented for `PhantomPinned`, which is required by `Test: Unpin` + | ^^^^^^^ within `Test`, the trait `Unpin` is not implemented for `PhantomPinned` | = note: consider using the `pin!` macro consider using `Box::pin` if you need to access the pinned value outside of the current scope diff --git a/tests/ui/suggestions/suggest-remove-refs-1.stderr b/tests/ui/suggestions/suggest-remove-refs-1.stderr index 171184bf77d..523f78dffcc 100644 --- a/tests/ui/suggestions/suggest-remove-refs-1.stderr +++ b/tests/ui/suggestions/suggest-remove-refs-1.stderr @@ -4,7 +4,7 @@ error[E0277]: `&Enumerate<std::slice::Iter<'_, {integer}>>` is not an iterator LL | for (i, _) in &v.iter().enumerate() { | ^^^^^^^^^^^^^^^^^^^^^ `&Enumerate<std::slice::Iter<'_, {integer}>>` is not an iterator | - = help: the trait `Iterator` is not implemented for `&Enumerate<std::slice::Iter<'_, {integer}>>`, which is required by `&Enumerate<std::slice::Iter<'_, {integer}>>: IntoIterator` + = help: the trait `Iterator` is not implemented for `&Enumerate<std::slice::Iter<'_, {integer}>>` = note: required for `&Enumerate<std::slice::Iter<'_, {integer}>>` to implement `IntoIterator` help: consider removing the leading `&`-reference | diff --git a/tests/ui/suggestions/suggest-remove-refs-2.stderr b/tests/ui/suggestions/suggest-remove-refs-2.stderr index 4e1994523dc..bbe3261e148 100644 --- a/tests/ui/suggestions/suggest-remove-refs-2.stderr +++ b/tests/ui/suggestions/suggest-remove-refs-2.stderr @@ -4,7 +4,7 @@ error[E0277]: `&&&&&Enumerate<std::slice::Iter<'_, {integer}>>` is not an iterat LL | for (i, _) in & & & & &v.iter().enumerate() { | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ `&&&&&Enumerate<std::slice::Iter<'_, {integer}>>` is not an iterator | - = help: the trait `Iterator` is not implemented for `&&&&&Enumerate<std::slice::Iter<'_, {integer}>>`, which is required by `&&&&&Enumerate<std::slice::Iter<'_, {integer}>>: IntoIterator` + = help: the trait `Iterator` is not implemented for `&&&&&Enumerate<std::slice::Iter<'_, {integer}>>` = note: required for `&&&&&Enumerate<std::slice::Iter<'_, {integer}>>` to implement `IntoIterator` help: consider removing 5 leading `&`-references | diff --git a/tests/ui/suggestions/suggest-remove-refs-3.stderr b/tests/ui/suggestions/suggest-remove-refs-3.stderr index 1d180f9d8be..a3e142563ff 100644 --- a/tests/ui/suggestions/suggest-remove-refs-3.stderr +++ b/tests/ui/suggestions/suggest-remove-refs-3.stderr @@ -8,7 +8,7 @@ LL | | .iter() LL | | .enumerate() { | |____________________^ `&&&&&Enumerate<std::slice::Iter<'_, {integer}>>` is not an iterator | - = help: the trait `Iterator` is not implemented for `&&&&&Enumerate<std::slice::Iter<'_, {integer}>>`, which is required by `&&&&&Enumerate<std::slice::Iter<'_, {integer}>>: IntoIterator` + = help: the trait `Iterator` is not implemented for `&&&&&Enumerate<std::slice::Iter<'_, {integer}>>` = note: required for `&&&&&Enumerate<std::slice::Iter<'_, {integer}>>` to implement `IntoIterator` help: consider removing 5 leading `&`-references | diff --git a/tests/ui/suggestions/suggest-remove-refs-4.stderr b/tests/ui/suggestions/suggest-remove-refs-4.stderr index 7ab34c4af51..ed9fc2dd256 100644 --- a/tests/ui/suggestions/suggest-remove-refs-4.stderr +++ b/tests/ui/suggestions/suggest-remove-refs-4.stderr @@ -4,7 +4,7 @@ error[E0277]: `&&std::slice::Iter<'_, {integer}>` is not an iterator LL | for _i in &foo {} | ^^^^ `&&std::slice::Iter<'_, {integer}>` is not an iterator | - = help: the trait `Iterator` is not implemented for `&&std::slice::Iter<'_, {integer}>`, which is required by `&&std::slice::Iter<'_, {integer}>: IntoIterator` + = help: the trait `Iterator` is not implemented for `&&std::slice::Iter<'_, {integer}>` = note: required for `&&std::slice::Iter<'_, {integer}>` to implement `IntoIterator` help: consider removing 2 leading `&`-references | diff --git a/tests/ui/suggestions/suggest-remove-refs-5.stderr b/tests/ui/suggestions/suggest-remove-refs-5.stderr index b132c56473e..ae83012c70e 100644 --- a/tests/ui/suggestions/suggest-remove-refs-5.stderr +++ b/tests/ui/suggestions/suggest-remove-refs-5.stderr @@ -4,7 +4,7 @@ error[E0277]: `&mut &mut &mut &mut Vec<i32>` is not an iterator LL | for _ in &mut &mut v {} | ^^^^^^^^^^^ `&mut &mut &mut &mut Vec<i32>` is not an iterator | - = help: the trait `Iterator` is not implemented for `Vec<i32>`, which is required by `&mut &mut &mut &mut Vec<i32>: IntoIterator` + = help: the trait `Iterator` is not implemented for `Vec<i32>` = note: required for `&mut Vec<i32>` to implement `Iterator` = note: 3 redundant requirements hidden = note: required for `&mut &mut &mut &mut Vec<i32>` to implement `Iterator` @@ -21,7 +21,7 @@ error[E0277]: `&mut &mut &mut [u8; 1]` is not an iterator LL | for _ in &mut v {} | ^^^^^^ `&mut &mut &mut [u8; 1]` is not an iterator | - = help: the trait `Iterator` is not implemented for `[u8; 1]`, which is required by `&mut &mut &mut [u8; 1]: IntoIterator` + = help: the trait `Iterator` is not implemented for `[u8; 1]` = note: required for `&mut [u8; 1]` to implement `Iterator` = note: 2 redundant requirements hidden = note: required for `&mut &mut &mut [u8; 1]` to implement `Iterator` diff --git a/tests/ui/sync/mutexguard-sync.stderr b/tests/ui/sync/mutexguard-sync.stderr index 6b686741d1f..1501a793d5e 100644 --- a/tests/ui/sync/mutexguard-sync.stderr +++ b/tests/ui/sync/mutexguard-sync.stderr @@ -6,7 +6,7 @@ LL | test_sync(guard); | | | required by a bound introduced by this call | - = help: the trait `Sync` is not implemented for `Cell<i32>`, which is required by `MutexGuard<'_, Cell<i32>>: Sync` + = help: the trait `Sync` is not implemented for `Cell<i32>` = note: if you want to do aliasing and mutation between multiple threads, use `std::sync::RwLock` or `std::sync::atomic::AtomicI32` instead = note: required for `MutexGuard<'_, Cell<i32>>` to implement `Sync` note: required by a bound in `test_sync` diff --git a/tests/ui/sync/reentrantlockguard-sync.stderr b/tests/ui/sync/reentrantlockguard-sync.stderr index ed2e3e2f112..6bedf8f9f2e 100644 --- a/tests/ui/sync/reentrantlockguard-sync.stderr +++ b/tests/ui/sync/reentrantlockguard-sync.stderr @@ -6,7 +6,7 @@ LL | test_sync(guard); | | | required by a bound introduced by this call | - = help: the trait `Sync` is not implemented for `Cell<i32>`, which is required by `ReentrantLockGuard<'_, Cell<i32>>: Sync` + = help: the trait `Sync` is not implemented for `Cell<i32>` = note: if you want to do aliasing and mutation between multiple threads, use `std::sync::RwLock` or `std::sync::atomic::AtomicI32` instead = note: required for `ReentrantLockGuard<'_, Cell<i32>>` to implement `Sync` note: required by a bound in `test_sync` diff --git a/tests/ui/thir-print/thir-tree-match.stdout b/tests/ui/thir-print/thir-tree-match.stdout index b2431698cc6..8cff7887661 100644 --- a/tests/ui/thir-print/thir-tree-match.stdout +++ b/tests/ui/thir-print/thir-tree-match.stdout @@ -41,7 +41,7 @@ body: Block { targeted_by_break: false span: $DIR/thir-tree-match.rs:15:32: 21:2 (#0) - region_scope: Node(25) + region_scope: Node(3) safety_mode: Safe stmts: [] expr: @@ -51,8 +51,8 @@ body: span: $DIR/thir-tree-match.rs:16:5: 20:6 (#0) kind: Scope { - region_scope: Node(3) - lint_level: Explicit(HirId(DefId(0:16 ~ thir_tree_match[fcf8]::has_match).3)) + region_scope: Node(4) + lint_level: Explicit(HirId(DefId(0:16 ~ thir_tree_match[fcf8]::has_match).4)) value: Expr { ty: bool @@ -67,8 +67,8 @@ body: span: $DIR/thir-tree-match.rs:16:11: 16:14 (#0) kind: Scope { - region_scope: Node(4) - lint_level: Explicit(HirId(DefId(0:16 ~ thir_tree_match[fcf8]::has_match).4)) + region_scope: Node(5) + lint_level: Explicit(HirId(DefId(0:16 ~ thir_tree_match[fcf8]::has_match).5)) value: Expr { ty: Foo @@ -123,16 +123,16 @@ body: body: Expr { ty: bool - temp_lifetime: Some(Node(12)) + temp_lifetime: Some(Node(13)) span: $DIR/thir-tree-match.rs:17:36: 17:40 (#0) kind: Scope { - region_scope: Node(13) - lint_level: Explicit(HirId(DefId(0:16 ~ thir_tree_match[fcf8]::has_match).13)) + region_scope: Node(14) + lint_level: Explicit(HirId(DefId(0:16 ~ thir_tree_match[fcf8]::has_match).14)) value: Expr { ty: bool - temp_lifetime: Some(Node(12)) + temp_lifetime: Some(Node(13)) span: $DIR/thir-tree-match.rs:17:36: 17:40 (#0) kind: Literal( lit: Spanned { node: Bool(true), span: $DIR/thir-tree-match.rs:17:36: 17:40 (#0) }, neg: false) @@ -140,8 +140,8 @@ body: } } } - lint_level: Explicit(HirId(DefId(0:16 ~ thir_tree_match[fcf8]::has_match).12)) - scope: Node(12) + lint_level: Explicit(HirId(DefId(0:16 ~ thir_tree_match[fcf8]::has_match).13)) + scope: Node(13) span: $DIR/thir-tree-match.rs:17:9: 17:40 (#0) } Arm { @@ -175,16 +175,16 @@ body: body: Expr { ty: bool - temp_lifetime: Some(Node(18)) + temp_lifetime: Some(Node(19)) span: $DIR/thir-tree-match.rs:18:27: 18:32 (#0) kind: Scope { - region_scope: Node(19) - lint_level: Explicit(HirId(DefId(0:16 ~ thir_tree_match[fcf8]::has_match).19)) + region_scope: Node(20) + lint_level: Explicit(HirId(DefId(0:16 ~ thir_tree_match[fcf8]::has_match).20)) value: Expr { ty: bool - temp_lifetime: Some(Node(18)) + temp_lifetime: Some(Node(19)) span: $DIR/thir-tree-match.rs:18:27: 18:32 (#0) kind: Literal( lit: Spanned { node: Bool(false), span: $DIR/thir-tree-match.rs:18:27: 18:32 (#0) }, neg: false) @@ -192,8 +192,8 @@ body: } } } - lint_level: Explicit(HirId(DefId(0:16 ~ thir_tree_match[fcf8]::has_match).18)) - scope: Node(18) + lint_level: Explicit(HirId(DefId(0:16 ~ thir_tree_match[fcf8]::has_match).19)) + scope: Node(19) span: $DIR/thir-tree-match.rs:18:9: 18:32 (#0) } Arm { @@ -219,16 +219,16 @@ body: body: Expr { ty: bool - temp_lifetime: Some(Node(23)) + temp_lifetime: Some(Node(24)) span: $DIR/thir-tree-match.rs:19:24: 19:28 (#0) kind: Scope { - region_scope: Node(24) - lint_level: Explicit(HirId(DefId(0:16 ~ thir_tree_match[fcf8]::has_match).24)) + region_scope: Node(25) + lint_level: Explicit(HirId(DefId(0:16 ~ thir_tree_match[fcf8]::has_match).25)) value: Expr { ty: bool - temp_lifetime: Some(Node(23)) + temp_lifetime: Some(Node(24)) span: $DIR/thir-tree-match.rs:19:24: 19:28 (#0) kind: Literal( lit: Spanned { node: Bool(true), span: $DIR/thir-tree-match.rs:19:24: 19:28 (#0) }, neg: false) @@ -236,8 +236,8 @@ body: } } } - lint_level: Explicit(HirId(DefId(0:16 ~ thir_tree_match[fcf8]::has_match).23)) - scope: Node(23) + lint_level: Explicit(HirId(DefId(0:16 ~ thir_tree_match[fcf8]::has_match).24)) + scope: Node(24) span: $DIR/thir-tree-match.rs:19:9: 19:28 (#0) } ] diff --git a/tests/ui/trait-bounds/super-assoc-mismatch.stderr b/tests/ui/trait-bounds/super-assoc-mismatch.stderr index f2c5eb47e59..780535283a3 100644 --- a/tests/ui/trait-bounds/super-assoc-mismatch.stderr +++ b/tests/ui/trait-bounds/super-assoc-mismatch.stderr @@ -53,7 +53,7 @@ error[E0277]: the trait bound `(): Sub` is not satisfied --> $DIR/super-assoc-mismatch.rs:29:21 | LL | type Assoc<T> = (); - | ^^ the trait `Sub` is not implemented for `()`, which is required by `<u8 as BoundOnGat>::Assoc<u8>: Sub` + | ^^ the trait `Sub` is not implemented for `()` | help: this trait has no implementations, consider adding one --> $DIR/super-assoc-mismatch.rs:7:1 @@ -87,7 +87,7 @@ error[E0277]: the trait bound `(): SubGeneric<u16>` is not satisfied --> $DIR/super-assoc-mismatch.rs:55:22 | LL | type Assoc1<T> = (); - | ^^ the trait `SubGeneric<u16>` is not implemented for `()`, which is required by `<u8 as MultiAssoc>::Assoc1<()>: SubGeneric<<u8 as MultiAssoc>::Assoc2>` + | ^^ the trait `SubGeneric<u16>` is not implemented for `()` | help: this trait has no implementations, consider adding one --> $DIR/super-assoc-mismatch.rs:43:1 diff --git a/tests/ui/traits/alias/cross-crate.stderr b/tests/ui/traits/alias/cross-crate.stderr index 52eb7e44f44..8ed05b4758d 100644 --- a/tests/ui/traits/alias/cross-crate.stderr +++ b/tests/ui/traits/alias/cross-crate.stderr @@ -2,7 +2,7 @@ error[E0277]: the trait bound `Rc<u32>: SendSync` is not satisfied --> $DIR/cross-crate.rs:14:17 | LL | use_alias::<Rc<u32>>(); - | ^^^^^^^ the trait `Send` is not implemented for `Rc<u32>`, which is required by `Rc<u32>: SendSync` + | ^^^^^^^ the trait `Send` is not implemented for `Rc<u32>` | = note: required for `Rc<u32>` to implement `SendSync` note: required by a bound in `use_alias` @@ -15,7 +15,7 @@ error[E0277]: the trait bound `Rc<u32>: SendSync` is not satisfied --> $DIR/cross-crate.rs:14:17 | LL | use_alias::<Rc<u32>>(); - | ^^^^^^^ the trait `Sync` is not implemented for `Rc<u32>`, which is required by `Rc<u32>: SendSync` + | ^^^^^^^ the trait `Sync` is not implemented for `Rc<u32>` | = note: required for `Rc<u32>` to implement `SendSync` note: required by a bound in `use_alias` diff --git a/tests/ui/traits/alias/issue-108072-unmet-trait-alias-bound.stderr b/tests/ui/traits/alias/issue-108072-unmet-trait-alias-bound.stderr index c73c2f68032..27e23adb92a 100644 --- a/tests/ui/traits/alias/issue-108072-unmet-trait-alias-bound.stderr +++ b/tests/ui/traits/alias/issue-108072-unmet-trait-alias-bound.stderr @@ -2,7 +2,7 @@ error[E0277]: the trait bound `(): IteratorAlias` is not satisfied --> $DIR/issue-108072-unmet-trait-alias-bound.rs:10:7 | LL | f(()) - | - ^^ the trait `Iterator` is not implemented for `()`, which is required by `(): IteratorAlias` + | - ^^ the trait `Iterator` is not implemented for `()` | | | required by a bound introduced by this call | diff --git a/tests/ui/traits/bound/assoc-fn-bound-root-obligation.rs b/tests/ui/traits/bound/assoc-fn-bound-root-obligation.rs index dc2de5bb715..667d283bea3 100644 --- a/tests/ui/traits/bound/assoc-fn-bound-root-obligation.rs +++ b/tests/ui/traits/bound/assoc-fn-bound-root-obligation.rs @@ -2,7 +2,7 @@ fn strip_lf(s: &str) -> &str { s.strip_suffix(b'\n').unwrap_or(s) //~^ ERROR the trait bound `u8: Pattern` is not satisfied //~| NOTE required by a bound introduced by this call - //~| NOTE the trait `FnMut(char)` is not implemented for `u8`, which is required by `u8: Pattern` + //~| NOTE the trait `FnMut(char)` is not implemented for `u8` //~| HELP the following other types implement trait `Pattern`: //~| NOTE required for `u8` to implement `Pattern` //~| NOTE required by a bound in `core::str::<impl str>::strip_suffix` diff --git a/tests/ui/traits/bound/assoc-fn-bound-root-obligation.stderr b/tests/ui/traits/bound/assoc-fn-bound-root-obligation.stderr index 8351d15fdf3..1cd62d2cbdb 100644 --- a/tests/ui/traits/bound/assoc-fn-bound-root-obligation.stderr +++ b/tests/ui/traits/bound/assoc-fn-bound-root-obligation.stderr @@ -2,7 +2,7 @@ error[E0277]: the trait bound `u8: Pattern` is not satisfied --> $DIR/assoc-fn-bound-root-obligation.rs:2:20 | LL | s.strip_suffix(b'\n').unwrap_or(s) - | ------------ ^^^^^ the trait `FnMut(char)` is not implemented for `u8`, which is required by `u8: Pattern` + | ------------ ^^^^^ the trait `FnMut(char)` is not implemented for `u8` | | | required by a bound introduced by this call | diff --git a/tests/ui/traits/const-traits/assoc-type.stderr b/tests/ui/traits/const-traits/assoc-type.stderr index 5c77754200a..672eaf26f72 100644 --- a/tests/ui/traits/const-traits/assoc-type.stderr +++ b/tests/ui/traits/const-traits/assoc-type.stderr @@ -17,7 +17,7 @@ note: required by a bound in `Foo::Bar` --> $DIR/assoc-type.rs:32:15 | LL | type Bar: ~const Add; - | ^^^^^^^^^^ required by this bound in `Foo::Bar` + | ^^^^^^ required by this bound in `Foo::Bar` error: aborting due to 1 previous error; 1 warning emitted diff --git a/tests/ui/traits/const-traits/call-generic-in-impl.stderr b/tests/ui/traits/const-traits/call-generic-in-impl.stderr index 971e77e372b..52ee04425b2 100644 --- a/tests/ui/traits/const-traits/call-generic-in-impl.stderr +++ b/tests/ui/traits/const-traits/call-generic-in-impl.stderr @@ -1,14 +1,14 @@ error: `~const` can only be applied to `#[const_trait]` traits - --> $DIR/call-generic-in-impl.rs:10:16 + --> $DIR/call-generic-in-impl.rs:10:9 | LL | impl<T: ~const PartialEq> const MyPartialEq for T { - | ^^^^^^^^^ + | ^^^^^^ error: `~const` can only be applied to `#[const_trait]` traits - --> $DIR/call-generic-in-impl.rs:10:16 + --> $DIR/call-generic-in-impl.rs:10:9 | LL | impl<T: ~const PartialEq> const MyPartialEq for T { - | ^^^^^^^^^ + | ^^^^^^ | = note: duplicate diagnostic emitted due to `-Z deduplicate-diagnostics=no` diff --git a/tests/ui/traits/const-traits/call-generic-method-chain.stderr b/tests/ui/traits/const-traits/call-generic-method-chain.stderr index aa90305c648..6dbf3ad2526 100644 --- a/tests/ui/traits/const-traits/call-generic-method-chain.stderr +++ b/tests/ui/traits/const-traits/call-generic-method-chain.stderr @@ -17,30 +17,30 @@ LL | impl const PartialEq for S { = note: adding a non-const method body in the future would be a breaking change error: `~const` can only be applied to `#[const_trait]` traits - --> $DIR/call-generic-method-chain.rs:20:32 + --> $DIR/call-generic-method-chain.rs:20:25 | LL | const fn equals_self<T: ~const PartialEq>(t: &T) -> bool { - | ^^^^^^^^^ + | ^^^^^^ error: `~const` can only be applied to `#[const_trait]` traits - --> $DIR/call-generic-method-chain.rs:20:32 + --> $DIR/call-generic-method-chain.rs:20:25 | LL | const fn equals_self<T: ~const PartialEq>(t: &T) -> bool { - | ^^^^^^^^^ + | ^^^^^^ | = note: duplicate diagnostic emitted due to `-Z deduplicate-diagnostics=no` error: `~const` can only be applied to `#[const_trait]` traits - --> $DIR/call-generic-method-chain.rs:24:40 + --> $DIR/call-generic-method-chain.rs:24:33 | LL | const fn equals_self_wrapper<T: ~const PartialEq>(t: &T) -> bool { - | ^^^^^^^^^ + | ^^^^^^ error: `~const` can only be applied to `#[const_trait]` traits - --> $DIR/call-generic-method-chain.rs:24:40 + --> $DIR/call-generic-method-chain.rs:24:33 | LL | const fn equals_self_wrapper<T: ~const PartialEq>(t: &T) -> bool { - | ^^^^^^^^^ + | ^^^^^^ | = note: duplicate diagnostic emitted due to `-Z deduplicate-diagnostics=no` diff --git a/tests/ui/traits/const-traits/call-generic-method-dup-bound.stderr b/tests/ui/traits/const-traits/call-generic-method-dup-bound.stderr index 029915b7646..08877daad79 100644 --- a/tests/ui/traits/const-traits/call-generic-method-dup-bound.stderr +++ b/tests/ui/traits/const-traits/call-generic-method-dup-bound.stderr @@ -17,30 +17,30 @@ LL | impl const PartialEq for S { = note: adding a non-const method body in the future would be a breaking change error: `~const` can only be applied to `#[const_trait]` traits - --> $DIR/call-generic-method-dup-bound.rs:20:44 + --> $DIR/call-generic-method-dup-bound.rs:20:37 | LL | const fn equals_self<T: PartialEq + ~const PartialEq>(t: &T) -> bool { - | ^^^^^^^^^ + | ^^^^^^ error: `~const` can only be applied to `#[const_trait]` traits - --> $DIR/call-generic-method-dup-bound.rs:20:44 + --> $DIR/call-generic-method-dup-bound.rs:20:37 | LL | const fn equals_self<T: PartialEq + ~const PartialEq>(t: &T) -> bool { - | ^^^^^^^^^ + | ^^^^^^ | = note: duplicate diagnostic emitted due to `-Z deduplicate-diagnostics=no` error: `~const` can only be applied to `#[const_trait]` traits - --> $DIR/call-generic-method-dup-bound.rs:27:37 + --> $DIR/call-generic-method-dup-bound.rs:27:30 | LL | const fn equals_self2<T: A + ~const PartialEq>(t: &T) -> bool { - | ^^^^^^^^^ + | ^^^^^^ error: `~const` can only be applied to `#[const_trait]` traits - --> $DIR/call-generic-method-dup-bound.rs:27:37 + --> $DIR/call-generic-method-dup-bound.rs:27:30 | LL | const fn equals_self2<T: A + ~const PartialEq>(t: &T) -> bool { - | ^^^^^^^^^ + | ^^^^^^ | = note: duplicate diagnostic emitted due to `-Z deduplicate-diagnostics=no` diff --git a/tests/ui/traits/const-traits/call-generic-method-pass.stderr b/tests/ui/traits/const-traits/call-generic-method-pass.stderr index 97ce7fe1c2a..ac08c057435 100644 --- a/tests/ui/traits/const-traits/call-generic-method-pass.stderr +++ b/tests/ui/traits/const-traits/call-generic-method-pass.stderr @@ -17,16 +17,16 @@ LL | impl const PartialEq for S { = note: adding a non-const method body in the future would be a breaking change error: `~const` can only be applied to `#[const_trait]` traits - --> $DIR/call-generic-method-pass.rs:20:32 + --> $DIR/call-generic-method-pass.rs:20:25 | LL | const fn equals_self<T: ~const PartialEq>(t: &T) -> bool { - | ^^^^^^^^^ + | ^^^^^^ error: `~const` can only be applied to `#[const_trait]` traits - --> $DIR/call-generic-method-pass.rs:20:32 + --> $DIR/call-generic-method-pass.rs:20:25 | LL | const fn equals_self<T: ~const PartialEq>(t: &T) -> bool { - | ^^^^^^^^^ + | ^^^^^^ | = note: duplicate diagnostic emitted due to `-Z deduplicate-diagnostics=no` diff --git a/tests/ui/traits/const-traits/const-bounds-non-const-trait.stderr b/tests/ui/traits/const-traits/const-bounds-non-const-trait.stderr index 6c3c11c6a47..8e836685eb0 100644 --- a/tests/ui/traits/const-traits/const-bounds-non-const-trait.stderr +++ b/tests/ui/traits/const-traits/const-bounds-non-const-trait.stderr @@ -7,30 +7,25 @@ LL | #![feature(const_trait_impl, effects)] = note: see issue #102090 <https://github.com/rust-lang/rust/issues/102090> for more information = note: `#[warn(incomplete_features)]` on by default -error: using `#![feature(effects)]` without enabling next trait solver globally - | - = note: the next trait solver must be enabled globally for the effects feature to work correctly - = help: use `-Znext-solver` to enable - error: `~const` can only be applied to `#[const_trait]` traits - --> $DIR/const-bounds-non-const-trait.rs:6:28 + --> $DIR/const-bounds-non-const-trait.rs:6:21 | LL | const fn perform<T: ~const NonConst>() {} - | ^^^^^^^^ + | ^^^^^^ error: `~const` can only be applied to `#[const_trait]` traits - --> $DIR/const-bounds-non-const-trait.rs:6:28 + --> $DIR/const-bounds-non-const-trait.rs:6:21 | LL | const fn perform<T: ~const NonConst>() {} - | ^^^^^^^^ + | ^^^^^^ | = note: duplicate diagnostic emitted due to `-Z deduplicate-diagnostics=no` error: `const` can only be applied to `#[const_trait]` traits - --> $DIR/const-bounds-non-const-trait.rs:10:21 + --> $DIR/const-bounds-non-const-trait.rs:10:15 | LL | fn operate<T: const NonConst>() {} - | ^^^^^^^^ + | ^^^^^ -error: aborting due to 4 previous errors; 1 warning emitted +error: aborting due to 3 previous errors; 1 warning emitted diff --git a/tests/ui/traits/const-traits/const-closure-parse-not-item.stderr b/tests/ui/traits/const-traits/const-closure-parse-not-item.stderr index 12cc79f5961..25c81ff900f 100644 --- a/tests/ui/traits/const-traits/const-closure-parse-not-item.stderr +++ b/tests/ui/traits/const-traits/const-closure-parse-not-item.stderr @@ -1,14 +1,14 @@ error: `~const` can only be applied to `#[const_trait]` traits - --> $DIR/const-closure-parse-not-item.rs:7:32 + --> $DIR/const-closure-parse-not-item.rs:7:25 | LL | const fn test() -> impl ~const Fn() { - | ^^^^ + | ^^^^^^ error: `~const` can only be applied to `#[const_trait]` traits - --> $DIR/const-closure-parse-not-item.rs:7:32 + --> $DIR/const-closure-parse-not-item.rs:7:25 | LL | const fn test() -> impl ~const Fn() { - | ^^^^ + | ^^^^^^ | = note: duplicate diagnostic emitted due to `-Z deduplicate-diagnostics=no` diff --git a/tests/ui/traits/const-traits/const-closure-trait-method-fail.stderr b/tests/ui/traits/const-traits/const-closure-trait-method-fail.stderr index f0f033bceef..cb4c994bc2f 100644 --- a/tests/ui/traits/const-traits/const-closure-trait-method-fail.stderr +++ b/tests/ui/traits/const-traits/const-closure-trait-method-fail.stderr @@ -1,14 +1,14 @@ error: `~const` can only be applied to `#[const_trait]` traits - --> $DIR/const-closure-trait-method-fail.rs:14:39 + --> $DIR/const-closure-trait-method-fail.rs:14:32 | LL | const fn need_const_closure<T: ~const FnOnce(()) -> i32>(x: T) -> i32 { - | ^^^^^^^^^^^^^^^^^ + | ^^^^^^ error: `~const` can only be applied to `#[const_trait]` traits - --> $DIR/const-closure-trait-method-fail.rs:14:39 + --> $DIR/const-closure-trait-method-fail.rs:14:32 | LL | const fn need_const_closure<T: ~const FnOnce(()) -> i32>(x: T) -> i32 { - | ^^^^^^^^^^^^^^^^^ + | ^^^^^^ | = note: duplicate diagnostic emitted due to `-Z deduplicate-diagnostics=no` diff --git a/tests/ui/traits/const-traits/const-closure-trait-method.stderr b/tests/ui/traits/const-traits/const-closure-trait-method.stderr index 4c5a4d0cdf4..43af435ae64 100644 --- a/tests/ui/traits/const-traits/const-closure-trait-method.stderr +++ b/tests/ui/traits/const-traits/const-closure-trait-method.stderr @@ -1,14 +1,14 @@ error: `~const` can only be applied to `#[const_trait]` traits - --> $DIR/const-closure-trait-method.rs:14:39 + --> $DIR/const-closure-trait-method.rs:14:32 | LL | const fn need_const_closure<T: ~const FnOnce(()) -> i32>(x: T) -> i32 { - | ^^^^^^^^^^^^^^^^^ + | ^^^^^^ error: `~const` can only be applied to `#[const_trait]` traits - --> $DIR/const-closure-trait-method.rs:14:39 + --> $DIR/const-closure-trait-method.rs:14:32 | LL | const fn need_const_closure<T: ~const FnOnce(()) -> i32>(x: T) -> i32 { - | ^^^^^^^^^^^^^^^^^ + | ^^^^^^ | = note: duplicate diagnostic emitted due to `-Z deduplicate-diagnostics=no` diff --git a/tests/ui/traits/const-traits/const-closures.stderr b/tests/ui/traits/const-traits/const-closures.stderr index a81804a50dc..2e9e37ba321 100644 --- a/tests/ui/traits/const-traits/const-closures.stderr +++ b/tests/ui/traits/const-traits/const-closures.stderr @@ -1,56 +1,56 @@ error: `~const` can only be applied to `#[const_trait]` traits - --> $DIR/const-closures.rs:8:19 + --> $DIR/const-closures.rs:8:12 | LL | F: ~const FnOnce() -> u8, - | ^^^^^^^^^^^^^^ + | ^^^^^^ error: `~const` can only be applied to `#[const_trait]` traits - --> $DIR/const-closures.rs:9:19 + --> $DIR/const-closures.rs:9:12 | LL | F: ~const FnMut() -> u8, - | ^^^^^^^^^^^^^ + | ^^^^^^ error: `~const` can only be applied to `#[const_trait]` traits - --> $DIR/const-closures.rs:10:19 + --> $DIR/const-closures.rs:10:12 | LL | F: ~const Fn() -> u8, - | ^^^^^^^^^^ + | ^^^^^^ error: `~const` can only be applied to `#[const_trait]` traits - --> $DIR/const-closures.rs:8:19 + --> $DIR/const-closures.rs:8:12 | LL | F: ~const FnOnce() -> u8, - | ^^^^^^^^^^^^^^ + | ^^^^^^ | = note: duplicate diagnostic emitted due to `-Z deduplicate-diagnostics=no` error: `~const` can only be applied to `#[const_trait]` traits - --> $DIR/const-closures.rs:9:19 + --> $DIR/const-closures.rs:9:12 | LL | F: ~const FnMut() -> u8, - | ^^^^^^^^^^^^^ + | ^^^^^^ | = note: duplicate diagnostic emitted due to `-Z deduplicate-diagnostics=no` error: `~const` can only be applied to `#[const_trait]` traits - --> $DIR/const-closures.rs:10:19 + --> $DIR/const-closures.rs:10:12 | LL | F: ~const Fn() -> u8, - | ^^^^^^^^^^ + | ^^^^^^ | = note: duplicate diagnostic emitted due to `-Z deduplicate-diagnostics=no` error: `~const` can only be applied to `#[const_trait]` traits - --> $DIR/const-closures.rs:23:27 + --> $DIR/const-closures.rs:23:20 | LL | const fn answer<F: ~const Fn() -> u8>(f: &F) -> u8 { - | ^^^^^^^^^^ + | ^^^^^^ error: `~const` can only be applied to `#[const_trait]` traits - --> $DIR/const-closures.rs:23:27 + --> $DIR/const-closures.rs:23:20 | LL | const fn answer<F: ~const Fn() -> u8>(f: &F) -> u8 { - | ^^^^^^^^^^ + | ^^^^^^ | = note: duplicate diagnostic emitted due to `-Z deduplicate-diagnostics=no` diff --git a/tests/ui/traits/const-traits/const-drop-bound.stderr b/tests/ui/traits/const-traits/const-drop-bound.stderr index d94b0542324..3f718645433 100644 --- a/tests/ui/traits/const-traits/const-drop-bound.stderr +++ b/tests/ui/traits/const-traits/const-drop-bound.stderr @@ -1,42 +1,42 @@ error: `~const` can only be applied to `#[const_trait]` traits - --> $DIR/const-drop-bound.rs:9:68 + --> $DIR/const-drop-bound.rs:9:61 | LL | const fn foo<T, E>(res: Result<T, E>) -> Option<T> where E: ~const Destruct { - | ^^^^^^^^ + | ^^^^^^ error: `~const` can only be applied to `#[const_trait]` traits - --> $DIR/const-drop-bound.rs:9:68 + --> $DIR/const-drop-bound.rs:9:61 | LL | const fn foo<T, E>(res: Result<T, E>) -> Option<T> where E: ~const Destruct { - | ^^^^^^^^ + | ^^^^^^ | = note: duplicate diagnostic emitted due to `-Z deduplicate-diagnostics=no` error: `~const` can only be applied to `#[const_trait]` traits - --> $DIR/const-drop-bound.rs:20:15 + --> $DIR/const-drop-bound.rs:20:8 | LL | T: ~const Destruct, - | ^^^^^^^^ + | ^^^^^^ error: `~const` can only be applied to `#[const_trait]` traits - --> $DIR/const-drop-bound.rs:21:15 + --> $DIR/const-drop-bound.rs:21:8 | LL | E: ~const Destruct, - | ^^^^^^^^ + | ^^^^^^ error: `~const` can only be applied to `#[const_trait]` traits - --> $DIR/const-drop-bound.rs:20:15 + --> $DIR/const-drop-bound.rs:20:8 | LL | T: ~const Destruct, - | ^^^^^^^^ + | ^^^^^^ | = note: duplicate diagnostic emitted due to `-Z deduplicate-diagnostics=no` error: `~const` can only be applied to `#[const_trait]` traits - --> $DIR/const-drop-bound.rs:21:15 + --> $DIR/const-drop-bound.rs:21:8 | LL | E: ~const Destruct, - | ^^^^^^^^ + | ^^^^^^ | = note: duplicate diagnostic emitted due to `-Z deduplicate-diagnostics=no` diff --git a/tests/ui/traits/const-traits/const-drop-fail-2.stderr b/tests/ui/traits/const-traits/const-drop-fail-2.stderr index 27e8053c969..82d6412ded0 100644 --- a/tests/ui/traits/const-traits/const-drop-fail-2.stderr +++ b/tests/ui/traits/const-traits/const-drop-fail-2.stderr @@ -8,16 +8,16 @@ LL | impl<T: ~const A> const Drop for ConstDropImplWithNonConstBounds<T> { = note: adding a non-const method body in the future would be a breaking change error: `~const` can only be applied to `#[const_trait]` traits - --> $DIR/const-drop-fail-2.rs:20:26 + --> $DIR/const-drop-fail-2.rs:20:19 | LL | const fn check<T: ~const Destruct>(_: T) {} - | ^^^^^^^^ + | ^^^^^^ error: `~const` can only be applied to `#[const_trait]` traits - --> $DIR/const-drop-fail-2.rs:20:26 + --> $DIR/const-drop-fail-2.rs:20:19 | LL | const fn check<T: ~const Destruct>(_: T) {} - | ^^^^^^^^ + | ^^^^^^ | = note: duplicate diagnostic emitted due to `-Z deduplicate-diagnostics=no` diff --git a/tests/ui/traits/const-traits/const-drop-fail.precise.stderr b/tests/ui/traits/const-traits/const-drop-fail.precise.stderr index bde13b4d6cf..859fdfae81a 100644 --- a/tests/ui/traits/const-traits/const-drop-fail.precise.stderr +++ b/tests/ui/traits/const-traits/const-drop-fail.precise.stderr @@ -8,16 +8,16 @@ LL | impl const Drop for ConstImplWithDropGlue { = note: adding a non-const method body in the future would be a breaking change error: `~const` can only be applied to `#[const_trait]` traits - --> $DIR/const-drop-fail.rs:23:26 + --> $DIR/const-drop-fail.rs:23:19 | LL | const fn check<T: ~const Destruct>(_: T) {} - | ^^^^^^^^ + | ^^^^^^ error: `~const` can only be applied to `#[const_trait]` traits - --> $DIR/const-drop-fail.rs:23:26 + --> $DIR/const-drop-fail.rs:23:19 | LL | const fn check<T: ~const Destruct>(_: T) {} - | ^^^^^^^^ + | ^^^^^^ | = note: duplicate diagnostic emitted due to `-Z deduplicate-diagnostics=no` diff --git a/tests/ui/traits/const-traits/const-drop-fail.stock.stderr b/tests/ui/traits/const-traits/const-drop-fail.stock.stderr index 064ffacca42..20dea28922b 100644 --- a/tests/ui/traits/const-traits/const-drop-fail.stock.stderr +++ b/tests/ui/traits/const-traits/const-drop-fail.stock.stderr @@ -8,16 +8,16 @@ LL | impl const Drop for ConstImplWithDropGlue { = note: adding a non-const method body in the future would be a breaking change error: `~const` can only be applied to `#[const_trait]` traits - --> $DIR/const-drop-fail.rs:23:26 + --> $DIR/const-drop-fail.rs:23:19 | LL | const fn check<T: ~const Destruct>(_: T) {} - | ^^^^^^^^ + | ^^^^^^ error: `~const` can only be applied to `#[const_trait]` traits - --> $DIR/const-drop-fail.rs:23:26 + --> $DIR/const-drop-fail.rs:23:19 | LL | const fn check<T: ~const Destruct>(_: T) {} - | ^^^^^^^^ + | ^^^^^^ | = note: duplicate diagnostic emitted due to `-Z deduplicate-diagnostics=no` diff --git a/tests/ui/traits/const-traits/const-drop.precise.stderr b/tests/ui/traits/const-traits/const-drop.precise.stderr index 7b6d185c7cc..381e4d78c28 100644 --- a/tests/ui/traits/const-traits/const-drop.precise.stderr +++ b/tests/ui/traits/const-traits/const-drop.precise.stderr @@ -35,19 +35,43 @@ LL | impl<T: SomeTrait> const Drop for ConstDropWithNonconstBound<T> { = note: adding a non-const method body in the future would be a breaking change error: `~const` can only be applied to `#[const_trait]` traits - --> $DIR/const-drop.rs:18:22 + --> $DIR/const-drop.rs:18:15 | LL | const fn a<T: ~const Destruct>(_: T) {} - | ^^^^^^^^ + | ^^^^^^ error: `~const` can only be applied to `#[const_trait]` traits - --> $DIR/const-drop.rs:18:22 + --> $DIR/const-drop.rs:18:15 | LL | const fn a<T: ~const Destruct>(_: T) {} - | ^^^^^^^^ + | ^^^^^^ | = note: duplicate diagnostic emitted due to `-Z deduplicate-diagnostics=no` +error[E0277]: the trait bound `T: const SomeTrait` is not satisfied + --> $DIR/const-drop.rs:67:46 + | +LL | impl<T: ~const SomeTrait> const Drop for ConstDropWithBound<T> { + | ^^^^^^^^^^^^^^^^^^^^^ + | +note: required by a bound in `t::ConstDropWithBound` + --> $DIR/const-drop.rs:65:38 + | +LL | pub struct ConstDropWithBound<T: const SomeTrait>(pub core::marker::PhantomData<T>); + | ^^^^^ required by this bound in `ConstDropWithBound` + +error[E0277]: the trait bound `T: const SomeTrait` is not satisfied + --> $DIR/const-drop.rs:68:22 + | +LL | fn drop(&mut self) { + | ^^^^ + | +note: required by a bound in `t::ConstDropWithBound` + --> $DIR/const-drop.rs:65:38 + | +LL | pub struct ConstDropWithBound<T: const SomeTrait>(pub core::marker::PhantomData<T>); + | ^^^^^ required by this bound in `ConstDropWithBound` + error[E0493]: destructor of `T` cannot be evaluated at compile-time --> $DIR/const-drop.rs:18:32 | @@ -66,7 +90,7 @@ help: add `#![feature(effects)]` to the crate attributes to enable LL + #![feature(effects)] | -error: aborting due to 8 previous errors +error: aborting due to 10 previous errors -Some errors have detailed explanations: E0015, E0493. +Some errors have detailed explanations: E0015, E0277, E0493. For more information about an error, try `rustc --explain E0015`. diff --git a/tests/ui/traits/const-traits/const-drop.stock.stderr b/tests/ui/traits/const-traits/const-drop.stock.stderr index b497c39b08a..399e7849673 100644 --- a/tests/ui/traits/const-traits/const-drop.stock.stderr +++ b/tests/ui/traits/const-traits/const-drop.stock.stderr @@ -35,19 +35,43 @@ LL | impl<T: SomeTrait> const Drop for ConstDropWithNonconstBound<T> { = note: adding a non-const method body in the future would be a breaking change error: `~const` can only be applied to `#[const_trait]` traits - --> $DIR/const-drop.rs:18:22 + --> $DIR/const-drop.rs:18:15 | LL | const fn a<T: ~const Destruct>(_: T) {} - | ^^^^^^^^ + | ^^^^^^ error: `~const` can only be applied to `#[const_trait]` traits - --> $DIR/const-drop.rs:18:22 + --> $DIR/const-drop.rs:18:15 | LL | const fn a<T: ~const Destruct>(_: T) {} - | ^^^^^^^^ + | ^^^^^^ | = note: duplicate diagnostic emitted due to `-Z deduplicate-diagnostics=no` +error[E0277]: the trait bound `T: const SomeTrait` is not satisfied + --> $DIR/const-drop.rs:67:46 + | +LL | impl<T: ~const SomeTrait> const Drop for ConstDropWithBound<T> { + | ^^^^^^^^^^^^^^^^^^^^^ + | +note: required by a bound in `t::ConstDropWithBound` + --> $DIR/const-drop.rs:65:38 + | +LL | pub struct ConstDropWithBound<T: const SomeTrait>(pub core::marker::PhantomData<T>); + | ^^^^^ required by this bound in `ConstDropWithBound` + +error[E0277]: the trait bound `T: const SomeTrait` is not satisfied + --> $DIR/const-drop.rs:68:22 + | +LL | fn drop(&mut self) { + | ^^^^ + | +note: required by a bound in `t::ConstDropWithBound` + --> $DIR/const-drop.rs:65:38 + | +LL | pub struct ConstDropWithBound<T: const SomeTrait>(pub core::marker::PhantomData<T>); + | ^^^^^ required by this bound in `ConstDropWithBound` + error[E0493]: destructor of `T` cannot be evaluated at compile-time --> $DIR/const-drop.rs:18:32 | @@ -68,7 +92,7 @@ help: add `#![feature(effects)]` to the crate attributes to enable LL + #![feature(effects)] | -error: aborting due to 8 previous errors +error: aborting due to 10 previous errors -Some errors have detailed explanations: E0015, E0493. +Some errors have detailed explanations: E0015, E0277, E0493. For more information about an error, try `rustc --explain E0015`. diff --git a/tests/ui/traits/const-traits/const_derives/derive-const-non-const-type.stderr b/tests/ui/traits/const-traits/const_derives/derive-const-non-const-type.stderr index 4bcc17952e6..8f4235dabad 100644 --- a/tests/ui/traits/const-traits/const_derives/derive-const-non-const-type.stderr +++ b/tests/ui/traits/const-traits/const_derives/derive-const-non-const-type.stderr @@ -7,11 +7,6 @@ LL | #![feature(derive_const, effects)] = note: see issue #102090 <https://github.com/rust-lang/rust/issues/102090> for more information = note: `#[warn(incomplete_features)]` on by default -error: using `#![feature(effects)]` without enabling next trait solver globally - | - = note: the next trait solver must be enabled globally for the effects feature to work correctly - = help: use `-Znext-solver` to enable - error: const `impl` for trait `Default` which is not marked with `#[const_trait]` --> $DIR/derive-const-non-const-type.rs:10:16 | @@ -33,6 +28,6 @@ LL | pub struct S(A); = note: calls in constant functions are limited to constant functions, tuple structs and tuple variants = note: this error originates in the derive macro `Default` (in Nightly builds, run with -Z macro-backtrace for more info) -error: aborting due to 3 previous errors; 1 warning emitted +error: aborting due to 2 previous errors; 1 warning emitted For more information about this error, try `rustc --explain E0015`. diff --git a/tests/ui/traits/const-traits/const_derives/derive-const-use.stderr b/tests/ui/traits/const-traits/const_derives/derive-const-use.stderr index d471a8253ba..7fc44229e2a 100644 --- a/tests/ui/traits/const-traits/const_derives/derive-const-use.stderr +++ b/tests/ui/traits/const-traits/const_derives/derive-const-use.stderr @@ -19,11 +19,6 @@ error[E0635]: unknown feature `const_default_impls` LL | #![feature(const_trait_impl, const_cmp, const_default_impls, derive_const, effects)] | ^^^^^^^^^^^^^^^^^^^ -error: using `#![feature(effects)]` without enabling next trait solver globally - | - = note: the next trait solver must be enabled globally for the effects feature to work correctly - = help: use `-Znext-solver` to enable - error: const `impl` for trait `Default` which is not marked with `#[const_trait]` --> $DIR/derive-const-use.rs:7:12 | @@ -122,7 +117,7 @@ LL | pub struct S((), A); = note: calls in constant functions are limited to constant functions, tuple structs and tuple variants = note: this error originates in the derive macro `PartialEq` (in Nightly builds, run with -Z macro-backtrace for more info) -error: aborting due to 13 previous errors; 1 warning emitted +error: aborting due to 12 previous errors; 1 warning emitted Some errors have detailed explanations: E0015, E0635. For more information about an error, try `rustc --explain E0015`. diff --git a/tests/ui/traits/const-traits/const_derives/derive-const-with-params.stderr b/tests/ui/traits/const-traits/const_derives/derive-const-with-params.stderr index 33e7e08bb23..1395947bb15 100644 --- a/tests/ui/traits/const-traits/const_derives/derive-const-with-params.stderr +++ b/tests/ui/traits/const-traits/const_derives/derive-const-with-params.stderr @@ -7,11 +7,6 @@ LL | #![feature(const_trait_impl, effects)] = note: see issue #102090 <https://github.com/rust-lang/rust/issues/102090> for more information = note: `#[warn(incomplete_features)]` on by default -error: using `#![feature(effects)]` without enabling next trait solver globally - | - = note: the next trait solver must be enabled globally for the effects feature to work correctly - = help: use `-Znext-solver` to enable - error: const `impl` for trait `PartialEq` which is not marked with `#[const_trait]` --> $DIR/derive-const-with-params.rs:7:16 | @@ -23,12 +18,6 @@ LL | #[derive_const(PartialEq)] = note: this error originates in the derive macro `PartialEq` (in Nightly builds, run with -Z macro-backtrace for more info) error: `~const` can only be applied to `#[const_trait]` traits - --> $DIR/derive-const-with-params.rs:7:16 - | -LL | #[derive_const(PartialEq)] - | ^^^^^^^^^ - | - = note: this error originates in the derive macro `PartialEq` (in Nightly builds, run with -Z macro-backtrace for more info) error[E0015]: cannot call non-const operator in constant functions --> $DIR/derive-const-with-params.rs:8:23 @@ -49,6 +38,6 @@ LL | a == b | = note: calls in constant functions are limited to constant functions, tuple structs and tuple variants -error: aborting due to 5 previous errors; 1 warning emitted +error: aborting due to 4 previous errors; 1 warning emitted For more information about this error, try `rustc --explain E0015`. diff --git a/tests/ui/traits/const-traits/effects/ice-112822-expected-type-for-param.stderr b/tests/ui/traits/const-traits/effects/ice-112822-expected-type-for-param.stderr index edfdf8b5f78..36184856035 100644 --- a/tests/ui/traits/const-traits/effects/ice-112822-expected-type-for-param.stderr +++ b/tests/ui/traits/const-traits/effects/ice-112822-expected-type-for-param.stderr @@ -17,22 +17,17 @@ LL | #![feature(const_trait_impl, effects)] = note: see issue #102090 <https://github.com/rust-lang/rust/issues/102090> for more information = note: `#[warn(incomplete_features)]` on by default -error: using `#![feature(effects)]` without enabling next trait solver globally - | - = note: the next trait solver must be enabled globally for the effects feature to work correctly - = help: use `-Znext-solver` to enable - error: `~const` can only be applied to `#[const_trait]` traits - --> $DIR/ice-112822-expected-type-for-param.rs:3:32 + --> $DIR/ice-112822-expected-type-for-param.rs:3:25 | LL | const fn test() -> impl ~const Fn() { - | ^^^^ + | ^^^^^^ error: `~const` can only be applied to `#[const_trait]` traits - --> $DIR/ice-112822-expected-type-for-param.rs:3:32 + --> $DIR/ice-112822-expected-type-for-param.rs:3:25 | LL | const fn test() -> impl ~const Fn() { - | ^^^^ + | ^^^^^^ | = note: duplicate diagnostic emitted due to `-Z deduplicate-diagnostics=no` @@ -54,7 +49,7 @@ LL | assert_eq!(first, &b'f'); = note: calls in constant functions are limited to constant functions, tuple structs and tuple variants = note: this error originates in the macro `assert_eq` (in Nightly builds, run with -Z macro-backtrace for more info) -error: aborting due to 6 previous errors; 1 warning emitted +error: aborting due to 5 previous errors; 1 warning emitted Some errors have detailed explanations: E0015, E0658. For more information about an error, try `rustc --explain E0015`. diff --git a/tests/ui/traits/const-traits/effects/no-explicit-const-params.rs b/tests/ui/traits/const-traits/effects/no-explicit-const-params.rs index b08aba9acbc..c6b94fa2230 100644 --- a/tests/ui/traits/const-traits/effects/no-explicit-const-params.rs +++ b/tests/ui/traits/const-traits/effects/no-explicit-const-params.rs @@ -23,4 +23,5 @@ const FOO: () = { //~^ ERROR: function takes 0 generic arguments but 1 generic argument was supplied <() as Bar<false>>::bar(); //~^ ERROR: trait takes 0 generic arguments but 1 generic argument was supplied + //~| ERROR the trait bound `(): const Bar` is not satisfied }; diff --git a/tests/ui/traits/const-traits/effects/no-explicit-const-params.stderr b/tests/ui/traits/const-traits/effects/no-explicit-const-params.stderr index a3aa970e94d..bd9acc7a6d2 100644 --- a/tests/ui/traits/const-traits/effects/no-explicit-const-params.stderr +++ b/tests/ui/traits/const-traits/effects/no-explicit-const-params.stderr @@ -7,11 +7,6 @@ LL | #![feature(const_trait_impl, effects)] = note: see issue #102090 <https://github.com/rust-lang/rust/issues/102090> for more information = note: `#[warn(incomplete_features)]` on by default -error: using `#![feature(effects)]` without enabling next trait solver globally - | - = note: the next trait solver must be enabled globally for the effects feature to work correctly - = help: use `-Znext-solver` to enable - error[E0107]: function takes 0 generic arguments but 1 generic argument was supplied --> $DIR/no-explicit-const-params.rs:22:5 | @@ -40,6 +35,12 @@ note: trait defined here, with 0 generic parameters LL | trait Bar { | ^^^ +error[E0277]: the trait bound `(): const Bar` is not satisfied + --> $DIR/no-explicit-const-params.rs:24:5 + | +LL | <() as Bar<false>>::bar(); + | ^^^^^^^^^^^^^^^^^^^^^^^^^ + error[E0107]: function takes 0 generic arguments but 1 generic argument was supplied --> $DIR/no-explicit-const-params.rs:15:5 | @@ -70,4 +71,5 @@ LL | trait Bar { error: aborting due to 5 previous errors; 1 warning emitted -For more information about this error, try `rustc --explain E0107`. +Some errors have detailed explanations: E0107, E0277. +For more information about an error, try `rustc --explain E0107`. diff --git a/tests/ui/traits/const-traits/effects/span-bug-issue-121418.stderr b/tests/ui/traits/const-traits/effects/span-bug-issue-121418.stderr index 5ff1c6c5b9f..97663232fcf 100644 --- a/tests/ui/traits/const-traits/effects/span-bug-issue-121418.stderr +++ b/tests/ui/traits/const-traits/effects/span-bug-issue-121418.stderr @@ -17,11 +17,6 @@ LL | #![feature(effects)] = note: see issue #102090 <https://github.com/rust-lang/rust/issues/102090> for more information = note: `#[warn(incomplete_features)]` on by default -error: using `#![feature(effects)]` without enabling next trait solver globally - | - = note: the next trait solver must be enabled globally for the effects feature to work correctly - = help: use `-Znext-solver` to enable - error[E0308]: mismatched types --> $DIR/span-bug-issue-121418.rs:9:27 | @@ -39,12 +34,12 @@ error[E0277]: the size for values of type `(dyn T + 'static)` cannot be known at LL | pub const fn new() -> std::sync::Mutex<dyn T> {} | ^^^^^^^^^^^^^^^^^^^^^^^ doesn't have a size known at compile-time | - = help: within `Mutex<(dyn T + 'static)>`, the trait `Sized` is not implemented for `(dyn T + 'static)`, which is required by `Mutex<(dyn T + 'static)>: Sized` + = help: within `Mutex<(dyn T + 'static)>`, the trait `Sized` is not implemented for `(dyn T + 'static)` note: required because it appears within the type `Mutex<(dyn T + 'static)>` --> $SRC_DIR/std/src/sync/mutex.rs:LL:COL = note: the return type of a function must have a statically known size -error: aborting due to 4 previous errors; 1 warning emitted +error: aborting due to 3 previous errors; 1 warning emitted Some errors have detailed explanations: E0277, E0308. For more information about an error, try `rustc --explain E0277`. diff --git a/tests/ui/traits/const-traits/effects/spec-effectvar-ice.stderr b/tests/ui/traits/const-traits/effects/spec-effectvar-ice.stderr index d9655c4995f..273f9943212 100644 --- a/tests/ui/traits/const-traits/effects/spec-effectvar-ice.stderr +++ b/tests/ui/traits/const-traits/effects/spec-effectvar-ice.stderr @@ -7,11 +7,6 @@ LL | #![feature(effects)] = note: see issue #102090 <https://github.com/rust-lang/rust/issues/102090> for more information = note: `#[warn(incomplete_features)]` on by default -error: using `#![feature(effects)]` without enabling next trait solver globally - | - = note: the next trait solver must be enabled globally for the effects feature to work correctly - = help: use `-Znext-solver` to enable - error: const `impl` for trait `Foo` which is not marked with `#[const_trait]` --> $DIR/spec-effectvar-ice.rs:11:15 | @@ -37,10 +32,10 @@ LL | impl<T> const Foo for T where T: const Specialize {} = note: adding a non-const method body in the future would be a breaking change error: `const` can only be applied to `#[const_trait]` traits - --> $DIR/spec-effectvar-ice.rs:14:40 + --> $DIR/spec-effectvar-ice.rs:14:34 | LL | impl<T> const Foo for T where T: const Specialize {} - | ^^^^^^^^^^ + | ^^^^^ error: specialization impl does not specialize any associated items --> $DIR/spec-effectvar-ice.rs:14:1 @@ -60,5 +55,5 @@ error: cannot specialize on trait `Specialize` LL | impl<T> const Foo for T where T: const Specialize {} | ^^^^^^^^^^^^^^^^ -error: aborting due to 6 previous errors; 1 warning emitted +error: aborting due to 5 previous errors; 1 warning emitted diff --git a/tests/ui/traits/const-traits/effects/trait-fn-const.stderr b/tests/ui/traits/const-traits/effects/trait-fn-const.stderr index 15cb84026e4..33914cb306d 100644 --- a/tests/ui/traits/const-traits/effects/trait-fn-const.stderr +++ b/tests/ui/traits/const-traits/effects/trait-fn-const.stderr @@ -63,11 +63,6 @@ LL | #![feature(const_trait_impl, effects)] = note: see issue #102090 <https://github.com/rust-lang/rust/issues/102090> for more information = note: `#[warn(incomplete_features)]` on by default -error: using `#![feature(effects)]` without enabling next trait solver globally - | - = note: the next trait solver must be enabled globally for the effects feature to work correctly - = help: use `-Znext-solver` to enable - -error: aborting due to 5 previous errors; 1 warning emitted +error: aborting due to 4 previous errors; 1 warning emitted For more information about this error, try `rustc --explain E0379`. diff --git a/tests/ui/traits/const-traits/effects/with-without-next-solver.coherence.stderr b/tests/ui/traits/const-traits/effects/with-without-next-solver.coherence.stderr deleted file mode 100644 index 20448f51de2..00000000000 --- a/tests/ui/traits/const-traits/effects/with-without-next-solver.coherence.stderr +++ /dev/null @@ -1,7 +0,0 @@ -error: using `#![feature(effects)]` without enabling next trait solver globally - | - = note: the next trait solver must be enabled globally for the effects feature to work correctly - = help: use `-Znext-solver` to enable - -error: aborting due to 1 previous error - diff --git a/tests/ui/traits/const-traits/effects/with-without-next-solver.rs b/tests/ui/traits/const-traits/effects/with-without-next-solver.rs deleted file mode 100644 index f022af05c50..00000000000 --- a/tests/ui/traits/const-traits/effects/with-without-next-solver.rs +++ /dev/null @@ -1,10 +0,0 @@ -// test that we error correctly when effects is used without the next-solver flag. -//@ revisions: stock coherence full -//@[coherence] compile-flags: -Znext-solver=coherence -//@[full] compile-flags: -Znext-solver -//@[full] check-pass - -#![feature(effects)] -#![allow(incomplete_features)] - -fn main() {} diff --git a/tests/ui/traits/const-traits/effects/with-without-next-solver.stock.stderr b/tests/ui/traits/const-traits/effects/with-without-next-solver.stock.stderr deleted file mode 100644 index 20448f51de2..00000000000 --- a/tests/ui/traits/const-traits/effects/with-without-next-solver.stock.stderr +++ /dev/null @@ -1,7 +0,0 @@ -error: using `#![feature(effects)]` without enabling next trait solver globally - | - = note: the next trait solver must be enabled globally for the effects feature to work correctly - = help: use `-Znext-solver` to enable - -error: aborting due to 1 previous error - diff --git a/tests/ui/traits/const-traits/ice-119717-constant-lifetime.stderr b/tests/ui/traits/const-traits/ice-119717-constant-lifetime.stderr index 50cdded8d51..9e22422ad3b 100644 --- a/tests/ui/traits/const-traits/ice-119717-constant-lifetime.stderr +++ b/tests/ui/traits/const-traits/ice-119717-constant-lifetime.stderr @@ -1,8 +1,3 @@ -error: using `#![feature(effects)]` without enabling next trait solver globally - | - = note: the next trait solver must be enabled globally for the effects feature to work correctly - = help: use `-Znext-solver` to enable - error: const `impl` for trait `FromResidual` which is not marked with `#[const_trait]` --> $DIR/ice-119717-constant-lifetime.rs:6:15 | @@ -32,7 +27,7 @@ help: try replacing `_` with the type in the corresponding trait method signatur LL | fn from_residual(t: T) -> T { | ~ -error: aborting due to 4 previous errors +error: aborting due to 3 previous errors Some errors have detailed explanations: E0121, E0210. For more information about an error, try `rustc --explain E0121`. diff --git a/tests/ui/traits/const-traits/ice-120503-async-const-method.stderr b/tests/ui/traits/const-traits/ice-120503-async-const-method.stderr index 90771c344b5..1a11aec4b26 100644 --- a/tests/ui/traits/const-traits/ice-120503-async-const-method.stderr +++ b/tests/ui/traits/const-traits/ice-120503-async-const-method.stderr @@ -55,11 +55,6 @@ LL | #![feature(effects)] = note: see issue #102090 <https://github.com/rust-lang/rust/issues/102090> for more information = note: `#[warn(incomplete_features)]` on by default -error: using `#![feature(effects)]` without enabling next trait solver globally - | - = note: the next trait solver must be enabled globally for the effects feature to work correctly - = help: use `-Znext-solver` to enable - error[E0425]: cannot find function `main8` in this scope --> $DIR/ice-120503-async-const-method.rs:12:9 | @@ -69,7 +64,7 @@ LL | main8().await; LL | fn main() {} | --------- similarly named function `main` defined here -error: aborting due to 6 previous errors; 1 warning emitted +error: aborting due to 5 previous errors; 1 warning emitted Some errors have detailed explanations: E0379, E0407, E0425. For more information about an error, try `rustc --explain E0379`. diff --git a/tests/ui/traits/const-traits/ice-121536-const-method.stderr b/tests/ui/traits/const-traits/ice-121536-const-method.stderr index 29187654c3c..4fe88f263c8 100644 --- a/tests/ui/traits/const-traits/ice-121536-const-method.stderr +++ b/tests/ui/traits/const-traits/ice-121536-const-method.stderr @@ -23,11 +23,6 @@ LL | #![feature(const_trait_impl, effects)] = note: see issue #102090 <https://github.com/rust-lang/rust/issues/102090> for more information = note: `#[warn(incomplete_features)]` on by default -error: using `#![feature(effects)]` without enabling next trait solver globally - | - = note: the next trait solver must be enabled globally for the effects feature to work correctly - = help: use `-Znext-solver` to enable - -error: aborting due to 2 previous errors; 1 warning emitted +error: aborting due to 1 previous error; 1 warning emitted For more information about this error, try `rustc --explain E0379`. diff --git a/tests/ui/traits/const-traits/ice-123664-unexpected-bound-var.stderr b/tests/ui/traits/const-traits/ice-123664-unexpected-bound-var.stderr index 03f88be0093..1178c90fce5 100644 --- a/tests/ui/traits/const-traits/ice-123664-unexpected-bound-var.stderr +++ b/tests/ui/traits/const-traits/ice-123664-unexpected-bound-var.stderr @@ -1,21 +1,16 @@ -error: using `#![feature(effects)]` without enabling next trait solver globally - | - = note: the next trait solver must be enabled globally for the effects feature to work correctly - = help: use `-Znext-solver` to enable - error: `~const` can only be applied to `#[const_trait]` traits - --> $DIR/ice-123664-unexpected-bound-var.rs:4:34 + --> $DIR/ice-123664-unexpected-bound-var.rs:4:27 | LL | const fn with_positive<F: ~const Fn()>() {} - | ^^^^ + | ^^^^^^ error: `~const` can only be applied to `#[const_trait]` traits - --> $DIR/ice-123664-unexpected-bound-var.rs:4:34 + --> $DIR/ice-123664-unexpected-bound-var.rs:4:27 | LL | const fn with_positive<F: ~const Fn()>() {} - | ^^^^ + | ^^^^^^ | = note: duplicate diagnostic emitted due to `-Z deduplicate-diagnostics=no` -error: aborting due to 3 previous errors +error: aborting due to 2 previous errors diff --git a/tests/ui/traits/const-traits/ice-124857-combine-effect-const-infer-vars.stderr b/tests/ui/traits/const-traits/ice-124857-combine-effect-const-infer-vars.stderr index 284757c1a89..0b1f8b40898 100644 --- a/tests/ui/traits/const-traits/ice-124857-combine-effect-const-infer-vars.stderr +++ b/tests/ui/traits/const-traits/ice-124857-combine-effect-const-infer-vars.stderr @@ -1,8 +1,3 @@ -error: using `#![feature(effects)]` without enabling next trait solver globally - | - = note: the next trait solver must be enabled globally for the effects feature to work correctly - = help: use `-Znext-solver` to enable - error[E0119]: conflicting implementations of trait `Foo` for type `i32` --> $DIR/ice-124857-combine-effect-const-infer-vars.rs:11:1 | @@ -12,6 +7,6 @@ LL | LL | impl<T> const Foo for T where T: ~const Foo {} | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ conflicting implementation for `i32` -error: aborting due to 2 previous errors +error: aborting due to 1 previous error For more information about this error, try `rustc --explain E0119`. diff --git a/tests/ui/traits/const-traits/ice-126148-failed-to-normalize.stderr b/tests/ui/traits/const-traits/ice-126148-failed-to-normalize.stderr index 0ca16a1be40..db047bfd94d 100644 --- a/tests/ui/traits/const-traits/ice-126148-failed-to-normalize.stderr +++ b/tests/ui/traits/const-traits/ice-126148-failed-to-normalize.stderr @@ -1,8 +1,3 @@ -error: using `#![feature(effects)]` without enabling next trait solver globally - | - = note: the next trait solver must be enabled globally for the effects feature to work correctly - = help: use `-Znext-solver` to enable - error: const `impl` for trait `FromResidual` which is not marked with `#[const_trait]` --> $DIR/ice-126148-failed-to-normalize.rs:8:12 | @@ -54,7 +49,7 @@ LL | TryMe?; | = note: calls in constant functions are limited to constant functions, tuple structs and tuple variants -error: aborting due to 7 previous errors +error: aborting due to 6 previous errors Some errors have detailed explanations: E0015, E0046. For more information about an error, try `rustc --explain E0015`. diff --git a/tests/ui/traits/const-traits/impl-with-default-fn-fail.stderr b/tests/ui/traits/const-traits/impl-with-default-fn-fail.stderr index 2ea203627f4..0135296526f 100644 --- a/tests/ui/traits/const-traits/impl-with-default-fn-fail.stderr +++ b/tests/ui/traits/const-traits/impl-with-default-fn-fail.stderr @@ -1,8 +1,3 @@ -error: using `#![feature(effects)]` without enabling next trait solver globally - | - = note: the next trait solver must be enabled globally for the effects feature to work correctly - = help: use `-Znext-solver` to enable - error[E0046]: not all trait items implemented, missing: `req` --> $DIR/impl-with-default-fn-fail.rs:13:1 | @@ -12,6 +7,6 @@ LL | fn req(&self); LL | impl const Tr for u16 { | ^^^^^^^^^^^^^^^^^^^^^ missing `req` in implementation -error: aborting due to 2 previous errors +error: aborting due to 1 previous error For more information about this error, try `rustc --explain E0046`. diff --git a/tests/ui/traits/const-traits/issue-92111.stderr b/tests/ui/traits/const-traits/issue-92111.stderr index 805cc537014..51c6a22b43b 100644 --- a/tests/ui/traits/const-traits/issue-92111.stderr +++ b/tests/ui/traits/const-traits/issue-92111.stderr @@ -1,14 +1,14 @@ error: `~const` can only be applied to `#[const_trait]` traits - --> $DIR/issue-92111.rs:20:22 + --> $DIR/issue-92111.rs:20:15 | LL | const fn a<T: ~const Destruct>(t: T) {} - | ^^^^^^^^ + | ^^^^^^ error: `~const` can only be applied to `#[const_trait]` traits - --> $DIR/issue-92111.rs:20:22 + --> $DIR/issue-92111.rs:20:15 | LL | const fn a<T: ~const Destruct>(t: T) {} - | ^^^^^^^^ + | ^^^^^^ | = note: duplicate diagnostic emitted due to `-Z deduplicate-diagnostics=no` diff --git a/tests/ui/traits/const-traits/item-bound-entailment-fails.stderr b/tests/ui/traits/const-traits/item-bound-entailment-fails.stderr index 3b3868c4bc8..054a8ac7577 100644 --- a/tests/ui/traits/const-traits/item-bound-entailment-fails.stderr +++ b/tests/ui/traits/const-traits/item-bound-entailment-fails.stderr @@ -17,7 +17,7 @@ note: required by a bound in `Foo::Assoc` --> $DIR/item-bound-entailment-fails.rs:6:20 | LL | type Assoc<T>: ~const Bar - | ^^^^^^^^^^ required by this bound in `Foo::Assoc` + | ^^^^^^ required by this bound in `Foo::Assoc` error[E0277]: the trait bound `T: ~const Bar` is not satisfied --> $DIR/item-bound-entailment-fails.rs:25:21 @@ -29,7 +29,7 @@ note: required by a bound in `Foo::Assoc` --> $DIR/item-bound-entailment-fails.rs:6:20 | LL | type Assoc<T>: ~const Bar - | ^^^^^^^^^^ required by this bound in `Foo::Assoc` + | ^^^^^^ required by this bound in `Foo::Assoc` error: aborting due to 2 previous errors; 1 warning emitted diff --git a/tests/ui/traits/const-traits/non-const-op-in-closure-in-const.stderr b/tests/ui/traits/const-traits/non-const-op-in-closure-in-const.stderr index 08a40fe65bf..837effb7ca4 100644 --- a/tests/ui/traits/const-traits/non-const-op-in-closure-in-const.stderr +++ b/tests/ui/traits/const-traits/non-const-op-in-closure-in-const.stderr @@ -1,14 +1,14 @@ error: `~const` can only be applied to `#[const_trait]` traits - --> $DIR/non-const-op-in-closure-in-const.rs:10:51 + --> $DIR/non-const-op-in-closure-in-const.rs:10:44 | LL | impl<A, B> const Convert<B> for A where B: ~const From<A> { - | ^^^^^^^ + | ^^^^^^ error: `~const` can only be applied to `#[const_trait]` traits - --> $DIR/non-const-op-in-closure-in-const.rs:10:51 + --> $DIR/non-const-op-in-closure-in-const.rs:10:44 | LL | impl<A, B> const Convert<B> for A where B: ~const From<A> { - | ^^^^^^^ + | ^^^^^^ | = note: duplicate diagnostic emitted due to `-Z deduplicate-diagnostics=no` diff --git a/tests/ui/traits/const-traits/predicate-entailment-fails.stderr b/tests/ui/traits/const-traits/predicate-entailment-fails.stderr index 7cd48ef1d48..c50009e9b8c 100644 --- a/tests/ui/traits/const-traits/predicate-entailment-fails.stderr +++ b/tests/ui/traits/const-traits/predicate-entailment-fails.stderr @@ -14,7 +14,7 @@ LL | type Bar<T> where T: ~const Bar; | ----------- definition of `Bar` from trait ... LL | type Bar<T> = () where T: const Bar; - | ^^^^^^^^^ impl has extra requirement `T: const Bar` + | ^^^^^ impl has extra requirement `T: const Bar` error[E0276]: impl has stricter requirements than trait --> $DIR/predicate-entailment-fails.rs:18:26 @@ -23,7 +23,7 @@ LL | fn foo<T>() where T: ~const Bar; | -------------------------------- definition of `foo` from trait ... LL | fn foo<T>() where T: const Bar {} - | ^^^^^^^^^ impl has extra requirement `T: const Bar` + | ^^^^^ impl has extra requirement `T: const Bar` error[E0276]: impl has stricter requirements than trait --> $DIR/predicate-entailment-fails.rs:29:31 @@ -32,7 +32,7 @@ LL | type Bar<T> where T: Bar; | ----------- definition of `Bar` from trait ... LL | type Bar<T> = () where T: const Bar; - | ^^^^^^^^^ impl has extra requirement `T: const Bar` + | ^^^^^ impl has extra requirement `T: const Bar` error[E0276]: impl has stricter requirements than trait --> $DIR/predicate-entailment-fails.rs:32:26 @@ -41,7 +41,7 @@ LL | fn foo<T>() where T: Bar; | ------------------------- definition of `foo` from trait ... LL | fn foo<T>() where T: const Bar {} - | ^^^^^^^^^ impl has extra requirement `T: const Bar` + | ^^^^^ impl has extra requirement `T: const Bar` error[E0276]: impl has stricter requirements than trait --> $DIR/predicate-entailment-fails.rs:36:31 @@ -50,7 +50,7 @@ LL | type Bar<T> where T: Bar; | ----------- definition of `Bar` from trait ... LL | type Bar<T> = () where T: ~const Bar; - | ^^^^^^^^^^ impl has extra requirement `T: ~const Bar` + | ^^^^^^ impl has extra requirement `T: ~const Bar` error[E0276]: impl has stricter requirements than trait --> $DIR/predicate-entailment-fails.rs:39:26 @@ -59,7 +59,7 @@ LL | fn foo<T>() where T: Bar; | ------------------------- definition of `foo` from trait ... LL | fn foo<T>() where T: ~const Bar {} - | ^^^^^^^^^^ impl has extra requirement `T: ~const Bar` + | ^^^^^^ impl has extra requirement `T: ~const Bar` error: aborting due to 6 previous errors; 1 warning emitted diff --git a/tests/ui/traits/const-traits/specialization/const-default-impl-non-const-specialized-impl.stderr b/tests/ui/traits/const-traits/specialization/const-default-impl-non-const-specialized-impl.stderr index c51d169dd33..363fbee1f8b 100644 --- a/tests/ui/traits/const-traits/specialization/const-default-impl-non-const-specialized-impl.stderr +++ b/tests/ui/traits/const-traits/specialization/const-default-impl-non-const-specialized-impl.stderr @@ -7,16 +7,11 @@ LL | #![feature(const_trait_impl, effects)] = note: see issue #102090 <https://github.com/rust-lang/rust/issues/102090> for more information = note: `#[warn(incomplete_features)]` on by default -error: using `#![feature(effects)]` without enabling next trait solver globally - | - = note: the next trait solver must be enabled globally for the effects feature to work correctly - = help: use `-Znext-solver` to enable - error: cannot specialize on const impl with non-const impl --> $DIR/const-default-impl-non-const-specialized-impl.rs:19:1 | LL | impl Value for FortyTwo { | ^^^^^^^^^^^^^^^^^^^^^^^ -error: aborting due to 2 previous errors; 1 warning emitted +error: aborting due to 1 previous error; 1 warning emitted diff --git a/tests/ui/traits/const-traits/specializing-constness.stderr b/tests/ui/traits/const-traits/specializing-constness.stderr index e8c4fb0f0c7..226295bf949 100644 --- a/tests/ui/traits/const-traits/specializing-constness.stderr +++ b/tests/ui/traits/const-traits/specializing-constness.stderr @@ -7,16 +7,11 @@ LL | #![feature(const_trait_impl, effects, min_specialization, rustc_attrs)] = note: see issue #102090 <https://github.com/rust-lang/rust/issues/102090> for more information = note: `#[warn(incomplete_features)]` on by default -error: using `#![feature(effects)]` without enabling next trait solver globally - | - = note: the next trait solver must be enabled globally for the effects feature to work correctly - = help: use `-Znext-solver` to enable - error: cannot specialize on const impl with non-const impl --> $DIR/specializing-constness.rs:23:1 | LL | impl<T: Spec + Sup> A for T { | ^^^^^^^^^^^^^^^^^^^^^^^^^^^ -error: aborting due to 2 previous errors; 1 warning emitted +error: aborting due to 1 previous error; 1 warning emitted diff --git a/tests/ui/traits/const-traits/super-traits-fail-2.nn.stderr b/tests/ui/traits/const-traits/super-traits-fail-2.nn.stderr index 6277966b08e..8de1bb07e90 100644 --- a/tests/ui/traits/const-traits/super-traits-fail-2.nn.stderr +++ b/tests/ui/traits/const-traits/super-traits-fail-2.nn.stderr @@ -11,24 +11,24 @@ LL | trait Bar: ~const Foo {} | ^^^^^^^^^^^^^^^^^^^^^^^^ error: `~const` can only be applied to `#[const_trait]` traits - --> $DIR/super-traits-fail-2.rs:12:19 + --> $DIR/super-traits-fail-2.rs:12:12 | LL | trait Bar: ~const Foo {} - | ^^^ + | ^^^^^^ error: `~const` can only be applied to `#[const_trait]` traits - --> $DIR/super-traits-fail-2.rs:12:19 + --> $DIR/super-traits-fail-2.rs:12:12 | LL | trait Bar: ~const Foo {} - | ^^^ + | ^^^^^^ | = note: duplicate diagnostic emitted due to `-Z deduplicate-diagnostics=no` error: `~const` can only be applied to `#[const_trait]` traits - --> $DIR/super-traits-fail-2.rs:12:19 + --> $DIR/super-traits-fail-2.rs:12:12 | LL | trait Bar: ~const Foo {} - | ^^^ + | ^^^^^^ | = note: duplicate diagnostic emitted due to `-Z deduplicate-diagnostics=no` diff --git a/tests/ui/traits/const-traits/super-traits-fail-2.ny.stderr b/tests/ui/traits/const-traits/super-traits-fail-2.ny.stderr index 60660ecc279..82b306aeff6 100644 --- a/tests/ui/traits/const-traits/super-traits-fail-2.ny.stderr +++ b/tests/ui/traits/const-traits/super-traits-fail-2.ny.stderr @@ -1,38 +1,38 @@ error: `~const` can only be applied to `#[const_trait]` traits - --> $DIR/super-traits-fail-2.rs:12:19 + --> $DIR/super-traits-fail-2.rs:12:12 | LL | trait Bar: ~const Foo {} - | ^^^ + | ^^^^^^ error: `~const` can only be applied to `#[const_trait]` traits - --> $DIR/super-traits-fail-2.rs:12:19 + --> $DIR/super-traits-fail-2.rs:12:12 | LL | trait Bar: ~const Foo {} - | ^^^ + | ^^^^^^ | = note: duplicate diagnostic emitted due to `-Z deduplicate-diagnostics=no` error: `~const` can only be applied to `#[const_trait]` traits - --> $DIR/super-traits-fail-2.rs:12:19 + --> $DIR/super-traits-fail-2.rs:12:12 | LL | trait Bar: ~const Foo {} - | ^^^ + | ^^^^^^ | = note: duplicate diagnostic emitted due to `-Z deduplicate-diagnostics=no` error: `~const` can only be applied to `#[const_trait]` traits - --> $DIR/super-traits-fail-2.rs:12:19 + --> $DIR/super-traits-fail-2.rs:12:12 | LL | trait Bar: ~const Foo {} - | ^^^ + | ^^^^^^ | = note: duplicate diagnostic emitted due to `-Z deduplicate-diagnostics=no` error: `~const` can only be applied to `#[const_trait]` traits - --> $DIR/super-traits-fail-2.rs:12:19 + --> $DIR/super-traits-fail-2.rs:12:12 | LL | trait Bar: ~const Foo {} - | ^^^ + | ^^^^^^ | = note: duplicate diagnostic emitted due to `-Z deduplicate-diagnostics=no` diff --git a/tests/ui/traits/const-traits/super-traits-fail-3.nn.stderr b/tests/ui/traits/const-traits/super-traits-fail-3.nn.stderr index b39bf8d8e15..1dd4a2ed5a5 100644 --- a/tests/ui/traits/const-traits/super-traits-fail-3.nn.stderr +++ b/tests/ui/traits/const-traits/super-traits-fail-3.nn.stderr @@ -11,38 +11,38 @@ LL | trait Bar: ~const Foo {} | ^^^^^^^^^^^^^^^^^^^^^^^^ error: `~const` can only be applied to `#[const_trait]` traits - --> $DIR/super-traits-fail-3.rs:14:19 + --> $DIR/super-traits-fail-3.rs:14:12 | LL | trait Bar: ~const Foo {} - | ^^^ + | ^^^^^^ error: `~const` can only be applied to `#[const_trait]` traits - --> $DIR/super-traits-fail-3.rs:14:19 + --> $DIR/super-traits-fail-3.rs:14:12 | LL | trait Bar: ~const Foo {} - | ^^^ + | ^^^^^^ | = note: duplicate diagnostic emitted due to `-Z deduplicate-diagnostics=no` error: `~const` can only be applied to `#[const_trait]` traits - --> $DIR/super-traits-fail-3.rs:14:19 + --> $DIR/super-traits-fail-3.rs:14:12 | LL | trait Bar: ~const Foo {} - | ^^^ + | ^^^^^^ | = note: duplicate diagnostic emitted due to `-Z deduplicate-diagnostics=no` error: `~const` can only be applied to `#[const_trait]` traits - --> $DIR/super-traits-fail-3.rs:22:24 + --> $DIR/super-traits-fail-3.rs:22:17 | LL | const fn foo<T: ~const Bar>(x: &T) { - | ^^^ + | ^^^^^^ error: `~const` can only be applied to `#[const_trait]` traits - --> $DIR/super-traits-fail-3.rs:22:24 + --> $DIR/super-traits-fail-3.rs:22:17 | LL | const fn foo<T: ~const Bar>(x: &T) { - | ^^^ + | ^^^^^^ | = note: duplicate diagnostic emitted due to `-Z deduplicate-diagnostics=no` diff --git a/tests/ui/traits/const-traits/super-traits-fail-3.ny.stderr b/tests/ui/traits/const-traits/super-traits-fail-3.ny.stderr index 187cd998d95..e619b8bd6ba 100644 --- a/tests/ui/traits/const-traits/super-traits-fail-3.ny.stderr +++ b/tests/ui/traits/const-traits/super-traits-fail-3.ny.stderr @@ -1,38 +1,38 @@ error: `~const` can only be applied to `#[const_trait]` traits - --> $DIR/super-traits-fail-3.rs:14:19 + --> $DIR/super-traits-fail-3.rs:14:12 | LL | trait Bar: ~const Foo {} - | ^^^ + | ^^^^^^ error: `~const` can only be applied to `#[const_trait]` traits - --> $DIR/super-traits-fail-3.rs:14:19 + --> $DIR/super-traits-fail-3.rs:14:12 | LL | trait Bar: ~const Foo {} - | ^^^ + | ^^^^^^ | = note: duplicate diagnostic emitted due to `-Z deduplicate-diagnostics=no` error: `~const` can only be applied to `#[const_trait]` traits - --> $DIR/super-traits-fail-3.rs:14:19 + --> $DIR/super-traits-fail-3.rs:14:12 | LL | trait Bar: ~const Foo {} - | ^^^ + | ^^^^^^ | = note: duplicate diagnostic emitted due to `-Z deduplicate-diagnostics=no` error: `~const` can only be applied to `#[const_trait]` traits - --> $DIR/super-traits-fail-3.rs:14:19 + --> $DIR/super-traits-fail-3.rs:14:12 | LL | trait Bar: ~const Foo {} - | ^^^ + | ^^^^^^ | = note: duplicate diagnostic emitted due to `-Z deduplicate-diagnostics=no` error: `~const` can only be applied to `#[const_trait]` traits - --> $DIR/super-traits-fail-3.rs:14:19 + --> $DIR/super-traits-fail-3.rs:14:12 | LL | trait Bar: ~const Foo {} - | ^^^ + | ^^^^^^ | = note: duplicate diagnostic emitted due to `-Z deduplicate-diagnostics=no` diff --git a/tests/ui/traits/const-traits/super-traits-fail-3.yn.stderr b/tests/ui/traits/const-traits/super-traits-fail-3.yn.stderr index b6747d10e83..0a36d40d931 100644 --- a/tests/ui/traits/const-traits/super-traits-fail-3.yn.stderr +++ b/tests/ui/traits/const-traits/super-traits-fail-3.yn.stderr @@ -11,16 +11,16 @@ LL | trait Bar: ~const Foo {} | ^^^^^^^^^^^^^^^^^^^^^^^^ error: `~const` can only be applied to `#[const_trait]` traits - --> $DIR/super-traits-fail-3.rs:22:24 + --> $DIR/super-traits-fail-3.rs:22:17 | LL | const fn foo<T: ~const Bar>(x: &T) { - | ^^^ + | ^^^^^^ error: `~const` can only be applied to `#[const_trait]` traits - --> $DIR/super-traits-fail-3.rs:22:24 + --> $DIR/super-traits-fail-3.rs:22:17 | LL | const fn foo<T: ~const Bar>(x: &T) { - | ^^^ + | ^^^^^^ | = note: duplicate diagnostic emitted due to `-Z deduplicate-diagnostics=no` diff --git a/tests/ui/traits/const-traits/tilde-const-and-const-params.rs b/tests/ui/traits/const-traits/tilde-const-and-const-params.rs index f6a7c7c1746..b316ac75a8a 100644 --- a/tests/ui/traits/const-traits/tilde-const-and-const-params.rs +++ b/tests/ui/traits/const-traits/tilde-const-and-const-params.rs @@ -8,6 +8,7 @@ struct Foo<const N: usize>; impl<const N: usize> Foo<N> { fn add<A: ~const Add42>(self) -> Foo<{ A::add(N) }> { //~^ ERROR `~const` is not allowed here + //~| ERROR the trait bound `A: const Add42` is not satisfied Foo } } @@ -25,6 +26,7 @@ impl const Add42 for () { fn bar<A: ~const Add42, const N: usize>(_: Foo<N>) -> Foo<{ A::add(N) }> { //~^ ERROR `~const` is not allowed here + //~| ERROR the trait bound `A: const Add42` is not satisfied Foo } diff --git a/tests/ui/traits/const-traits/tilde-const-and-const-params.stderr b/tests/ui/traits/const-traits/tilde-const-and-const-params.stderr index 84a425f6791..78bf85e9c6d 100644 --- a/tests/ui/traits/const-traits/tilde-const-and-const-params.stderr +++ b/tests/ui/traits/const-traits/tilde-const-and-const-params.stderr @@ -11,21 +11,29 @@ LL | fn add<A: ~const Add42>(self) -> Foo<{ A::add(N) }> { | ^^^ error: `~const` is not allowed here - --> $DIR/tilde-const-and-const-params.rs:26:11 + --> $DIR/tilde-const-and-const-params.rs:27:11 | LL | fn bar<A: ~const Add42, const N: usize>(_: Foo<N>) -> Foo<{ A::add(N) }> { | ^^^^^^ | note: this function is not `const`, so it cannot have `~const` trait bounds - --> $DIR/tilde-const-and-const-params.rs:26:4 + --> $DIR/tilde-const-and-const-params.rs:27:4 | LL | fn bar<A: ~const Add42, const N: usize>(_: Foo<N>) -> Foo<{ A::add(N) }> { | ^^^ -error: using `#![feature(effects)]` without enabling next trait solver globally +error[E0277]: the trait bound `A: const Add42` is not satisfied + --> $DIR/tilde-const-and-const-params.rs:27:61 | - = note: the next trait solver must be enabled globally for the effects feature to work correctly - = help: use `-Znext-solver` to enable +LL | fn bar<A: ~const Add42, const N: usize>(_: Foo<N>) -> Foo<{ A::add(N) }> { + | ^^^^^^^^^ + +error[E0277]: the trait bound `A: const Add42` is not satisfied + --> $DIR/tilde-const-and-const-params.rs:9:44 + | +LL | fn add<A: ~const Add42>(self) -> Foo<{ A::add(N) }> { + | ^^^^^^^^^ -error: aborting due to 3 previous errors +error: aborting due to 4 previous errors +For more information about this error, try `rustc --explain E0277`. diff --git a/tests/ui/traits/const-traits/unsatisfied-const-trait-bound.stderr b/tests/ui/traits/const-traits/unsatisfied-const-trait-bound.stderr index e0cf062ad95..35f3019b6ee 100644 --- a/tests/ui/traits/const-traits/unsatisfied-const-trait-bound.stderr +++ b/tests/ui/traits/const-traits/unsatisfied-const-trait-bound.stderr @@ -28,7 +28,7 @@ note: required by a bound in `require` --> $DIR/unsatisfied-const-trait-bound.rs:8:15 | LL | fn require<T: const Trait>() {} - | ^^^^^^^^^^^ required by this bound in `require` + | ^^^^^ required by this bound in `require` error: aborting due to 4 previous errors diff --git a/tests/ui/traits/copy-impl-cannot-normalize.stderr b/tests/ui/traits/copy-impl-cannot-normalize.stderr index a98bb47f54f..3bdb8b70172 100644 --- a/tests/ui/traits/copy-impl-cannot-normalize.stderr +++ b/tests/ui/traits/copy-impl-cannot-normalize.stderr @@ -2,7 +2,7 @@ error[E0277]: the trait bound `T: TraitFoo` is not satisfied --> $DIR/copy-impl-cannot-normalize.rs:22:18 | LL | impl<T> Copy for Foo<T> {} - | ^^^^^^ the trait `TraitFoo` is not implemented for `T`, which is required by `Foo<T>: Clone` + | ^^^^^^ the trait `TraitFoo` is not implemented for `T` | note: required for `Foo<T>` to implement `Clone` --> $DIR/copy-impl-cannot-normalize.rs:12:9 diff --git a/tests/ui/traits/dont-autoderef-ty-with-escaping-var.stderr b/tests/ui/traits/dont-autoderef-ty-with-escaping-var.stderr index fecb05cade7..a5d0e6ab095 100644 --- a/tests/ui/traits/dont-autoderef-ty-with-escaping-var.stderr +++ b/tests/ui/traits/dont-autoderef-ty-with-escaping-var.stderr @@ -8,7 +8,7 @@ error[E0277]: the trait bound `for<'a> &'a mut Vec<&'a u32>: Foo<'static, i32>` --> $DIR/dont-autoderef-ty-with-escaping-var.rs:17:6 | LL | <i32 as RefFoo<i32>>::ref_foo(unknown); - | ^^^ the trait `for<'a> Foo<'static, i32>` is not implemented for `&'a mut Vec<&'a u32>`, which is required by `i32: RefFoo<i32>` + | ^^^ the trait `for<'a> Foo<'static, i32>` is not implemented for `&'a mut Vec<&'a u32>` | help: this trait has no implementations, consider adding one --> $DIR/dont-autoderef-ty-with-escaping-var.rs:3:1 diff --git a/tests/ui/traits/inductive-overflow/supertrait-auto-trait.stderr b/tests/ui/traits/inductive-overflow/supertrait-auto-trait.stderr index 17fced307ed..07edc4ede76 100644 --- a/tests/ui/traits/inductive-overflow/supertrait-auto-trait.stderr +++ b/tests/ui/traits/inductive-overflow/supertrait-auto-trait.stderr @@ -10,7 +10,7 @@ error[E0277]: the trait bound `NoClone: Magic` is not satisfied --> $DIR/supertrait-auto-trait.rs:16:23 | LL | let (a, b) = copy(NoClone); - | ---- ^^^^^^^ the trait `Copy` is not implemented for `NoClone`, which is required by `NoClone: Magic` + | ---- ^^^^^^^ the trait `Copy` is not implemented for `NoClone` | | | required by a bound introduced by this call | diff --git a/tests/ui/traits/issue-43784-supertrait.stderr b/tests/ui/traits/issue-43784-supertrait.stderr index 4c565c3fa1d..2bf365745a6 100644 --- a/tests/ui/traits/issue-43784-supertrait.stderr +++ b/tests/ui/traits/issue-43784-supertrait.stderr @@ -2,7 +2,7 @@ error[E0277]: the trait bound `T: Copy` is not satisfied --> $DIR/issue-43784-supertrait.rs:8:22 | LL | impl<T> Complete for T {} - | ^ the trait `Copy` is not implemented for `T`, which is required by `T: Partial` + | ^ the trait `Copy` is not implemented for `T` | note: required for `T` to implement `Partial` --> $DIR/issue-43784-supertrait.rs:1:11 diff --git a/tests/ui/traits/issue-7013.stderr b/tests/ui/traits/issue-7013.stderr index 5067c7d7dd7..17493663172 100644 --- a/tests/ui/traits/issue-7013.stderr +++ b/tests/ui/traits/issue-7013.stderr @@ -4,7 +4,7 @@ error[E0277]: `Rc<RefCell<A>>` cannot be sent between threads safely LL | let a = A {v: Box::new(B{v: None}) as Box<dyn Foo + Send>}; | ^^^^^^^^^^^^^^^^^^^^ `Rc<RefCell<A>>` cannot be sent between threads safely | - = help: within `B`, the trait `Send` is not implemented for `Rc<RefCell<A>>`, which is required by `B: Send` + = help: within `B`, the trait `Send` is not implemented for `Rc<RefCell<A>>` note: required because it appears within the type `Option<Rc<RefCell<A>>>` --> $SRC_DIR/core/src/option.rs:LL:COL note: required because it appears within the type `B` diff --git a/tests/ui/traits/issue-71036.stderr b/tests/ui/traits/issue-71036.stderr index 35d543eb017..2452731f19f 100644 --- a/tests/ui/traits/issue-71036.stderr +++ b/tests/ui/traits/issue-71036.stderr @@ -2,7 +2,7 @@ error[E0277]: the trait bound `&'a T: Unsize<&'a U>` is not satisfied --> $DIR/issue-71036.rs:11:1 | LL | impl<'a, T: ?Sized + Unsize<U>, U: ?Sized> DispatchFromDyn<Foo<'a, U>> for Foo<'a, T> {} - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ the trait `Unsize<&'a U>` is not implemented for `&'a T`, which is required by `&'a &'a T: DispatchFromDyn<&'a &'a U>` + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ the trait `Unsize<&'a U>` is not implemented for `&'a T` | = note: all implementations of `Unsize` are provided automatically by the compiler, see <https://doc.rust-lang.org/stable/std/marker/trait.Unsize.html> for more information = note: required for `&'a &'a T` to implement `DispatchFromDyn<&'a &'a U>` diff --git a/tests/ui/traits/issue-71136.stderr b/tests/ui/traits/issue-71136.stderr index d37ad8ae34d..2c03c6bf08e 100644 --- a/tests/ui/traits/issue-71136.stderr +++ b/tests/ui/traits/issue-71136.stderr @@ -5,7 +5,7 @@ LL | #[derive(Clone)] | ----- in this derive macro expansion LL | struct FooHolster { LL | the_foos: Vec<Foo>, - | ^^^^^^^^^^^^^^^^^^ the trait `Clone` is not implemented for `Foo`, which is required by `Vec<Foo>: Clone` + | ^^^^^^^^^^^^^^^^^^ the trait `Clone` is not implemented for `Foo` | = note: required for `Vec<Foo>` to implement `Clone` = note: this error originates in the derive macro `Clone` (in Nightly builds, run with -Z macro-backtrace for more info) diff --git a/tests/ui/traits/issue-91594.stderr b/tests/ui/traits/issue-91594.stderr index 726ee5b6146..13568179e81 100644 --- a/tests/ui/traits/issue-91594.stderr +++ b/tests/ui/traits/issue-91594.stderr @@ -2,7 +2,7 @@ error[E0277]: the trait bound `Foo: HasComponent<()>` is not satisfied --> $DIR/issue-91594.rs:10:19 | LL | impl HasComponent<<Foo as Component<Foo>>::Interface> for Foo {} - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ the trait `HasComponent<()>` is not implemented for `Foo`, which is required by `Foo: Component<Foo>` + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ the trait `HasComponent<()>` is not implemented for `Foo` | = help: the trait `HasComponent<<Foo as Component<Foo>>::Interface>` is implemented for `Foo` note: required for `Foo` to implement `Component<Foo>` diff --git a/tests/ui/traits/issue-97576.stderr b/tests/ui/traits/issue-97576.stderr index bee254461f1..2c6cfd83b95 100644 --- a/tests/ui/traits/issue-97576.stderr +++ b/tests/ui/traits/issue-97576.stderr @@ -2,7 +2,7 @@ error[E0277]: the trait bound `String: From<impl ToString>` is not satisfied --> $DIR/issue-97576.rs:8:22 | LL | bar: bar.into(), - | ^^^^ the trait `From<impl ToString>` is not implemented for `String`, which is required by `impl ToString: Into<_>` + | ^^^^ the trait `From<impl ToString>` is not implemented for `String` | = note: required for `impl ToString` to implement `Into<String>` diff --git a/tests/ui/traits/negative-impls/negated-auto-traits-error.stderr b/tests/ui/traits/negative-impls/negated-auto-traits-error.stderr index 2a3833beb26..8f5b937e586 100644 --- a/tests/ui/traits/negative-impls/negated-auto-traits-error.stderr +++ b/tests/ui/traits/negative-impls/negated-auto-traits-error.stderr @@ -49,7 +49,7 @@ LL | is_send((8, TestType)); | | | required by a bound introduced by this call | - = help: within `({integer}, dummy1c::TestType)`, the trait `Send` is not implemented for `dummy1c::TestType`, which is required by `({integer}, dummy1c::TestType): Send` + = help: within `({integer}, dummy1c::TestType)`, the trait `Send` is not implemented for `dummy1c::TestType` = note: required because it appears within the type `({integer}, dummy1c::TestType)` note: required by a bound in `is_send` --> $DIR/negated-auto-traits-error.rs:16:15 @@ -87,7 +87,7 @@ LL | is_send(Box::new(Outer2(TestType))); | | | required by a bound introduced by this call | - = help: within `Outer2<dummy3::TestType>`, the trait `Send` is not implemented for `dummy3::TestType`, which is required by `Box<Outer2<dummy3::TestType>>: Send` + = help: within `Outer2<dummy3::TestType>`, the trait `Send` is not implemented for `dummy3::TestType` note: required because it appears within the type `Outer2<dummy3::TestType>` --> $DIR/negated-auto-traits-error.rs:12:8 | @@ -110,7 +110,7 @@ LL | is_sync(Outer2(TestType)); | | | required by a bound introduced by this call | - = help: the trait `Send` is not implemented for `main::TestType`, which is required by `Outer2<main::TestType>: Sync` + = help: the trait `Send` is not implemented for `main::TestType` note: required for `Outer2<main::TestType>` to implement `Sync` --> $DIR/negated-auto-traits-error.rs:14:22 | diff --git a/tests/ui/traits/next-solver/auto-with-drop_tracking_mir.fail.stderr b/tests/ui/traits/next-solver/auto-with-drop_tracking_mir.fail.stderr index c2029a5a1c8..55f52181ec9 100644 --- a/tests/ui/traits/next-solver/auto-with-drop_tracking_mir.fail.stderr +++ b/tests/ui/traits/next-solver/auto-with-drop_tracking_mir.fail.stderr @@ -4,7 +4,7 @@ error: future cannot be sent between threads safely LL | is_send(foo()); | ^^^^^ future returned by `foo` is not `Send` | - = help: the trait `Sync` is not implemented for `NotSync`, which is required by `impl Future<Output = ()>: Send` + = help: the trait `Sync` is not implemented for `NotSync` note: future is not `Send` as this value is used across an await --> $DIR/auto-with-drop_tracking_mir.rs:16:11 | diff --git a/tests/ui/traits/next-solver/builtin-fn-must-return-sized.stderr b/tests/ui/traits/next-solver/builtin-fn-must-return-sized.stderr index b487ceef1d4..bb39d110777 100644 --- a/tests/ui/traits/next-solver/builtin-fn-must-return-sized.stderr +++ b/tests/ui/traits/next-solver/builtin-fn-must-return-sized.stderr @@ -4,7 +4,7 @@ error[E0277]: the size for values of type `str` cannot be known at compilation t LL | foo::<fn() -> str, _>(None, ()); | ^^^^^^^^^^^ doesn't have a size known at compile-time | - = help: within `fn() -> str`, the trait `Sized` is not implemented for `str`, which is required by `fn() -> str: Fn<_>` + = help: within `fn() -> str`, the trait `Sized` is not implemented for `str` = note: required because it appears within the type `fn() -> str` note: required by a bound in `foo` --> $DIR/builtin-fn-must-return-sized.rs:10:11 diff --git a/tests/ui/traits/next-solver/cycles/coinduction/incompleteness-unstable-result.with.stderr b/tests/ui/traits/next-solver/cycles/coinduction/incompleteness-unstable-result.with.stderr index a81229e5e35..9114bcadac0 100644 --- a/tests/ui/traits/next-solver/cycles/coinduction/incompleteness-unstable-result.with.stderr +++ b/tests/ui/traits/next-solver/cycles/coinduction/incompleteness-unstable-result.with.stderr @@ -2,7 +2,7 @@ error[E0277]: the trait bound `A<X>: Trait<_, _, _>` is not satisfied --> $DIR/incompleteness-unstable-result.rs:65:19 | LL | impls_trait::<A<X>, _, _, _>(); - | ^^^^ the trait `Trait<_, _, _>` is not implemented for `A<X>`, which is required by `A<X>: Trait<_, _, _>` + | ^^^^ the trait `Trait<_, _, _>` is not implemented for `A<X>` | = help: the trait `Trait<U, V, D>` is implemented for `A<T>` note: required for `A<X>` to implement `Trait<_, _, _>` diff --git a/tests/ui/traits/next-solver/cycles/coinduction/incompleteness-unstable-result.without.stderr b/tests/ui/traits/next-solver/cycles/coinduction/incompleteness-unstable-result.without.stderr index a81229e5e35..9114bcadac0 100644 --- a/tests/ui/traits/next-solver/cycles/coinduction/incompleteness-unstable-result.without.stderr +++ b/tests/ui/traits/next-solver/cycles/coinduction/incompleteness-unstable-result.without.stderr @@ -2,7 +2,7 @@ error[E0277]: the trait bound `A<X>: Trait<_, _, _>` is not satisfied --> $DIR/incompleteness-unstable-result.rs:65:19 | LL | impls_trait::<A<X>, _, _, _>(); - | ^^^^ the trait `Trait<_, _, _>` is not implemented for `A<X>`, which is required by `A<X>: Trait<_, _, _>` + | ^^^^ the trait `Trait<_, _, _>` is not implemented for `A<X>` | = help: the trait `Trait<U, V, D>` is implemented for `A<T>` note: required for `A<X>` to implement `Trait<_, _, _>` diff --git a/tests/ui/traits/next-solver/diagnostics/point-at-failing-nested.stderr b/tests/ui/traits/next-solver/diagnostics/point-at-failing-nested.stderr index 9a18a58debd..a841618ec6f 100644 --- a/tests/ui/traits/next-solver/diagnostics/point-at-failing-nested.stderr +++ b/tests/ui/traits/next-solver/diagnostics/point-at-failing-nested.stderr @@ -2,7 +2,7 @@ error[E0277]: the trait bound `(): Foo` is not satisfied --> $DIR/point-at-failing-nested.rs:22:17 | LL | needs_foo::<()>(); - | ^^ the trait `Bar` is not implemented for `()`, which is required by `(): Foo` + | ^^ the trait `Bar` is not implemented for `()` | help: this trait has no implementations, consider adding one --> $DIR/point-at-failing-nested.rs:4:1 diff --git a/tests/ui/traits/next-solver/diagnostics/where-clause-doesnt-apply.stderr b/tests/ui/traits/next-solver/diagnostics/where-clause-doesnt-apply.stderr index ab1d4a56c02..29703679a86 100644 --- a/tests/ui/traits/next-solver/diagnostics/where-clause-doesnt-apply.stderr +++ b/tests/ui/traits/next-solver/diagnostics/where-clause-doesnt-apply.stderr @@ -2,7 +2,7 @@ error[E0277]: the trait bound `(): Foo` is not satisfied --> $DIR/where-clause-doesnt-apply.rs:18:15 | LL | needs_foo(()); - | --------- ^^ the trait `Bar` is not implemented for `()`, which is required by `(): Foo` + | --------- ^^ the trait `Bar` is not implemented for `()` | | | required by a bound introduced by this call | diff --git a/tests/ui/traits/next-solver/dyn-incompatibility.stderr b/tests/ui/traits/next-solver/dyn-incompatibility.stderr index 7f2c0646ef5..a720797efc4 100644 --- a/tests/ui/traits/next-solver/dyn-incompatibility.stderr +++ b/tests/ui/traits/next-solver/dyn-incompatibility.stderr @@ -2,7 +2,7 @@ error[E0277]: the trait bound `T: Copy` is not satisfied in `dyn Setup<From = T> --> $DIR/dyn-incompatibility.rs:12:12 | LL | copy::<dyn Setup<From=T>>(t) - | ^^^^^^^^^^^^^^^^^ within `dyn Setup<From = T>`, the trait `Copy` is not implemented for `T`, which is required by `dyn Setup<From = T>: Setup` + | ^^^^^^^^^^^^^^^^^ within `dyn Setup<From = T>`, the trait `Copy` is not implemented for `T` | = note: required because it appears within the type `dyn Setup<From = T>` note: required by a bound in `copy` @@ -35,7 +35,7 @@ error[E0277]: the trait bound `T: Copy` is not satisfied in `dyn Setup<From = T> --> $DIR/dyn-incompatibility.rs:12:5 | LL | copy::<dyn Setup<From=T>>(t) - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^ within `dyn Setup<From = T>`, the trait `Copy` is not implemented for `T`, which is required by `dyn Setup<From = T>: Setup` + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^ within `dyn Setup<From = T>`, the trait `Copy` is not implemented for `T` | = note: required because it appears within the type `dyn Setup<From = T>` help: consider restricting type parameter `T` diff --git a/tests/ui/traits/next-solver/global-cache-and-parallel-frontend.stderr b/tests/ui/traits/next-solver/global-cache-and-parallel-frontend.stderr index 65e7dd2ab34..1f319cc6743 100644 --- a/tests/ui/traits/next-solver/global-cache-and-parallel-frontend.stderr +++ b/tests/ui/traits/next-solver/global-cache-and-parallel-frontend.stderr @@ -2,7 +2,7 @@ error[E0277]: the trait bound `T: Clone` is not satisfied --> $DIR/global-cache-and-parallel-frontend.rs:15:17 | LL | #[derive(Clone, Eq)] - | ^^ the trait `Clone` is not implemented for `T`, which is required by `Struct<T>: PartialEq` + | ^^ the trait `Clone` is not implemented for `T` | note: required for `Struct<T>` to implement `PartialEq` --> $DIR/global-cache-and-parallel-frontend.rs:18:19 diff --git a/tests/ui/traits/non_lifetime_binders/bad-sized-cond.stderr b/tests/ui/traits/non_lifetime_binders/bad-sized-cond.stderr index f7d5d6fcee4..f4deb169516 100644 --- a/tests/ui/traits/non_lifetime_binders/bad-sized-cond.stderr +++ b/tests/ui/traits/non_lifetime_binders/bad-sized-cond.stderr @@ -29,7 +29,7 @@ error[E0277]: `V` is not an iterator LL | bar(); | ^^^^^ `V` is not an iterator | - = help: the trait `Iterator` is not implemented for `V`, which is required by `V: IntoIterator` + = help: the trait `Iterator` is not implemented for `V` = note: required for `V` to implement `IntoIterator` note: required by a bound in `bar` --> $DIR/bad-sized-cond.rs:12:15 @@ -46,7 +46,7 @@ error[E0277]: the size for values of type `V` cannot be known at compilation tim LL | bar(); | ^^^^^ doesn't have a size known at compile-time | - = help: the trait `Sized` is not implemented for `V`, which is required by `V: IntoIterator` + = help: the trait `Sized` is not implemented for `V` = note: required for `V` to implement `IntoIterator` note: required by a bound in `bar` --> $DIR/bad-sized-cond.rs:12:15 diff --git a/tests/ui/traits/question-mark-result-err-mismatch.stderr b/tests/ui/traits/question-mark-result-err-mismatch.stderr index 0e0ae6d5990..bad325a6720 100644 --- a/tests/ui/traits/question-mark-result-err-mismatch.stderr +++ b/tests/ui/traits/question-mark-result-err-mismatch.stderr @@ -11,7 +11,7 @@ LL | | e; LL | | }) | |__________- this can't be annotated with `?` because it has type `Result<_, ()>` LL | .map(|()| "")?; - | ^ the trait `From<()>` is not implemented for `String`, which is required by `Result<String, String>: FromResidual<Result<Infallible, ()>>` + | ^ the trait `From<()>` is not implemented for `String` | = note: the question mark operation (`?`) implicitly performs a conversion on the error value using the `From` trait = note: required for `Result<String, String>` to implement `FromResidual<Result<Infallible, ()>>` @@ -25,7 +25,7 @@ LL | let x = foo(); | ----- this has type `Result<_, String>` ... LL | .map_err(|_| ())?; - | ---------------^ the trait `From<()>` is not implemented for `String`, which is required by `Result<(), String>: FromResidual<Result<Infallible, ()>>` + | ---------------^ the trait `From<()>` is not implemented for `String` | | | this can't be annotated with `?` because it has type `Result<_, ()>` | @@ -50,7 +50,7 @@ LL | .ok_or_else(|| { LL | | "Couldn't split the test string"; | | - help: remove this semicolon LL | | })?; - | | -^ the trait `From<()>` is not implemented for `String`, which is required by `Result<String, String>: FromResidual<Result<Infallible, ()>>` + | | -^ the trait `From<()>` is not implemented for `String` | |__________| | this can't be annotated with `?` because it has type `Result<_, ()>` | diff --git a/tests/ui/traits/suggest-dereferences/dont-suggest-unsize-deref.stderr b/tests/ui/traits/suggest-dereferences/dont-suggest-unsize-deref.stderr index 28a0646a86b..8024ad28d5a 100644 --- a/tests/ui/traits/suggest-dereferences/dont-suggest-unsize-deref.stderr +++ b/tests/ui/traits/suggest-dereferences/dont-suggest-unsize-deref.stderr @@ -6,7 +6,7 @@ LL | use_iterator(i); | | | required by a bound introduced by this call | - = help: the trait `Iterator` is not implemented for `&dyn IntoIterator<IntoIter = I, Item = i32>`, which is required by `&dyn IntoIterator<IntoIter = I, Item = i32>: IntoIterator` + = help: the trait `Iterator` is not implemented for `&dyn IntoIterator<IntoIter = I, Item = i32>` = note: required for `&dyn IntoIterator<IntoIter = I, Item = i32>` to implement `IntoIterator` note: required by a bound in `use_iterator` --> $DIR/dont-suggest-unsize-deref.rs:3:8 diff --git a/tests/ui/traits/suggest-dereferences/invalid-suggest-deref-issue-127590.stderr b/tests/ui/traits/suggest-dereferences/invalid-suggest-deref-issue-127590.stderr index 85d6cdf779b..f0957e5cd9f 100644 --- a/tests/ui/traits/suggest-dereferences/invalid-suggest-deref-issue-127590.stderr +++ b/tests/ui/traits/suggest-dereferences/invalid-suggest-deref-issue-127590.stderr @@ -6,7 +6,7 @@ LL | for (src, dest) in std::iter::zip(fields.iter(), &variant.iter()) { | | | required by a bound introduced by this call | - = help: the trait `Iterator` is not implemented for `&std::slice::Iter<'_, {integer}>`, which is required by `&std::slice::Iter<'_, {integer}>: IntoIterator` + = help: the trait `Iterator` is not implemented for `&std::slice::Iter<'_, {integer}>` = note: required for `&std::slice::Iter<'_, {integer}>` to implement `IntoIterator` note: required by a bound in `std::iter::zip` --> $SRC_DIR/core/src/iter/adapters/zip.rs:LL:COL @@ -22,7 +22,7 @@ error[E0277]: `&std::slice::Iter<'_, {integer}>` is not an iterator LL | for (src, dest) in std::iter::zip(fields.iter(), &variant.iter()) { | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ `&std::slice::Iter<'_, {integer}>` is not an iterator | - = help: the trait `Iterator` is not implemented for `&std::slice::Iter<'_, {integer}>`, which is required by `Zip<std::slice::Iter<'_, {integer}>, &std::slice::Iter<'_, {integer}>>: IntoIterator` + = help: the trait `Iterator` is not implemented for `&std::slice::Iter<'_, {integer}>` = help: the trait `Iterator` is implemented for `std::slice::Iter<'_, T>` = note: required for `Zip<std::slice::Iter<'_, {integer}>, &std::slice::Iter<'_, {integer}>>` to implement `Iterator` = note: required for `Zip<std::slice::Iter<'_, {integer}>, &std::slice::Iter<'_, {integer}>>` to implement `IntoIterator` @@ -35,7 +35,7 @@ LL | for (src, dest) in std::iter::zip(fields.iter(), &variant.iter().clone( | | | required by a bound introduced by this call | - = help: the trait `Iterator` is not implemented for `&std::slice::Iter<'_, {integer}>`, which is required by `&std::slice::Iter<'_, {integer}>: IntoIterator` + = help: the trait `Iterator` is not implemented for `&std::slice::Iter<'_, {integer}>` = note: required for `&std::slice::Iter<'_, {integer}>` to implement `IntoIterator` note: required by a bound in `std::iter::zip` --> $SRC_DIR/core/src/iter/adapters/zip.rs:LL:COL @@ -51,7 +51,7 @@ error[E0277]: `&std::slice::Iter<'_, {integer}>` is not an iterator LL | for (src, dest) in std::iter::zip(fields.iter(), &variant.iter().clone()) { | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ `&std::slice::Iter<'_, {integer}>` is not an iterator | - = help: the trait `Iterator` is not implemented for `&std::slice::Iter<'_, {integer}>`, which is required by `Zip<std::slice::Iter<'_, {integer}>, &std::slice::Iter<'_, {integer}>>: IntoIterator` + = help: the trait `Iterator` is not implemented for `&std::slice::Iter<'_, {integer}>` = help: the trait `Iterator` is implemented for `std::slice::Iter<'_, T>` = note: required for `Zip<std::slice::Iter<'_, {integer}>, &std::slice::Iter<'_, {integer}>>` to implement `Iterator` = note: required for `Zip<std::slice::Iter<'_, {integer}>, &std::slice::Iter<'_, {integer}>>` to implement `IntoIterator` diff --git a/tests/ui/traits/suggest-dereferences/issue-39029.stderr b/tests/ui/traits/suggest-dereferences/issue-39029.stderr index 0eea6cbcc5a..fd45fa3cf74 100644 --- a/tests/ui/traits/suggest-dereferences/issue-39029.stderr +++ b/tests/ui/traits/suggest-dereferences/issue-39029.stderr @@ -2,7 +2,7 @@ error[E0277]: the trait bound `NoToSocketAddrs: ToSocketAddrs` is not satisfied --> $DIR/issue-39029.rs:16:38 | LL | let _errors = TcpListener::bind(&bad); - | ----------------- ^^^ the trait `ToSocketAddrs` is not implemented for `NoToSocketAddrs`, which is required by `&NoToSocketAddrs: ToSocketAddrs` + | ----------------- ^^^ the trait `ToSocketAddrs` is not implemented for `NoToSocketAddrs` | | | required by a bound introduced by this call | diff --git a/tests/ui/traits/suggest-dereferences/root-obligation.stderr b/tests/ui/traits/suggest-dereferences/root-obligation.stderr index 2f5e1c5b537..dafd3469b6f 100644 --- a/tests/ui/traits/suggest-dereferences/root-obligation.stderr +++ b/tests/ui/traits/suggest-dereferences/root-obligation.stderr @@ -2,7 +2,7 @@ error[E0277]: the trait bound `&char: Pattern` is not satisfied --> $DIR/root-obligation.rs:6:38 | LL | .filter(|c| "aeiou".contains(c)) - | -------- ^ the trait `Fn(char)` is not implemented for `char`, which is required by `&char: Pattern` + | -------- ^ the trait `Fn(char)` is not implemented for `char` | | | required by a bound introduced by this call | diff --git a/tests/ui/traits/suggest-dereferences/suggest-dereferencing-receiver-argument.stderr b/tests/ui/traits/suggest-dereferences/suggest-dereferencing-receiver-argument.stderr index d1d75625aba..d6033bc6baa 100644 --- a/tests/ui/traits/suggest-dereferences/suggest-dereferencing-receiver-argument.stderr +++ b/tests/ui/traits/suggest-dereferences/suggest-dereferencing-receiver-argument.stderr @@ -2,7 +2,7 @@ error[E0277]: the trait bound `TargetStruct: From<&{integer}>` is not satisfied --> $DIR/suggest-dereferencing-receiver-argument.rs:13:30 | LL | let _b: TargetStruct = a.into(); - | ^^^^ the trait `From<&{integer}>` is not implemented for `TargetStruct`, which is required by `&{integer}: Into<_>` + | ^^^^ the trait `From<&{integer}>` is not implemented for `TargetStruct` | = note: required for `&{integer}` to implement `Into<TargetStruct>` help: consider dereferencing here diff --git a/tests/ui/traits/unsend-future.stderr b/tests/ui/traits/unsend-future.stderr index 4462208cb49..25df3419794 100644 --- a/tests/ui/traits/unsend-future.stderr +++ b/tests/ui/traits/unsend-future.stderr @@ -4,7 +4,7 @@ error: future cannot be sent between threads safely LL | require_handler(handler) | ^^^^^^^ future returned by `handler` is not `Send` | - = help: within `impl Future<Output = ()>`, the trait `Send` is not implemented for `*const i32`, which is required by `fn() -> impl Future<Output = ()> {handler}: Handler` + = help: within `impl Future<Output = ()>`, the trait `Send` is not implemented for `*const i32` note: future is not `Send` as this value is used across an await --> $DIR/unsend-future.rs:15:14 | diff --git a/tests/ui/try-block/try-block-bad-type.stderr b/tests/ui/try-block/try-block-bad-type.stderr index e9e6255cd2a..d94962e4031 100644 --- a/tests/ui/try-block/try-block-bad-type.stderr +++ b/tests/ui/try-block/try-block-bad-type.stderr @@ -2,7 +2,7 @@ error[E0277]: `?` couldn't convert the error to `TryFromSliceError` --> $DIR/try-block-bad-type.rs:7:16 | LL | Err("")?; - | -------^ the trait `From<&str>` is not implemented for `TryFromSliceError`, which is required by `Result<u32, TryFromSliceError>: FromResidual<Result<Infallible, &str>>` + | -------^ the trait `From<&str>` is not implemented for `TryFromSliceError` | | | this can't be annotated with `?` because it has type `Result<_, &str>` | diff --git a/tests/ui/try-trait/bad-interconversion.stderr b/tests/ui/try-trait/bad-interconversion.stderr index 82877baef3e..fe28912ba00 100644 --- a/tests/ui/try-trait/bad-interconversion.stderr +++ b/tests/ui/try-trait/bad-interconversion.stderr @@ -4,7 +4,7 @@ error[E0277]: `?` couldn't convert the error to `u8` LL | fn result_to_result() -> Result<u64, u8> { | --------------- expected `u8` because of this LL | Ok(Err(123_i32)?) - | ------------^ the trait `From<i32>` is not implemented for `u8`, which is required by `Result<u64, u8>: FromResidual<Result<Infallible, i32>>` + | ------------^ the trait `From<i32>` is not implemented for `u8` | | | this can't be annotated with `?` because it has type `Result<_, i32>` | diff --git a/tests/ui/try-trait/issue-32709.stderr b/tests/ui/try-trait/issue-32709.stderr index 9b77f578437..475bd1ff3ac 100644 --- a/tests/ui/try-trait/issue-32709.stderr +++ b/tests/ui/try-trait/issue-32709.stderr @@ -4,7 +4,7 @@ error[E0277]: `?` couldn't convert the error to `()` LL | fn a() -> Result<i32, ()> { | --------------- expected `()` because of this LL | Err(5)?; - | ------^ the trait `From<{integer}>` is not implemented for `()`, which is required by `Result<i32, ()>: FromResidual<Result<Infallible, {integer}>>` + | ------^ the trait `From<{integer}>` is not implemented for `()` | | | this can't be annotated with `?` because it has type `Result<_, {integer}>` | diff --git a/tests/ui/type-alias-impl-trait/auto-trait-leakage2.stderr b/tests/ui/type-alias-impl-trait/auto-trait-leakage2.stderr index 5c5506fb853..2ed918eca17 100644 --- a/tests/ui/type-alias-impl-trait/auto-trait-leakage2.stderr +++ b/tests/ui/type-alias-impl-trait/auto-trait-leakage2.stderr @@ -9,7 +9,7 @@ LL | is_send(m::foo()); | | | required by a bound introduced by this call | - = help: within `Foo`, the trait `Send` is not implemented for `Rc<u32>`, which is required by `Foo: Send` + = help: within `Foo`, the trait `Send` is not implemented for `Rc<u32>` note: required because it appears within the type `Foo` --> $DIR/auto-trait-leakage2.rs:7:16 | diff --git a/tests/ui/type-alias-impl-trait/escaping-bound-var.rs b/tests/ui/type-alias-impl-trait/escaping-bound-var.rs index 1ff200680be..07206dd2491 100644 --- a/tests/ui/type-alias-impl-trait/escaping-bound-var.rs +++ b/tests/ui/type-alias-impl-trait/escaping-bound-var.rs @@ -8,6 +8,7 @@ trait Test<'a> {} pub type Foo = impl for<'a> Trait<'a, Assoc = impl Test<'a>>; //~^ ERROR `impl Trait` cannot capture higher-ranked lifetime from outer `impl Trait` +//~| ERROR `impl Trait` cannot capture higher-ranked lifetime from outer `impl Trait` impl Trait<'_> for () { type Assoc = (); diff --git a/tests/ui/type-alias-impl-trait/escaping-bound-var.stderr b/tests/ui/type-alias-impl-trait/escaping-bound-var.stderr index 09f6fba79cf..c9f0618639a 100644 --- a/tests/ui/type-alias-impl-trait/escaping-bound-var.stderr +++ b/tests/ui/type-alias-impl-trait/escaping-bound-var.stderr @@ -10,6 +10,18 @@ note: lifetime declared here LL | pub type Foo = impl for<'a> Trait<'a, Assoc = impl Test<'a>>; | ^^ -error: aborting due to 1 previous error +error[E0657]: `impl Trait` cannot capture higher-ranked lifetime from outer `impl Trait` + --> $DIR/escaping-bound-var.rs:9:57 + | +LL | pub type Foo = impl for<'a> Trait<'a, Assoc = impl Test<'a>>; + | ^^ + | +note: lifetime declared here + --> $DIR/escaping-bound-var.rs:9:25 + | +LL | pub type Foo = impl for<'a> Trait<'a, Assoc = impl Test<'a>>; + | ^^ + +error: aborting due to 2 previous errors For more information about this error, try `rustc --explain E0657`. diff --git a/tests/ui/type-alias-impl-trait/issue-57700.rs b/tests/ui/type-alias-impl-trait/issue-57700.rs deleted file mode 100644 index 8746545ecc9..00000000000 --- a/tests/ui/type-alias-impl-trait/issue-57700.rs +++ /dev/null @@ -1,21 +0,0 @@ -#![feature(arbitrary_self_types)] -#![feature(impl_trait_in_assoc_type)] - -use std::ops::Deref; - -trait Foo { - type Bar: Foo; - - fn foo(self: impl Deref<Target = Self>) -> Self::Bar; -} - -impl<C> Foo for C { - type Bar = impl Foo; - - fn foo(self: impl Deref<Target = Self>) -> Self::Bar { - self - //~^ Error type parameter `impl Deref<Target = Self>` is part of concrete type but not used in parameter list for the `impl Trait` type alias - } -} - -fn main() {} diff --git a/tests/ui/type-alias-impl-trait/issue-57700.stderr b/tests/ui/type-alias-impl-trait/issue-57700.stderr deleted file mode 100644 index 7efb05f40b0..00000000000 --- a/tests/ui/type-alias-impl-trait/issue-57700.stderr +++ /dev/null @@ -1,8 +0,0 @@ -error: type parameter `impl Deref<Target = Self>` is part of concrete type but not used in parameter list for the `impl Trait` type alias - --> $DIR/issue-57700.rs:16:9 - | -LL | self - | ^^^^ - -error: aborting due to 1 previous error - diff --git a/tests/ui/type-alias-impl-trait/multiple-def-uses-in-one-fn.stderr b/tests/ui/type-alias-impl-trait/multiple-def-uses-in-one-fn.stderr index a7840e0a5bf..b5f38074632 100644 --- a/tests/ui/type-alias-impl-trait/multiple-def-uses-in-one-fn.stderr +++ b/tests/ui/type-alias-impl-trait/multiple-def-uses-in-one-fn.stderr @@ -2,7 +2,7 @@ error[E0277]: the trait bound `&'static B: From<&A>` is not satisfied --> $DIR/multiple-def-uses-in-one-fn.rs:9:45 | LL | fn f<A, B: 'static>(a: &'static A, b: B) -> (X<A, B>, X<B, A>) { - | ^^^^^^^^^^^^^^^^^^ the trait `From<&A>` is not implemented for `&'static B`, which is required by `&A: Into<&'static B>` + | ^^^^^^^^^^^^^^^^^^ the trait `From<&A>` is not implemented for `&'static B` | = note: required for `&A` to implement `Into<&'static B>` help: consider introducing a `where` clause, but there might be an alternative better way to express this requirement diff --git a/tests/ui/type-alias-impl-trait/underconstrained_generic.stderr b/tests/ui/type-alias-impl-trait/underconstrained_generic.stderr index 913a35eb9fb..e4de9245951 100644 --- a/tests/ui/type-alias-impl-trait/underconstrained_generic.stderr +++ b/tests/ui/type-alias-impl-trait/underconstrained_generic.stderr @@ -2,7 +2,7 @@ error[E0277]: the trait bound `T: Trait` is not satisfied --> $DIR/underconstrained_generic.rs:22:5 | LL | () - | ^^ the trait `Trait` is not implemented for `T`, which is required by `(): ProofForConversion<T>` + | ^^ the trait `Trait` is not implemented for `T` | note: required for `()` to implement `ProofForConversion<T>` --> $DIR/underconstrained_generic.rs:13:16 diff --git a/tests/ui/type-alias-impl-trait/variance.rs b/tests/ui/type-alias-impl-trait/variance.rs index 113f6a4cc44..40e8ec0129a 100644 --- a/tests/ui/type-alias-impl-trait/variance.rs +++ b/tests/ui/type-alias-impl-trait/variance.rs @@ -11,11 +11,11 @@ type NotCapturedEarly<'a> = impl Sized; //~ ['a: *, 'a: o] type CapturedEarly<'a> = impl Sized + Captures<'a>; //~ ['a: *, 'a: o] //~^ ERROR: unconstrained opaque type -type NotCapturedLate<'a> = dyn for<'b> Iterator<Item = impl Sized>; //~ ['a: *, 'b: o, 'a: o] +type NotCapturedLate<'a> = dyn for<'b> Iterator<Item = impl Sized>; //~ ['a: *, 'a: o, 'b: o] //~^ ERROR `impl Trait` cannot capture higher-ranked lifetime from `dyn` type //~| ERROR: unconstrained opaque type -type Captured<'a> = dyn for<'b> Iterator<Item = impl Sized + Captures<'a>>; //~ ['a: *, 'b: o, 'a: o] +type Captured<'a> = dyn for<'b> Iterator<Item = impl Sized + Captures<'a>>; //~ ['a: *, 'a: o, 'b: o] //~^ ERROR `impl Trait` cannot capture higher-ranked lifetime from `dyn` type //~| ERROR: unconstrained opaque type @@ -31,24 +31,24 @@ trait Foo<'i> { } impl<'i> Foo<'i> for &'i () { - type ImplicitCapture<'a> = impl Sized; //~ ['i: *, 'a: *, 'a: o, 'i: o] + type ImplicitCapture<'a> = impl Sized; //~ ['i: *, 'a: *, 'i: o, 'a: o] //~^ ERROR: unconstrained opaque type - type ExplicitCaptureFromHeader<'a> = impl Sized + Captures<'i>; //~ ['i: *, 'a: *, 'a: o, 'i: o] + type ExplicitCaptureFromHeader<'a> = impl Sized + Captures<'i>; //~ ['i: *, 'a: *, 'i: o, 'a: o] //~^ ERROR: unconstrained opaque type - type ExplicitCaptureFromGat<'a> = impl Sized + Captures<'a>; //~ ['i: *, 'a: *, 'a: o, 'i: o] + type ExplicitCaptureFromGat<'a> = impl Sized + Captures<'a>; //~ ['i: *, 'a: *, 'i: o, 'a: o] //~^ ERROR: unconstrained opaque type } impl<'i> Foo<'i> for () { - type ImplicitCapture<'a> = impl Sized; //~ ['i: *, 'a: *, 'a: o, 'i: o] + type ImplicitCapture<'a> = impl Sized; //~ ['i: *, 'a: *, 'i: o, 'a: o] //~^ ERROR: unconstrained opaque type - type ExplicitCaptureFromHeader<'a> = impl Sized + Captures<'i>; //~ ['i: *, 'a: *, 'a: o, 'i: o] + type ExplicitCaptureFromHeader<'a> = impl Sized + Captures<'i>; //~ ['i: *, 'a: *, 'i: o, 'a: o] //~^ ERROR: unconstrained opaque type - type ExplicitCaptureFromGat<'a> = impl Sized + Captures<'a>; //~ ['i: *, 'a: *, 'a: o, 'i: o] + type ExplicitCaptureFromGat<'a> = impl Sized + Captures<'a>; //~ ['i: *, 'a: *, 'i: o, 'a: o] //~^ ERROR: unconstrained opaque type } diff --git a/tests/ui/type-alias-impl-trait/variance.stderr b/tests/ui/type-alias-impl-trait/variance.stderr index 489dfe03d44..79ce8148f19 100644 --- a/tests/ui/type-alias-impl-trait/variance.stderr +++ b/tests/ui/type-alias-impl-trait/variance.stderr @@ -122,13 +122,13 @@ error: ['a: *, 'a: o] LL | type CapturedEarly<'a> = impl Sized + Captures<'a>; | ^^^^^^^^^^^^^^^^^^^^^^^^^ -error: ['a: *, 'b: o, 'a: o] +error: ['a: *, 'a: o, 'b: o] --> $DIR/variance.rs:14:56 | LL | type NotCapturedLate<'a> = dyn for<'b> Iterator<Item = impl Sized>; | ^^^^^^^^^^ -error: ['a: *, 'b: o, 'a: o] +error: ['a: *, 'a: o, 'b: o] --> $DIR/variance.rs:18:49 | LL | type Captured<'a> = dyn for<'b> Iterator<Item = impl Sized + Captures<'a>>; @@ -140,37 +140,37 @@ error: ['a: *, 'b: *, T: o, 'a: o, 'b: o] LL | type Bar<'a, 'b: 'b, T> = impl Sized; | ^^^^^^^^^^ -error: ['i: *, 'a: *, 'a: o, 'i: o] +error: ['i: *, 'a: *, 'i: o, 'a: o] --> $DIR/variance.rs:34:32 | LL | type ImplicitCapture<'a> = impl Sized; | ^^^^^^^^^^ -error: ['i: *, 'a: *, 'a: o, 'i: o] +error: ['i: *, 'a: *, 'i: o, 'a: o] --> $DIR/variance.rs:37:42 | LL | type ExplicitCaptureFromHeader<'a> = impl Sized + Captures<'i>; | ^^^^^^^^^^^^^^^^^^^^^^^^^ -error: ['i: *, 'a: *, 'a: o, 'i: o] +error: ['i: *, 'a: *, 'i: o, 'a: o] --> $DIR/variance.rs:40:39 | LL | type ExplicitCaptureFromGat<'a> = impl Sized + Captures<'a>; | ^^^^^^^^^^^^^^^^^^^^^^^^^ -error: ['i: *, 'a: *, 'a: o, 'i: o] +error: ['i: *, 'a: *, 'i: o, 'a: o] --> $DIR/variance.rs:45:32 | LL | type ImplicitCapture<'a> = impl Sized; | ^^^^^^^^^^ -error: ['i: *, 'a: *, 'a: o, 'i: o] +error: ['i: *, 'a: *, 'i: o, 'a: o] --> $DIR/variance.rs:48:42 | LL | type ExplicitCaptureFromHeader<'a> = impl Sized + Captures<'i>; | ^^^^^^^^^^^^^^^^^^^^^^^^^ -error: ['i: *, 'a: *, 'a: o, 'i: o] +error: ['i: *, 'a: *, 'i: o, 'a: o] --> $DIR/variance.rs:51:39 | LL | type ExplicitCaptureFromGat<'a> = impl Sized + Captures<'a>; diff --git a/tests/ui/type/issue-58355.stderr b/tests/ui/type/issue-58355.stderr index cd8e3538802..b6056f0fd65 100644 --- a/tests/ui/type/issue-58355.stderr +++ b/tests/ui/type/issue-58355.stderr @@ -4,7 +4,7 @@ error[E0277]: the size for values of type `dyn ToString` cannot be known at comp LL | x = Some(Box::new(callback)); | ^^^^^^^^^^^^^^^^^^ doesn't have a size known at compile-time | - = help: within `fn() -> dyn ToString`, the trait `Sized` is not implemented for `dyn ToString`, which is required by `fn() -> dyn ToString: Fn()` + = help: within `fn() -> dyn ToString`, the trait `Sized` is not implemented for `dyn ToString` = note: required because it appears within the type `fn() -> dyn ToString` = note: required for the cast from `Box<fn() -> dyn ToString>` to `Box<dyn Fn() -> (dyn ToString + 'static)>` diff --git a/tests/ui/typeck/bad-index-due-to-nested.stderr b/tests/ui/typeck/bad-index-due-to-nested.stderr index 137c7b06396..bd7fd0392c3 100644 --- a/tests/ui/typeck/bad-index-due-to-nested.stderr +++ b/tests/ui/typeck/bad-index-due-to-nested.stderr @@ -2,7 +2,7 @@ error[E0277]: the trait bound `K: Hash` is not satisfied --> $DIR/bad-index-due-to-nested.rs:20:5 | LL | map[k] - | ^^^ the trait `Hash` is not implemented for `K`, which is required by `HashMap<_, _>: Index<&_>` + | ^^^ the trait `Hash` is not implemented for `K` | note: required for `HashMap<K, V>` to implement `Index<&K>` --> $DIR/bad-index-due-to-nested.rs:7:12 @@ -21,7 +21,7 @@ error[E0277]: the trait bound `V: Copy` is not satisfied --> $DIR/bad-index-due-to-nested.rs:20:5 | LL | map[k] - | ^^^ the trait `Copy` is not implemented for `V`, which is required by `HashMap<_, _>: Index<&_>` + | ^^^ the trait `Copy` is not implemented for `V` | note: required for `HashMap<K, V>` to implement `Index<&K>` --> $DIR/bad-index-due-to-nested.rs:7:12 diff --git a/tests/ui/typeck/issue-90101.stderr b/tests/ui/typeck/issue-90101.stderr index 796e904a438..2e140461c1d 100644 --- a/tests/ui/typeck/issue-90101.stderr +++ b/tests/ui/typeck/issue-90101.stderr @@ -2,7 +2,7 @@ error[E0277]: the trait bound `PathBuf: From<Cow<'_, str>>` is not satisfied --> $DIR/issue-90101.rs:6:10 | LL | func(Path::new("hello").to_path_buf().to_string_lossy(), "world") - | ---- ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ the trait `From<Cow<'_, str>>` is not implemented for `PathBuf`, which is required by `Cow<'_, str>: Into<PathBuf>` + | ---- ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ the trait `From<Cow<'_, str>>` is not implemented for `PathBuf` | | | required by a bound introduced by this call | diff --git a/tests/ui/typeck/suggest-similar-impls-for-root-obligation.stderr b/tests/ui/typeck/suggest-similar-impls-for-root-obligation.stderr index 8410574e311..ab307aadec9 100644 --- a/tests/ui/typeck/suggest-similar-impls-for-root-obligation.stderr +++ b/tests/ui/typeck/suggest-similar-impls-for-root-obligation.stderr @@ -2,7 +2,7 @@ error[E0277]: the trait bound `((),): Into<Bar>` is not satisfied --> $DIR/suggest-similar-impls-for-root-obligation.rs:14:24 | LL | let _: Bar = ((),).into(); - | ^^^^ the trait `Foo<'_>` is not implemented for `((),)`, which is required by `((),): Into<_>` + | ^^^^ the trait `Foo<'_>` is not implemented for `((),)` | = help: the trait `Foo<'_>` is implemented for `()` = help: for that trait implementation, expected `()`, found `((),)` diff --git a/tests/ui/typeck/typeck-default-trait-impl-negation-sync.stderr b/tests/ui/typeck/typeck-default-trait-impl-negation-sync.stderr index f5311b6e8ed..b9fca1a1b54 100644 --- a/tests/ui/typeck/typeck-default-trait-impl-negation-sync.stderr +++ b/tests/ui/typeck/typeck-default-trait-impl-negation-sync.stderr @@ -17,7 +17,7 @@ error[E0277]: `UnsafeCell<u8>` cannot be shared between threads safely LL | is_sync::<MyTypeWUnsafe>(); | ^^^^^^^^^^^^^ `UnsafeCell<u8>` cannot be shared between threads safely | - = help: within `MyTypeWUnsafe`, the trait `Sync` is not implemented for `UnsafeCell<u8>`, which is required by `MyTypeWUnsafe: Sync` + = help: within `MyTypeWUnsafe`, the trait `Sync` is not implemented for `UnsafeCell<u8>` note: required because it appears within the type `MyTypeWUnsafe` --> $DIR/typeck-default-trait-impl-negation-sync.rs:21:8 | @@ -35,7 +35,7 @@ error[E0277]: `Managed` cannot be shared between threads safely LL | is_sync::<MyTypeManaged>(); | ^^^^^^^^^^^^^ `Managed` cannot be shared between threads safely | - = help: within `MyTypeManaged`, the trait `Sync` is not implemented for `Managed`, which is required by `MyTypeManaged: Sync` + = help: within `MyTypeManaged`, the trait `Sync` is not implemented for `Managed` note: required because it appears within the type `MyTypeManaged` --> $DIR/typeck-default-trait-impl-negation-sync.rs:25:8 | diff --git a/tests/ui/typeck/typeck-unsafe-always-share.stderr b/tests/ui/typeck/typeck-unsafe-always-share.stderr index 3eb792b82e0..154e504996b 100644 --- a/tests/ui/typeck/typeck-unsafe-always-share.stderr +++ b/tests/ui/typeck/typeck-unsafe-always-share.stderr @@ -36,7 +36,7 @@ LL | test(ms); | | | required by a bound introduced by this call | - = help: within `MySync<NoSync>`, the trait `Sync` is not implemented for `UnsafeCell<NoSync>`, which is required by `MySync<NoSync>: Sync` + = help: within `MySync<NoSync>`, the trait `Sync` is not implemented for `UnsafeCell<NoSync>` note: required because it appears within the type `MySync<NoSync>` --> $DIR/typeck-unsafe-always-share.rs:8:8 | diff --git a/tests/ui/underscore-ident-matcher.rs b/tests/ui/underscore-ident-matcher.rs index bddc8c80a7b..77ec70d43d5 100644 --- a/tests/ui/underscore-ident-matcher.rs +++ b/tests/ui/underscore-ident-matcher.rs @@ -5,5 +5,5 @@ macro_rules! identity { } fn main() { - let identity!(_) = 10; //~ ERROR no rules expected the token `_` + let identity!(_) = 10; //~ ERROR no rules expected reserved identifier `_` } diff --git a/tests/ui/underscore-ident-matcher.stderr b/tests/ui/underscore-ident-matcher.stderr index a663f34cde1..0c3f980cf6c 100644 --- a/tests/ui/underscore-ident-matcher.stderr +++ b/tests/ui/underscore-ident-matcher.stderr @@ -1,4 +1,4 @@ -error: no rules expected the token `_` +error: no rules expected reserved identifier `_` --> $DIR/underscore-ident-matcher.rs:8:19 | LL | macro_rules! identity { diff --git a/tests/ui/union/projection-as-union-type-error-2.stderr b/tests/ui/union/projection-as-union-type-error-2.stderr index 39cdf30d860..3b073ca1fb4 100644 --- a/tests/ui/union/projection-as-union-type-error-2.stderr +++ b/tests/ui/union/projection-as-union-type-error-2.stderr @@ -2,7 +2,7 @@ error[E0277]: the trait bound `u8: NotImplemented` is not satisfied --> $DIR/projection-as-union-type-error-2.rs:18:8 | LL | a: <Foo as Identity>::Identity, - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^ the trait `NotImplemented` is not implemented for `u8`, which is required by `u8: Identity` + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^ the trait `NotImplemented` is not implemented for `u8` | help: this trait has no implementations, consider adding one --> $DIR/projection-as-union-type-error-2.rs:9:1 diff --git a/tests/ui/unsized-locals/issue-50940-with-feature.stderr b/tests/ui/unsized-locals/issue-50940-with-feature.stderr index 4c06566709e..b39eb2e70bb 100644 --- a/tests/ui/unsized-locals/issue-50940-with-feature.stderr +++ b/tests/ui/unsized-locals/issue-50940-with-feature.stderr @@ -13,7 +13,7 @@ error[E0277]: the size for values of type `str` cannot be known at compilation t LL | A as fn(str) -> A<str>; | ^ doesn't have a size known at compile-time | - = help: within `A<str>`, the trait `Sized` is not implemented for `str`, which is required by `A<str>: Sized` + = help: within `A<str>`, the trait `Sized` is not implemented for `str` note: required because it appears within the type `A<str>` --> $DIR/issue-50940-with-feature.rs:5:12 | diff --git a/tests/ui/unsized-locals/rust-call.stderr b/tests/ui/unsized-locals/rust-call.stderr index b2e13b553e9..9eb0f3dabcc 100644 --- a/tests/ui/unsized-locals/rust-call.stderr +++ b/tests/ui/unsized-locals/rust-call.stderr @@ -4,7 +4,7 @@ error[E0277]: the size for values of type `[u8]` cannot be known at compilation LL | f(*slice); | ^^^^^^ doesn't have a size known at compile-time | - = help: within `([u8],)`, the trait `Sized` is not implemented for `[u8]`, which is required by `([u8],): Sized` + = help: within `([u8],)`, the trait `Sized` is not implemented for `[u8]` = note: required because it appears within the type `([u8],)` = note: argument required to be sized due to `extern "rust-call"` ABI diff --git a/tests/ui/unsized-locals/unsized-exprs.stderr b/tests/ui/unsized-locals/unsized-exprs.stderr index 6da37749fac..8a2ecf0f6c3 100644 --- a/tests/ui/unsized-locals/unsized-exprs.stderr +++ b/tests/ui/unsized-locals/unsized-exprs.stderr @@ -4,7 +4,7 @@ error[E0277]: the size for values of type `[u8]` cannot be known at compilation LL | udrop::<(i32, [u8])>((42, *foo())); | ^^^^^^^^^^^^ doesn't have a size known at compile-time | - = help: within `({integer}, [u8])`, the trait `Sized` is not implemented for `[u8]`, which is required by `({integer}, [u8]): Sized` + = help: within `({integer}, [u8])`, the trait `Sized` is not implemented for `[u8]` = note: required because it appears within the type `({integer}, [u8])` = note: tuples must have a statically known size to be initialized @@ -14,7 +14,7 @@ error[E0277]: the size for values of type `[u8]` cannot be known at compilation LL | udrop::<A<[u8]>>(A { 0: *foo() }); | ^^^^^^^^^^^^^^^ doesn't have a size known at compile-time | - = help: within `A<[u8]>`, the trait `Sized` is not implemented for `[u8]`, which is required by `A<[u8]>: Sized` + = help: within `A<[u8]>`, the trait `Sized` is not implemented for `[u8]` note: required because it appears within the type `A<[u8]>` --> $DIR/unsized-exprs.rs:3:8 | @@ -28,7 +28,7 @@ error[E0277]: the size for values of type `[u8]` cannot be known at compilation LL | udrop::<A<[u8]>>(A(*foo())); | ^^^^^^^^^ doesn't have a size known at compile-time | - = help: within `A<[u8]>`, the trait `Sized` is not implemented for `[u8]`, which is required by `A<[u8]>: Sized` + = help: within `A<[u8]>`, the trait `Sized` is not implemented for `[u8]` note: required because it appears within the type `A<[u8]>` --> $DIR/unsized-exprs.rs:3:8 | diff --git a/tests/ui/unsized/unsized-enum2.stderr b/tests/ui/unsized/unsized-enum2.stderr index 48cca6eb4bd..71cf782120e 100644 --- a/tests/ui/unsized/unsized-enum2.stderr +++ b/tests/ui/unsized/unsized-enum2.stderr @@ -320,7 +320,7 @@ error[E0277]: the size for values of type `(dyn PathHelper1 + 'static)` cannot b LL | VI(Path1), | ^^^^^ doesn't have a size known at compile-time | - = help: within `Path1`, the trait `Sized` is not implemented for `(dyn PathHelper1 + 'static)`, which is required by `Path1: Sized` + = help: within `Path1`, the trait `Sized` is not implemented for `(dyn PathHelper1 + 'static)` note: required because it appears within the type `Path1` --> $DIR/unsized-enum2.rs:16:8 | @@ -343,7 +343,7 @@ error[E0277]: the size for values of type `(dyn PathHelper2 + 'static)` cannot b LL | VJ{x: Path2}, | ^^^^^ doesn't have a size known at compile-time | - = help: within `Path2`, the trait `Sized` is not implemented for `(dyn PathHelper2 + 'static)`, which is required by `Path2: Sized` + = help: within `Path2`, the trait `Sized` is not implemented for `(dyn PathHelper2 + 'static)` note: required because it appears within the type `Path2` --> $DIR/unsized-enum2.rs:17:8 | @@ -366,7 +366,7 @@ error[E0277]: the size for values of type `(dyn PathHelper3 + 'static)` cannot b LL | VK(isize, Path3), | ^^^^^ doesn't have a size known at compile-time | - = help: within `Path3`, the trait `Sized` is not implemented for `(dyn PathHelper3 + 'static)`, which is required by `Path3: Sized` + = help: within `Path3`, the trait `Sized` is not implemented for `(dyn PathHelper3 + 'static)` note: required because it appears within the type `Path3` --> $DIR/unsized-enum2.rs:18:8 | @@ -389,7 +389,7 @@ error[E0277]: the size for values of type `(dyn PathHelper4 + 'static)` cannot b LL | VL{u: isize, x: Path4}, | ^^^^^ doesn't have a size known at compile-time | - = help: within `Path4`, the trait `Sized` is not implemented for `(dyn PathHelper4 + 'static)`, which is required by `Path4: Sized` + = help: within `Path4`, the trait `Sized` is not implemented for `(dyn PathHelper4 + 'static)` note: required because it appears within the type `Path4` --> $DIR/unsized-enum2.rs:19:8 | diff --git a/tests/ui/wf/hir-wf-check-erase-regions.stderr b/tests/ui/wf/hir-wf-check-erase-regions.stderr index 93449d60e9d..4b696dc1d1d 100644 --- a/tests/ui/wf/hir-wf-check-erase-regions.stderr +++ b/tests/ui/wf/hir-wf-check-erase-regions.stderr @@ -4,7 +4,7 @@ error[E0277]: `&'a T` is not an iterator LL | type IntoIter = std::iter::Flatten<std::slice::Iter<'a, T>>; | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ `&'a T` is not an iterator | - = help: the trait `Iterator` is not implemented for `&'a T`, which is required by `Flatten<std::slice::Iter<'a, T>>: Iterator` + = help: the trait `Iterator` is not implemented for `&'a T` = help: the trait `Iterator` is implemented for `&mut I` = note: required for `Flatten<std::slice::Iter<'a, T>>` to implement `Iterator` note: required by a bound in `std::iter::IntoIterator::IntoIter` @@ -16,7 +16,7 @@ error[E0277]: `&'a T` is not an iterator LL | type IntoIter = std::iter::Flatten<std::slice::Iter<'a, T>>; | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ `&'a T` is not an iterator | - = help: the trait `Iterator` is not implemented for `&'a T`, which is required by `&'a T: IntoIterator` + = help: the trait `Iterator` is not implemented for `&'a T` = help: the trait `Iterator` is implemented for `&mut I` = note: required for `&'a T` to implement `IntoIterator` note: required by a bound in `Flatten` @@ -28,7 +28,7 @@ error[E0277]: `&'a T` is not an iterator LL | fn into_iter(self) -> Self::IntoIter { | ^^^^^^^^^^^^^^ `&'a T` is not an iterator | - = help: the trait `Iterator` is not implemented for `&'a T`, which is required by `&'a T: IntoIterator` + = help: the trait `Iterator` is not implemented for `&'a T` = help: the trait `Iterator` is implemented for `&mut I` = note: required for `&'a T` to implement `IntoIterator` note: required by a bound in `Flatten` diff --git a/tests/ui/wf/wf-const-type.stderr b/tests/ui/wf/wf-const-type.stderr index d73642729ea..dd6e97755bd 100644 --- a/tests/ui/wf/wf-const-type.stderr +++ b/tests/ui/wf/wf-const-type.stderr @@ -2,7 +2,7 @@ error[E0277]: the trait bound `NotCopy: Copy` is not satisfied --> $DIR/wf-const-type.rs:10:12 | LL | const FOO: IsCopy<Option<NotCopy>> = IsCopy { t: None }; - | ^^^^^^^^^^^^^^^^^^^^^^^ the trait `Copy` is not implemented for `NotCopy`, which is required by `Option<NotCopy>: Copy` + | ^^^^^^^^^^^^^^^^^^^^^^^ the trait `Copy` is not implemented for `NotCopy` | = note: required for `Option<NotCopy>` to implement `Copy` note: required by a bound in `IsCopy` @@ -20,7 +20,7 @@ error[E0277]: the trait bound `NotCopy: Copy` is not satisfied --> $DIR/wf-const-type.rs:10:12 | LL | const FOO: IsCopy<Option<NotCopy>> = IsCopy { t: None }; - | ^^^^^^^^^^^^^^^^^^^^^^^ the trait `Copy` is not implemented for `NotCopy`, which is required by `Option<NotCopy>: Copy` + | ^^^^^^^^^^^^^^^^^^^^^^^ the trait `Copy` is not implemented for `NotCopy` | = note: required for `Option<NotCopy>` to implement `Copy` note: required by a bound in `IsCopy` @@ -39,7 +39,7 @@ error[E0277]: the trait bound `NotCopy: Copy` is not satisfied --> $DIR/wf-const-type.rs:10:50 | LL | const FOO: IsCopy<Option<NotCopy>> = IsCopy { t: None }; - | ^^^^ the trait `Copy` is not implemented for `NotCopy`, which is required by `Option<NotCopy>: Copy` + | ^^^^ the trait `Copy` is not implemented for `NotCopy` | = note: required for `Option<NotCopy>` to implement `Copy` note: required by a bound in `IsCopy` diff --git a/tests/ui/wf/wf-dyn-incompat-trait-obj-match.rs b/tests/ui/wf/wf-dyn-incompat-trait-obj-match.rs index 07e90538b85..6eba6b7abec 100644 --- a/tests/ui/wf/wf-dyn-incompat-trait-obj-match.rs +++ b/tests/ui/wf/wf-dyn-incompat-trait-obj-match.rs @@ -22,8 +22,8 @@ fn main() { Some(()) => &S, None => &R, //~ ERROR E0308 } - let t: &dyn Trait = match opt() { //~ ERROR E0038 + let t: &dyn Trait = match opt() { Some(()) => &S, //~ ERROR E0038 - None => &R, + None => &R, //~ ERROR E0038 }; } diff --git a/tests/ui/wf/wf-dyn-incompat-trait-obj-match.stderr b/tests/ui/wf/wf-dyn-incompat-trait-obj-match.stderr index d7366e12256..6cd4ebf8412 100644 --- a/tests/ui/wf/wf-dyn-incompat-trait-obj-match.stderr +++ b/tests/ui/wf/wf-dyn-incompat-trait-obj-match.stderr @@ -31,14 +31,10 @@ LL | trait Trait: Sized {} = note: required for the cast from `&S` to `&dyn Trait` error[E0038]: the trait `Trait` cannot be made into an object - --> $DIR/wf-dyn-incompat-trait-obj-match.rs:25:25 + --> $DIR/wf-dyn-incompat-trait-obj-match.rs:27:17 | -LL | let t: &dyn Trait = match opt() { - | _________________________^ -LL | | Some(()) => &S, -LL | | None => &R, -LL | | }; - | |_____^ `Trait` cannot be made into an object +LL | None => &R, + | ^^ `Trait` cannot be made into an object | note: for a trait to be "dyn-compatible" it needs to allow building a vtable to allow the call to be resolvable dynamically; for more information visit <https://doc.rust-lang.org/reference/items/traits.html#object-safety> --> $DIR/wf-dyn-incompat-trait-obj-match.rs:6:14 diff --git a/tests/ui/wf/wf-static-type.stderr b/tests/ui/wf/wf-static-type.stderr index 36234f3fd17..53b90c69960 100644 --- a/tests/ui/wf/wf-static-type.stderr +++ b/tests/ui/wf/wf-static-type.stderr @@ -2,7 +2,7 @@ error[E0277]: the trait bound `NotCopy: Copy` is not satisfied --> $DIR/wf-static-type.rs:10:13 | LL | static FOO: IsCopy<Option<NotCopy>> = IsCopy { t: None }; - | ^^^^^^^^^^^^^^^^^^^^^^^ the trait `Copy` is not implemented for `NotCopy`, which is required by `Option<NotCopy>: Copy` + | ^^^^^^^^^^^^^^^^^^^^^^^ the trait `Copy` is not implemented for `NotCopy` | = note: required for `Option<NotCopy>` to implement `Copy` note: required by a bound in `IsCopy` @@ -20,7 +20,7 @@ error[E0277]: the trait bound `NotCopy: Copy` is not satisfied --> $DIR/wf-static-type.rs:10:13 | LL | static FOO: IsCopy<Option<NotCopy>> = IsCopy { t: None }; - | ^^^^^^^^^^^^^^^^^^^^^^^ the trait `Copy` is not implemented for `NotCopy`, which is required by `Option<NotCopy>: Copy` + | ^^^^^^^^^^^^^^^^^^^^^^^ the trait `Copy` is not implemented for `NotCopy` | = note: required for `Option<NotCopy>` to implement `Copy` note: required by a bound in `IsCopy` @@ -39,7 +39,7 @@ error[E0277]: the trait bound `NotCopy: Copy` is not satisfied --> $DIR/wf-static-type.rs:10:51 | LL | static FOO: IsCopy<Option<NotCopy>> = IsCopy { t: None }; - | ^^^^ the trait `Copy` is not implemented for `NotCopy`, which is required by `Option<NotCopy>: Copy` + | ^^^^ the trait `Copy` is not implemented for `NotCopy` | = note: required for `Option<NotCopy>` to implement `Copy` note: required by a bound in `IsCopy` diff --git a/triagebot.toml b/triagebot.toml index 2e8851e7ec2..7f4def6a11b 100644 --- a/triagebot.toml +++ b/triagebot.toml @@ -725,9 +725,6 @@ please modify the tool then regenerate the library source file with the tool instead of editing the library source file manually. """ -[mentions."src/librustdoc/clean/types.rs"] -cc = ["@camelid"] - [mentions."src/librustdoc/html/static"] message = "Some changes occurred in HTML/CSS/JS." cc = [ @@ -938,9 +935,6 @@ cc = ["@rust-lang/project-exploit-mitigations", "@rcvalle"] [mentions."tests/ui/stack-protector"] cc = ["@rust-lang/project-exploit-mitigations", "@rcvalle"] -[mentions."tests/ui/check-cfg"] -cc = ["@Urgau"] - [mentions."compiler/rustc_middle/src/mir/coverage.rs"] message = "Some changes occurred in coverage instrumentation." cc = ["@Zalathar"] @@ -972,7 +966,6 @@ cc = ["@kobzol"] warn_non_default_branch = true contributing_url = "https://rustc-dev-guide.rust-lang.org/getting-started.html" users_on_vacation = [ - "BoxyUwU", "fmease", "jyn514", "oli-obk", |
