diff --git a/.mailmap b/.mailmap index 38ea8431e8814..d72c2e39c26a3 100644 --- a/.mailmap +++ b/.mailmap @@ -462,6 +462,8 @@ Mateusz Mikuła Mateusz Mikuła Mateusz Mikuła Mateusz Mikuła +Matilde Morrone +Matilde Morrone Matt Brubeck Matthew Auld Matthew Jasper diff --git a/compiler/rustc_abi/src/layout.rs b/compiler/rustc_abi/src/layout.rs index e8779d6ee6869..fa03fb87d02d1 100644 --- a/compiler/rustc_abi/src/layout.rs +++ b/compiler/rustc_abi/src/layout.rs @@ -11,8 +11,9 @@ use tracing::{debug, trace}; use crate::{ AbiAlign, Align, BackendLaneCount, BackendRepr, FieldsShape, HasDataLayout, IndexSlice, - IndexVec, Integer, LayoutData, Niche, NumScalableVectors, Primitive, ReprOptions, Scalar, Size, - StructKind, TagEncoding, TargetDataLayout, VariantLayout, Variants, WrappingRange, + IndexVec, Integer, LayoutData, Niche, NicheOptimizations, NumScalableVectors, Primitive, + ReprOptions, Scalar, Size, StructKind, TagEncoding, TargetDataLayout, VariantLayout, Variants, + WrappingRange, }; mod coroutine; @@ -178,7 +179,7 @@ impl LayoutCalculator { Self { cx } } - pub fn array_like( + pub fn layout_of_array_like( &self, element: &LayoutData, count_if_sized: Option, // None for slices @@ -201,7 +202,7 @@ impl LayoutCalculator { }) } - pub fn scalable_vector_type( + pub fn layout_of_scalable_vector_type( &self, element: F, count: u64, @@ -220,7 +221,7 @@ impl LayoutCalculator { ) } - pub fn simd_type( + pub fn layout_of_simd_type( &self, element: F, count: u64, @@ -239,20 +240,20 @@ impl LayoutCalculator { /// /// This uses dedicated code instead of [`Self::layout_of_struct_or_enum`], as coroutine /// fields may be shared between multiple variants (see the [`coroutine`] module for details). - pub fn coroutine< - 'a, - F: Deref> + fmt::Debug + Copy, - VariantIdx: Idx, - FieldIdx: Idx, - LocalIdx: Idx, - >( + pub fn layout_of_coroutine<'a, F, VariantIdx, FieldIdx, LocalIdx>( &self, local_layouts: &IndexSlice, prefix_layouts: IndexVec, variant_fields: &IndexSlice>, storage_conflicts: &BitMatrix, tag_to_layout: impl Fn(Scalar) -> F, - ) -> LayoutCalculatorResult { + ) -> LayoutCalculatorResult + where + F: Deref> + fmt::Debug + Copy, + VariantIdx: Idx, + FieldIdx: Idx, + LocalIdx: Idx, + { coroutine::layout( self, local_layouts, @@ -263,96 +264,96 @@ impl LayoutCalculator { ) } - pub fn univariant< - 'a, - FieldIdx: Idx, - VariantIdx: Idx, - F: Deref> + fmt::Debug + Copy, - >( + /// Compute the layout for a univariant (see [`Variants::Single`]). + /// + /// As a consumer of `rustc_abi`, you should only use this method for non-ADTs. + /// For structs and univariant enums, use [`Self::layout_of_struct`] instead + /// (it uses this function internally). + pub fn layout_of_univariant<'a, FieldIdx, VariantIdx, F>( &self, fields: &IndexSlice, repr: &ReprOptions, kind: StructKind, - ) -> LayoutCalculatorResult { + ) -> LayoutCalculatorResult + where + FieldIdx: Idx, + VariantIdx: Idx, + F: Deref> + fmt::Debug + Copy, + { let dl = self.cx.data_layout(); - let layout = self.univariant_biased(fields, repr, kind, NicheBias::Start); + let layout = self.layout_of_univariant_biased(fields, repr, kind, NicheBias::Start); // Enums prefer niches close to the beginning or the end of the variants so that other // (smaller) data-carrying variants can be packed into the space after/before the niche. // If the default field ordering does not give us a niche at the front then we do a second // run and bias niches to the right and then check which one is closer to one of the // struct's edges. - if let Ok(layout) = &layout { + if let Ok(layout) = &layout // Don't try to calculate an end-biased layout for unsizable structs, // otherwise we could end up with different layouts for // Foo and Foo which would break unsizing. - if !matches!(kind, StructKind::MaybeUnsized) { - if let Some(niche) = layout.largest_niche { - let head_space = niche.offset.bytes(); - let niche_len = niche.value.size(dl).bytes(); - let tail_space = layout.size.bytes() - head_space - niche_len; - - // This may end up doing redundant work if the niche is already in the last - // field (e.g. a trailing bool) and there is tail padding. But it's non-trivial - // to get the unpadded size so we try anyway. - if fields.len() > 1 && head_space != 0 && tail_space > 0 { - let alt_layout = self - .univariant_biased(fields, repr, kind, NicheBias::End) - .expect("alt layout should always work"); - let alt_niche = alt_layout - .largest_niche - .expect("alt layout should have a niche like the regular one"); - let alt_head_space = alt_niche.offset.bytes(); - let alt_niche_len = alt_niche.value.size(dl).bytes(); - let alt_tail_space = - alt_layout.size.bytes() - alt_head_space - alt_niche_len; - - debug_assert_eq!(layout.size.bytes(), alt_layout.size.bytes()); - - let prefer_alt_layout = - alt_head_space > head_space && alt_head_space > tail_space; - - debug!( - "sz: {}, default_niche_at: {}+{}, default_tail_space: {}, alt_niche_at/head_space: {}+{}, alt_tail: {}, num_fields: {}, better: {}\n\ - layout: {}\n\ - alt_layout: {}\n", - layout.size.bytes(), - head_space, - niche_len, - tail_space, - alt_head_space, - alt_niche_len, - alt_tail_space, - layout.fields.count(), - prefer_alt_layout, - self.format_field_niches(layout, fields), - self.format_field_niches(&alt_layout, fields), - ); - - if prefer_alt_layout { - return Ok(alt_layout); - } - } - } + && !matches!(kind, StructKind::MaybeUnsized) + && let Some(niche) = layout.largest_niche + && let head_space = niche.offset.bytes() + && let niche_len = niche.value.size(dl).bytes() + && let tail_space = layout.size.bytes() - head_space - niche_len + // This may end up doing redundant work if the niche is already in the last + // field (e.g. a trailing bool) and there is tail padding. But it's non-trivial + // to get the unpadded size so we try anyway. + && (fields.len() > 1 && head_space != 0 && tail_space > 0) + { + let alt_layout = self + .layout_of_univariant_biased(fields, repr, kind, NicheBias::End) + .expect("alt layout should always work"); + let alt_niche = alt_layout + .largest_niche + .expect("alt layout should have a niche like the regular one"); + let alt_head_space = alt_niche.offset.bytes(); + let alt_niche_len = alt_niche.value.size(dl).bytes(); + let alt_tail_space = alt_layout.size.bytes() - alt_head_space - alt_niche_len; + + debug_assert_eq!(layout.size.bytes(), alt_layout.size.bytes()); + + let prefer_alt_layout = alt_head_space > head_space && alt_head_space > tail_space; + + debug!( + "sz: {}, default_niche_at: {}+{}, default_tail_space: {}, alt_niche_at/head_space: {}+{}, alt_tail: {}, num_fields: {}, better: {}\n\ + layout: {}\n\ + alt_layout: {}\n", + layout.size.bytes(), + head_space, + niche_len, + tail_space, + alt_head_space, + alt_niche_len, + alt_tail_space, + layout.fields.count(), + prefer_alt_layout, + self.format_field_niches(layout, fields), + self.format_field_niches(&alt_layout, fields), + ); + + if prefer_alt_layout { + return Ok(alt_layout); } } layout } - pub fn layout_of_struct_or_enum< - 'a, - FieldIdx: Idx, - VariantIdx: Idx, - F: Deref> + fmt::Debug + Copy, - >( + pub fn layout_of_struct_or_enum<'a, FieldIdx, VariantIdx, F>( &self, repr: &ReprOptions, variants: &IndexSlice>, is_enum: bool, - is_special_no_niche: bool, + niche_optimizations: NicheOptimizations, discr_range_of_repr: impl Fn(RangeFrom, RangeToInclusive) -> (Integer, bool), discriminants: impl Iterator, always_sized: bool, - ) -> LayoutCalculatorResult { + ) -> LayoutCalculatorResult + where + FieldIdx: Idx, + VariantIdx: Idx, + F: Deref> + fmt::Debug + Copy, + { let (present_first, present_second) = { let mut present_variants = variants.iter_enumerated().filter_map(|(i, v)| { if !repr.inhibit_enum_layout_opt() && absent(v) { None } else { Some(i) } @@ -378,10 +379,10 @@ impl LayoutCalculator { self.layout_of_struct( repr, variants, + present_first, is_enum, - is_special_no_niche, + niche_optimizations, always_sized, - present_first, ) } else { // At this point, we have handled all unions and @@ -392,16 +393,16 @@ impl LayoutCalculator { } } - pub fn layout_of_union< - 'a, - FieldIdx: Idx, - VariantIdx: Idx, - F: Deref> + fmt::Debug + Copy, - >( + pub fn layout_of_union<'a, FieldIdx, VariantIdx, F>( &self, repr: &ReprOptions, variants: &IndexSlice>, - ) -> LayoutCalculatorResult { + ) -> LayoutCalculatorResult + where + FieldIdx: Idx, + VariantIdx: Idx, + F: Deref> + fmt::Debug + Copy, + { let dl = self.cx.data_layout(); let mut align = if repr.pack.is_some() { dl.i8_align } else { dl.aggregate_align }; let mut max_repr_align = repr.align; @@ -519,36 +520,36 @@ impl LayoutCalculator { }) } - /// single-variant enums are just structs, if you think about it - fn layout_of_struct< - 'a, - FieldIdx: Idx, - VariantIdx: Idx, - F: Deref> + fmt::Debug + Copy, - >( + /// Calculate the layout for a struct, or a single-variant enum. + /// + /// They are the same thing, if you think about it + /// (Typechecking will reject discriminant-sizing attrs.) + fn layout_of_struct<'a, FieldIdx, VariantIdx, F>( &self, repr: &ReprOptions, variants: &IndexSlice>, + variant_idx: VariantIdx, is_enum: bool, - is_special_no_niche: bool, + niche_optimizations: NicheOptimizations, always_sized: bool, - present_first: VariantIdx, - ) -> LayoutCalculatorResult { - // Struct, or univariant enum equivalent to a struct. - // (Typechecking will reject discriminant-sizing attrs.) - + ) -> LayoutCalculatorResult + where + FieldIdx: Idx, + VariantIdx: Idx, + F: Deref> + fmt::Debug + Copy, + { let dl = self.cx.data_layout(); - let v = present_first; + let v = variant_idx; let kind = if is_enum || variants[v].is_empty() || always_sized { StructKind::AlwaysSized } else { StructKind::MaybeUnsized }; - let mut st = self.univariant(&variants[v], repr, kind)?; + let mut st = self.layout_of_univariant(&variants[v], repr, kind)?; st.variants = Variants::Single { index: v }; - if is_special_no_niche { + if niche_optimizations == NicheOptimizations::Disabled { let hide_niches = |scalar: &mut _| match scalar { Scalar::Initialized { value, valid_range } => { *valid_range = WrappingRange::full(value.size(dl)) @@ -573,18 +574,18 @@ impl LayoutCalculator { Ok(st) } - fn layout_of_enum< - 'a, - FieldIdx: Idx, - VariantIdx: Idx, - F: Deref> + fmt::Debug + Copy, - >( + fn layout_of_enum<'a, FieldIdx, VariantIdx, F>( &self, repr: &ReprOptions, variants: &IndexSlice>, discr_range_of_repr: impl Fn(RangeFrom, RangeToInclusive) -> (Integer, bool), discriminants: impl Iterator, - ) -> LayoutCalculatorResult { + ) -> LayoutCalculatorResult + where + FieldIdx: Idx, + VariantIdx: Idx, + F: Deref> + fmt::Debug + Copy, + { let dl = self.cx.data_layout(); // bail if the enum has an incoherent repr that cannot be computed if repr.packed() { @@ -613,7 +614,7 @@ impl LayoutCalculator { let mut variant_layouts = variants .iter() .map(|v| { - let st = self.univariant(v, repr, StructKind::AlwaysSized).ok()?; + let st = self.layout_of_univariant(v, repr, StructKind::AlwaysSized).ok()?; variants_info.push(VariantLayoutInfo { align_abi: st.align.abi }); @@ -815,7 +816,7 @@ impl LayoutCalculator { let mut layout_variants = variants .iter() .map(|field_layouts| { - let st = self.univariant( + let st = self.layout_of_univariant( field_layouts, repr, StructKind::Prefixed(min_ity.size(), prefix_align), @@ -1078,18 +1079,18 @@ impl LayoutCalculator { Ok(best_layout) } - fn univariant_biased< - 'a, - FieldIdx: Idx, - VariantIdx: Idx, - F: Deref> + fmt::Debug + Copy, - >( + fn layout_of_univariant_biased<'a, FieldIdx, VariantIdx, F>( &self, fields: &IndexSlice, repr: &ReprOptions, kind: StructKind, niche_bias: NicheBias, - ) -> LayoutCalculatorResult { + ) -> LayoutCalculatorResult + where + FieldIdx: Idx, + VariantIdx: Idx, + F: Deref> + fmt::Debug + Copy, + { let dl = self.cx.data_layout(); let pack = repr.pack; let mut align = if pack.is_some() { dl.i8_align } else { dl.aggregate_align }; @@ -1424,16 +1425,16 @@ impl LayoutCalculator { }) } - fn format_field_niches< - 'a, - FieldIdx: Idx, - VariantIdx: Idx, - F: Deref> + fmt::Debug, - >( + fn format_field_niches<'a, FieldIdx, VariantIdx, F>( &self, layout: &LayoutData, fields: &IndexSlice, - ) -> String { + ) -> String + where + FieldIdx: Idx, + VariantIdx: Idx, + F: Deref> + fmt::Debug, + { let dl = self.cx.data_layout(); let mut s = String::new(); for i in layout.fields.index_by_increasing_offset() { @@ -1484,15 +1485,13 @@ where }; // Compute the size and alignment of the vector - let size = elt - .size - .checked_mul(count.as_u64(), dl) - .ok_or_else(|| LayoutCalculatorError::SizeOverflow)?; + let size = + elt.size.checked_mul(count.as_u64(), dl).ok_or(LayoutCalculatorError::SizeOverflow)?; let (repr, size, align) = match kind { SimdVectorKind::Scalable(number_of_vectors) => ( BackendRepr::SimdScalableVector { element, count, number_of_vectors }, size.checked_mul(number_of_vectors.0 as u64, dl) - .ok_or_else(|| LayoutCalculatorError::SizeOverflow)?, + .ok_or(LayoutCalculatorError::SizeOverflow)?, dl.rust_vector_align(size), ), // Non-power-of-two vectors have padding up to the next power-of-two. diff --git a/compiler/rustc_abi/src/layout/coroutine.rs b/compiler/rustc_abi/src/layout/coroutine.rs index fd68d06c93829..c102fbb3e843c 100644 --- a/compiler/rustc_abi/src/layout/coroutine.rs +++ b/compiler/rustc_abi/src/layout/coroutine.rs @@ -136,20 +136,20 @@ fn coroutine_saved_local_eligibility> + core::fmt::Debug + Copy, - VariantIdx: Idx, - FieldIdx: Idx, - LocalIdx: Idx, ->( +pub(super) fn layout<'a, F, VariantIdx, FieldIdx, LocalIdx>( calc: &super::LayoutCalculator, local_layouts: &IndexSlice, mut prefix_layouts: IndexVec, variant_fields: &IndexSlice>, storage_conflicts: &BitMatrix, tag_to_layout: impl Fn(Scalar) -> F, -) -> super::LayoutCalculatorResult { +) -> super::LayoutCalculatorResult +where + F: core::ops::Deref> + core::fmt::Debug + Copy, + VariantIdx: Idx, + FieldIdx: Idx, + LocalIdx: Idx, +{ use SavedLocalEligibility::*; let (ineligible_locals, assignments) = @@ -171,8 +171,11 @@ pub(super) fn layout< let promoted_layouts = ineligible_locals.iter().map(|local| local_layouts[local]); prefix_layouts.push(tag_to_layout(tag)); prefix_layouts.extend(promoted_layouts); - let prefix = - calc.univariant(&prefix_layouts, &ReprOptions::default(), StructKind::AlwaysSized)?; + let prefix = calc.layout_of_univariant( + &prefix_layouts, + &ReprOptions::default(), + StructKind::AlwaysSized, + )?; let (prefix_size, prefix_align) = (prefix.size, prefix.align); @@ -225,7 +228,7 @@ pub(super) fn layout< }) .map(|local| local_layouts[*local]); - let mut variant = calc.univariant( + let mut variant = calc.layout_of_univariant( &variant_only_tys.collect::>(), &ReprOptions::default(), StructKind::Prefixed(prefix_size, prefix_align.abi), diff --git a/compiler/rustc_abi/src/lib.rs b/compiler/rustc_abi/src/lib.rs index 5322b451fc6e8..df2dca6ec252b 100644 --- a/compiler/rustc_abi/src/lib.rs +++ b/compiler/rustc_abi/src/lib.rs @@ -2027,10 +2027,10 @@ pub enum Variants { /// 2. the never type Empty, - /// The type has a single valid variant. + /// The type has a single valid variant. Such types are called "univariant". /// /// This is the case for: - /// 1. enums with a single inhabited variant + /// 1. enums with a single inhabited variant, aka. "univariant enums" /// 2. structs, unions, and non-ADTs (except coroutines; see below), /// as those can't have multiple variants Single { @@ -2195,6 +2195,18 @@ impl Niche { } } +/// Whether niche optimizations should be performed during layout calculation. +/// +/// [`UnsafeCell`] and [`UnsafePinned`] both disable niche optimizations. +/// +/// [`UnsafeCell`]: std::cell::UnsafeCell +/// [`UnsafePinned`]: std::pin::UnsafePinned +#[derive(PartialEq, Eq, Clone, Copy)] +pub enum NicheOptimizations { + Enabled, + Disabled, +} + // NOTE: This struct is generic over the FieldIdx and VariantIdx for rust-analyzer usage. #[derive(PartialEq, Eq, Hash, Clone)] #[cfg_attr(feature = "nightly", derive(StableHash))] diff --git a/compiler/rustc_builtin_macros/src/asm.rs b/compiler/rustc_builtin_macros/src/asm.rs index 975b2c49b292d..845dc8ab544fc 100644 --- a/compiler/rustc_builtin_macros/src/asm.rs +++ b/compiler/rustc_builtin_macros/src/asm.rs @@ -588,13 +588,7 @@ pub(super) fn expand_asm<'cx>( return ExpandResult::Retry(()); }; let expr = match mac { - Ok(inline_asm) => Box::new(ast::Expr { - id: ast::DUMMY_NODE_ID, - kind: ast::ExprKind::InlineAsm(Box::new(inline_asm)), - span: sp, - attrs: ast::AttrVec::new(), - tokens: None, - }), + Ok(inline_asm) => ecx.expr(sp, ast::ExprKind::InlineAsm(Box::new(inline_asm))), Err(guar) => DummyResult::raw_expr(sp, Some(guar)), }; MacEager::expr(expr) @@ -618,13 +612,7 @@ pub(super) fn expand_naked_asm<'cx>( return ExpandResult::Retry(()); }; let expr = match mac { - Ok(inline_asm) => Box::new(ast::Expr { - id: ast::DUMMY_NODE_ID, - kind: ast::ExprKind::InlineAsm(Box::new(inline_asm)), - span: sp, - attrs: ast::AttrVec::new(), - tokens: None, - }), + Ok(inline_asm) => ecx.expr(sp, ast::ExprKind::InlineAsm(Box::new(inline_asm))), Err(guar) => DummyResult::raw_expr(sp, Some(guar)), }; MacEager::expr(expr) @@ -648,17 +636,11 @@ pub(super) fn expand_global_asm<'cx>( return ExpandResult::Retry(()); }; match mac { - Ok(inline_asm) => MacEager::items(smallvec![Box::new(ast::Item { - attrs: ast::AttrVec::new(), - id: ast::DUMMY_NODE_ID, - kind: ast::ItemKind::GlobalAsm(Box::new(inline_asm)), - vis: ast::Visibility { - span: sp.shrink_to_lo(), - kind: ast::VisibilityKind::Inherited, - }, - span: sp, - tokens: None, - })]), + Ok(inline_asm) => MacEager::items(smallvec![ecx.item( + sp, + ast::AttrVec::new(), + ast::ItemKind::GlobalAsm(Box::new(inline_asm)) + )]), Err(guar) => DummyResult::any(sp, guar), } } diff --git a/compiler/rustc_builtin_macros/src/assert.rs b/compiler/rustc_builtin_macros/src/assert.rs index 5f71e02d1350b..f5a582ddffcc5 100644 --- a/compiler/rustc_builtin_macros/src/assert.rs +++ b/compiler/rustc_builtin_macros/src/assert.rs @@ -1,8 +1,8 @@ mod context; use rustc_ast::token::Delimiter; -use rustc_ast::tokenstream::{DelimSpan, TokenStream}; -use rustc_ast::{DelimArgs, Expr, ExprKind, MacCall, Path, PathSegment, UnOp, token}; +use rustc_ast::tokenstream::TokenStream; +use rustc_ast::{Expr, ExprKind, Path, UnOp, token}; use rustc_ast_pretty::pprust; use rustc_errors::PResult; use rustc_expand::base::{DummyResult, ExpandResult, ExtCtxt, MacEager, MacroExpanderResult}; @@ -34,14 +34,7 @@ pub(crate) fn expand_assert<'cx>( let panic_path = || { if use_panic_2021(span) { // On edition 2021, we always call `$crate::panic::panic_2021!()`. - Path { - span: call_site_span, - segments: cx - .std_path(&[sym::panic, sym::panic_2021]) - .into_iter() - .map(PathSegment::from_ident) - .collect(), - } + cx.path(call_site_span, cx.std_path(&[sym::panic, sym::panic_2021])) } else { // Before edition 2021, we call `panic!()` unqualified, // such that it calls either `std::panic!()` or `core::panic!()`. @@ -51,16 +44,9 @@ pub(crate) fn expand_assert<'cx>( // Simply uses the user provided message instead of generating custom outputs let expr = if let Some(tokens) = custom_message { - let then = cx.expr( + let then = cx.expr_macro_call( call_site_span, - ExprKind::MacCall(Box::new(MacCall { - path: panic_path(), - args: Box::new(DelimArgs { - dspan: DelimSpan::from_single(call_site_span), - delim: Delimiter::Parenthesis, - tokens, - }), - })), + cx.macro_call(call_site_span, panic_path(), Delimiter::Parenthesis, tokens), ); expr_if_not(cx, call_site_span, cond_expr, then, None) } diff --git a/compiler/rustc_builtin_macros/src/assert/context.rs b/compiler/rustc_builtin_macros/src/assert/context.rs index cb3ea2475721e..11c97da0db5ad 100644 --- a/compiler/rustc_builtin_macros/src/assert/context.rs +++ b/compiler/rustc_builtin_macros/src/assert/context.rs @@ -1,8 +1,8 @@ use rustc_ast::token::{self, Delimiter, IdentKind}; use rustc_ast::tokenstream::{DelimSpan, TokenStream, TokenTree}; use rustc_ast::{ - BinOpKind, BorrowKind, DUMMY_NODE_ID, DelimArgs, Expr, ExprKind, ItemKind, MacCall, MethodCall, - Mutability, Path, PathSegment, Stmt, StructRest, UnOp, UseTree, UseTreeAndId, UseTreeKind, + BinOpKind, BorrowKind, DUMMY_NODE_ID, DelimArgs, Expr, ExprKind, ItemKind, MacCall, Mutability, + Path, Stmt, StructRest, UnOp, UseTree, UseTreeAndId, UseTreeKind, }; use rustc_ast_pretty::pprust; use rustc_data_structures::fx::FxHashSet; @@ -382,20 +382,15 @@ impl<'cx, 'a> Context<'cx, 'a> { ); let try_capture_call = self .cx - .stmt_expr(expr_method_call( - self.cx, - PathSegment { - args: None, - id: DUMMY_NODE_ID, - ident: Ident::new(sym::try_capture, self.span), - }, - expr_paren(self.cx, self.span, self.cx.expr_addr_of(self.span, wrapper)), + .stmt_expr(self.cx.expr_method_call( + self.span, + self.cx.expr_paren(self.span, self.cx.expr_addr_of(self.span, wrapper)), + Ident::new(sym::try_capture, self.span), thin_vec![expr_addr_of_mut( self.cx, self.span, self.cx.expr_path(Path::from_ident(capture)), )], - self.span, )) .add_trailing_semicolon(); let local_bind_path = self.cx.expr_path(Path::from_ident(local_bind)); @@ -448,17 +443,3 @@ fn escape_to_fmt(s: &str) -> String { fn expr_addr_of_mut(cx: &ExtCtxt<'_>, sp: Span, e: Box) -> Box { cx.expr(sp, ExprKind::AddrOf(BorrowKind::Ref, Mutability::Mut, e)) } - -fn expr_method_call( - cx: &ExtCtxt<'_>, - seg: PathSegment, - receiver: Box, - args: ThinVec>, - span: Span, -) -> Box { - cx.expr(span, ExprKind::MethodCall(Box::new(MethodCall { seg, receiver, args, span }))) -} - -fn expr_paren(cx: &ExtCtxt<'_>, sp: Span, e: Box) -> Box { - cx.expr(sp, ExprKind::Paren(e)) -} diff --git a/compiler/rustc_builtin_macros/src/autodiff.rs b/compiler/rustc_builtin_macros/src/autodiff.rs index 0c81b9080c6cf..083d05d03a070 100644 --- a/compiler/rustc_builtin_macros/src/autodiff.rs +++ b/compiler/rustc_builtin_macros/src/autodiff.rs @@ -14,9 +14,8 @@ mod llvm_enzyme { use rustc_ast::tokenstream::*; use rustc_ast::visit::AssocCtxt::*; use rustc_ast::{ - self as ast, AngleBracketedArg, AngleBracketedArgs, AnonConst, AssocItemKind, BindingMode, - FnRetTy, FnSig, GenericArg, GenericArgs, GenericParamKind, Generics, ItemKind, - MetaItemInner, PatKind, Path, PathSegment, TyKind, Visibility, + self as ast, AnonConst, FnRetTy, FnSig, GenericArg, GenericParamKind, Generics, ItemKind, + MetaItemInner, PatKind, TyKind, Visibility, }; use rustc_attr_ir::RustcAutodiff; use rustc_expand::base::{Annotatable, ExtCtxt}; @@ -154,7 +153,7 @@ mod llvm_enzyme { } fn meta_item_inner_to_ts(t: &MetaItemInner, ts: &mut Vec) { - let comma: Token = Token::new(TokenKind::Comma, Span::default()); + let comma = Token::new(TokenKind::Comma, Span::default()); let val = first_ident(t); let t = Token::from_ast_ident(val); ts.push(TokenTree::Token(t, Spacing::Joint)); @@ -275,7 +274,7 @@ mod llvm_enzyme { // Now, if the user gave a width (vector aka batch-mode ad), then we copy it. // If it is not given, we default to 1 (scalar mode). let start_position; - let kind: LitKind = LitKind::Integer; + let kind = LitKind::Integer; let symbol; if meta_item_vec.len() >= 2 && let Some(width) = width(&meta_item_vec[1]) @@ -287,7 +286,7 @@ mod llvm_enzyme { symbol = sym::integer(1); } - let l: Lit = Lit { kind, symbol, suffix: None }; + let l = Lit { kind, symbol, suffix: None }; let t = Token::new(TokenKind::Literal(l), Span::default()); let comma = Token::new(TokenKind::Comma, Span::default()); ts.push(TokenTree::Token(t, Spacing::Joint)); @@ -306,9 +305,9 @@ mod llvm_enzyme { } // We remove the last, trailing comma. ts.pop(); - let ts: TokenStream = TokenStream::from_iter(ts); + let ts = TokenStream::from_iter(ts); - let x: RustcAutodiff = from_ast(ecx, &meta_item_vec, has_ret, mode); + let x = from_ast(ecx, &meta_item_vec, has_ret, mode); if !x.is_active() { // We encountered an error, so we return the original item. // This allows us to potentially parse other attributes. @@ -346,7 +345,7 @@ mod llvm_enzyme { let mut rustc_ad_attr = Box::new(ast::NormalAttr::from_ident(Ident::with_dummy_span(sym::rustc_autodiff))); - let ts2: Vec = vec![TokenTree::Token( + let ts2 = vec![TokenTree::Token( Token::new(TokenKind::Ident(sym::never, IdentKind::Normal), span), Spacing::Joint, )]; @@ -382,7 +381,7 @@ mod llvm_enzyme { let mut has_inline_never = false; // Don't add it multiple times: - let orig_annotatable: Annotatable = match item { + let orig_annotatable = match item { Annotatable::Item(ref mut iitem) => { if !iitem.attrs.iter().any(|a| same_attribute(&a.kind, &attr.kind)) { iitem.attrs.push(attr); @@ -439,7 +438,7 @@ mod llvm_enzyme { let d_annotatable = match &item { Annotatable::AssocItem(_, ctxt) => { - let assoc_item: AssocItemKind = ast::AssocItemKind::Fn(d_fn); + let assoc_item = ast::AssocItemKind::Fn(d_fn); let d_fn = Box::new(ast::AssocItem { attrs: d_attrs, id: ast::DUMMY_NODE_ID, @@ -459,12 +458,7 @@ mod llvm_enzyme { Annotatable::Stmt(_) => { let mut d_fn = ecx.item(span, d_attrs, ItemKind::Fn(d_fn)); d_fn.vis = vis; - - Annotatable::Stmt(Box::new(ast::Stmt { - id: ast::DUMMY_NODE_ID, - kind: ast::StmtKind::Item(d_fn), - span, - })) + Annotatable::Stmt(Box::new(ecx.stmt_item(span, d_fn))) } _ => { unreachable!("item kind checked previously") @@ -568,7 +562,7 @@ mod llvm_enzyme { let call_expr = ecx.expr_call( span, ecx.expr_path(enzyme_path), - vec![primal_fn_ptr, diff_path_expr, tuple_expr].into(), + thin_vec![primal_fn_ptr, diff_path_expr, tuple_expr], ); ecx.stmt_expr(call_expr) @@ -591,35 +585,20 @@ mod llvm_enzyme { GenericParamKind::Type { .. } => { let path = ast::Path::from_ident(p.ident); let ty = ecx.ty_path(path); - Some(AngleBracketedArg::Arg(GenericArg::Type(ty))) + Some(GenericArg::Type(ty)) } GenericParamKind::Const { .. } => { let expr = ecx.expr_path(ast::Path::from_ident(p.ident)); let anon_const = AnonConst { id: ast::DUMMY_NODE_ID, value: expr }; - Some(AngleBracketedArg::Arg(GenericArg::Const(anon_const))) + Some(GenericArg::Const(anon_const)) } GenericParamKind::Lifetime => None, }) - .collect::>(); - - let args: AngleBracketedArgs = AngleBracketedArgs { span, args: generic_args }; - - let segment = PathSegment { - ident, - id: ast::DUMMY_NODE_ID, - args: Some(Box::new(GenericArgs::AngleBracketed(args))), - }; - - let segments = if is_impl { - thin_vec![ - PathSegment { ident: Ident::from_str("Self"), id: ast::DUMMY_NODE_ID, args: None }, - segment, - ] - } else { - thin_vec![segment] - }; + .collect::>(); - let path = Path { span, segments }; + let idents = + if is_impl { vec![Ident::new(kw::SelfUpper, span), ident] } else { vec![ident] }; + let path = ecx.path_all(span, false, idents, generic_args); ecx.expr_path(path) } @@ -657,9 +636,7 @@ mod llvm_enzyme { assert!(sig.decl.inputs.len() == x.input_activity.len()); assert!(has_ret == x.has_ret_activity()); let mut d_decl = sig.decl.clone(); - let mut d_inputs = Vec::new(); - let mut new_inputs = Vec::new(); - let mut idents = Vec::new(); + let mut d_inputs = ThinVec::new(); let mut act_ret = ThinVec::new(); // We have two loops, a first one just to check the activities and types and possibly report @@ -724,15 +701,10 @@ mod llvm_enzyme { debug!("{:#?}", &shadow_arg.pat); panic!("not an ident?"); }; - let name: String = format!("d{}_{}", old_name, i); - new_inputs.push(name.clone()); + let name = format!("d{}_{}", old_name, i); let ident = Ident::from_str_and_span(&name, shadow_arg.pat.span); - *shadow_arg.pat = ast::Pat { - id: ast::DUMMY_NODE_ID, - kind: PatKind::Ident(BindingMode::NONE, ident, None), - span: shadow_arg.pat.span, - }; - d_inputs.push(shadow_arg.clone()); + *shadow_arg.pat = ecx.pat_ident(shadow_arg.pat.span, ident); + d_inputs.push(shadow_arg); } } DiffActivity::Dual @@ -755,15 +727,11 @@ mod llvm_enzyme { debug!("{:#?}", &shadow_arg.pat); panic!("not an ident?"); }; - let name: String = format!("b{}_{}", old_name, i); - new_inputs.push(name.clone()); + let name = format!("b{}_{}", old_name, i); let ident = Ident::from_str_and_span(&name, shadow_arg.pat.span); - *shadow_arg.pat = ast::Pat { - id: ast::DUMMY_NODE_ID, - kind: PatKind::Ident(BindingMode::NONE, ident, None), - span: shadow_arg.pat.span, - }; - d_inputs.push(shadow_arg.clone()); + + *shadow_arg.pat = ecx.pat_ident(shadow_arg.pat.span, ident); + d_inputs.push(shadow_arg); } } DiffActivity::Const => { @@ -773,11 +741,6 @@ mod llvm_enzyme { panic!("Should not happen"); } } - if let PatKind::Ident(_, ident, _) = arg.pat.kind { - idents.push(ident); - } else { - panic!("not an ident?"); - } } let active_only_ret = x.ret_activity == DiffActivity::ActiveOnly; @@ -798,33 +761,20 @@ mod llvm_enzyme { }; let name = "dret".to_string(); let ident = Ident::from_str_and_span(&name, ty.span); - let shadow_arg = ast::Param { - attrs: ThinVec::new(), - ty: ty.clone(), - pat: Box::new(ast::Pat { - id: ast::DUMMY_NODE_ID, - kind: PatKind::Ident(BindingMode::NONE, ident, None), - span: ty.span, - }), - id: ast::DUMMY_NODE_ID, - span: ty.span, - is_placeholder: false, - }; + let shadow_arg = ecx.param(ty.span, ident, ty); d_inputs.push(shadow_arg); - new_inputs.push(name); } _ => {} } } - d_decl.inputs = d_inputs.into(); + d_decl.inputs = d_inputs; if x.mode.is_fwd() { let ty = match d_decl.output { FnRetTy::Ty(ref ty) => ty.clone(), FnRetTy::Default(span) => { // We want to return std::hint::black_box(()). - let kind = TyKind::Tup(ThinVec::new()); - let ty = Box::new(rustc_ast::Ty { kind, id: ast::DUMMY_NODE_ID, span }); + let ty = ecx.ty_unit(span); d_decl.output = FnRetTy::Ty(ty.clone()); assert!(matches!(x.ret_activity, DiffActivity::None)); // this won't be used below, so any type would be fine. diff --git a/compiler/rustc_builtin_macros/src/deriving/coerce_pointee.rs b/compiler/rustc_builtin_macros/src/deriving/coerce_pointee.rs index ab9037331050e..7d0db12a450d6 100644 --- a/compiler/rustc_builtin_macros/src/deriving/coerce_pointee.rs +++ b/compiler/rustc_builtin_macros/src/deriving/coerce_pointee.rs @@ -2,8 +2,8 @@ use ast::HasAttrs; use rustc_ast::mut_visit::MutVisitor; use rustc_ast::visit::{BoundKind, Visitor}; use rustc_ast::{ - self as ast, GenericArg, GenericBound, GenericParamKind, Generics, ItemKind, - TraitBoundModifiers, VariantData, WherePredicate, + self as ast, GenericArg, GenericBound, GenericParamKind, ItemKind, TraitBoundModifiers, + VariantData, WherePredicate, }; use rustc_data_structures::flat_map_in_place::FlatMapInPlace; use rustc_errors::E0802; @@ -12,12 +12,10 @@ use rustc_macros::Diagnostic; use rustc_span::{Ident, Span, Symbol, sym}; use thin_vec::{ThinVec, thin_vec}; +use crate::deriving::generic::*; +use crate::deriving::{new_path, path_std}; use crate::diagnostics; -macro_rules! path { - ($span:expr, $($part:ident)::*) => { vec![$(Ident::new(sym::$part, $span),)*] } -} - pub(crate) fn expand_deriving_coerce_pointee( cx: &ExtCtxt<'_>, span: Span, @@ -43,15 +41,8 @@ pub(crate) fn expand_deriving_coerce_pointee( }; // Convert generic parameters (from the struct) into generic args. - let self_params: Vec<_> = generics - .params - .iter() - .map(|p| match p.kind { - GenericParamKind::Lifetime => GenericArg::Lifetime(cx.lifetime(p.span(), p.ident)), - GenericParamKind::Type { .. } => GenericArg::Type(cx.ty_ident(p.span(), p.ident)), - GenericParamKind::Const { .. } => GenericArg::Const(cx.const_ident(p.span(), p.ident)), - }) - .collect(); + let self_params: Vec<_> = + generics.params.iter().map(|p| generic_param_to_arg(cx, p, p.span())).collect(); let type_params: Vec<_> = generics .params .iter() @@ -98,71 +89,30 @@ pub(crate) fn expand_deriving_coerce_pointee( let attrs = thin_vec![cx.attr_word(sym::automatically_derived, span),]; // # Validity assertion which will be checked later in `rustc_hir_analysis::coherence::builtins`. { - let trait_path = - cx.path_all(span, true, path!(span, core::marker::CoercePointeeValidated), vec![]); - let trait_ref = cx.trait_ref(trait_path); - push( - cx.item( - span, - attrs.clone(), - ast::ItemKind::Impl(ast::Impl { - generics: Generics { - params: generics - .params - .iter() - .map(|p| match &p.kind { - GenericParamKind::Lifetime => { - cx.lifetime_param(p.span(), p.ident, p.bounds.clone()) - } - GenericParamKind::Type { default: _ } => { - cx.typaram(p.span(), p.ident, p.bounds.clone(), None) - } - GenericParamKind::Const { ty, span: _, default: _ } => cx - .const_param( - p.span(), - p.ident, - p.bounds.clone(), - ty.clone(), - None, - ), - }) - .collect(), - where_clause: generics.where_clause.clone(), - span: generics.span, - }, - of_trait: Some(Box::new(ast::TraitImplHeader { - safety: ast::Safety::Default, - polarity: ast::ImplPolarity::Positive, - defaultness: ast::Defaultness::Implicit, - trait_ref, - })), - constness: ast::Const::No, - self_ty: self_type.clone(), - items: ThinVec::new(), - }), - ), - ); + let trait_path = path_std!(cx, span, marker::CoercePointeeValidated); + push(cx.item_trait_impl( + span, + attrs.clone(), + generics_without_defaults(generics), + ast::Safety::Default, + false, + cx.trait_ref(trait_path), + self_type.clone(), + ThinVec::new(), + )); } let mut add_impl_block = |generics, trait_symbol, trait_args| { - let mut parts = path!(span, core::ops); - parts.push(Ident::new(trait_symbol, span)); - let trait_path = cx.path_all(span, true, parts, trait_args); + let trait_path = new_path(cx, span, &[sym::ops, trait_symbol], trait_args); let trait_ref = cx.trait_ref(trait_path); - let item = cx.item( + let item = cx.item_trait_impl( span, attrs.clone(), - ast::ItemKind::Impl(ast::Impl { - generics, - of_trait: Some(Box::new(ast::TraitImplHeader { - safety: ast::Safety::Default, - polarity: ast::ImplPolarity::Positive, - defaultness: ast::Defaultness::Implicit, - trait_ref, - })), - constness: ast::Const::No, - self_ty: self_type.clone(), - items: ThinVec::new(), - }), + generics, + ast::Safety::Default, + false, + trait_ref, + self_type.clone(), + ThinVec::new(), ); push(item); }; @@ -196,7 +146,7 @@ pub(crate) fn expand_deriving_coerce_pointee( return; } let arg = GenericArg::Type(s_ty.clone()); - let unsize = cx.path_all(span, true, path!(span, core::marker::Unsize), vec![arg]); + let unsize = cx.path_all(span, true, cx.std_path(&[sym::marker, sym::Unsize]), vec![arg]); pointee.bounds.push(cx.trait_bound(unsize, false)); // Drop `#[pointee]` attribute since it should not be recognized outside `derive(CoercePointee)` pointee.attrs.retain(|attr| !attr.has_name(sym::pointee)); @@ -313,11 +263,11 @@ pub(crate) fn expand_deriving_coerce_pointee( } } - let extra_param = cx.typaram(span, Ident::new(sym::__S, span), self_bounds, None); + let extra_param = cx.typaram(Ident::new(sym::__S, span), self_bounds, None); impl_generics.params.insert(pointee_param_idx + 1, extra_param); // Add the impl blocks for `DispatchFromDyn` and `CoerceUnsized`. - let gen_args = vec![GenericArg::Type(alt_self_type)]; + let gen_args = vec![alt_self_type]; add_impl_block(impl_generics.clone(), sym::DispatchFromDyn, gen_args.clone()); add_impl_block(impl_generics, sym::CoerceUnsized, gen_args); } diff --git a/compiler/rustc_builtin_macros/src/deriving/generic/mod.rs b/compiler/rustc_builtin_macros/src/deriving/generic/mod.rs index 71329da76c481..8b15920511aca 100644 --- a/compiler/rustc_builtin_macros/src/deriving/generic/mod.rs +++ b/compiler/rustc_builtin_macros/src/deriving/generic/mod.rs @@ -182,13 +182,13 @@ pub(crate) use rustc_ast as ast; use rustc_ast::token::{IdentKind, LitKind, Token, TokenKind}; use rustc_ast::tokenstream::{DelimSpan, Spacing, TokenTree}; use rustc_ast::{ - AttrArgs, DelimArgs, EnumDef, Expr, GenericArg, GenericParamKind, Generics, Safety, SelfKind, - VariantData, + AttrArgs, DelimArgs, EnumDef, Expr, GenericArg, GenericParam, GenericParamKind, Generics, + Safety, SelfKind, VariantData, }; use rustc_attr_ir::{Attribute, AttributeKind, ReprPacked}; use rustc_attr_parsing::AttributeParser; use rustc_expand::base::ExtCtxt; -use rustc_span::{DUMMY_SP, Ident, Span, Symbol, kw, respan, sym}; +use rustc_span::{Ident, Span, Symbol, kw, respan, sym}; pub(crate) use smallvec::{SmallVec, smallvec}; use thin_vec::{ThinVec, thin_vec}; @@ -610,7 +610,7 @@ impl<'a> TraitDef<'a> { ) .collect(); - cx.typaram(span, param.ident, bounds, None) + cx.typaram(param.ident, bounds, None) } GenericParamKind::Const { ty, span, .. } => { let const_nodefault_kind = GenericParamKind::Const { @@ -708,17 +708,7 @@ impl<'a> TraitDef<'a> { let self_params: Vec<_> = generics .params .iter() - .map(|param| match param.kind { - GenericParamKind::Lifetime => { - GenericArg::Lifetime(cx.lifetime(param.ident.span.with_ctxt(ctxt), param.ident)) - } - GenericParamKind::Type { .. } => { - GenericArg::Type(cx.ty_ident(param.ident.span.with_ctxt(ctxt), param.ident)) - } - GenericParamKind::Const { .. } => { - GenericArg::Const(cx.const_ident(param.ident.span.with_ctxt(ctxt), param.ident)) - } - }) + .map(|param| generic_param_to_arg(cx, param, param.ident.span.with_ctxt(ctxt))) .collect(); // Create the type of `self`. @@ -770,21 +760,15 @@ impl<'a> TraitDef<'a> { attrs.push(cx.attr_nested_word(sym::doc, sym::hidden, self.span)); } - cx.item( + cx.item_trait_impl( self.span, attrs, - ast::ItemKind::Impl(ast::Impl { - generics: trait_generics, - of_trait: Some(Box::new(ast::TraitImplHeader { - safety: self.safety, - polarity: ast::ImplPolarity::Positive, - defaultness: ast::Defaultness::Implicit, - trait_ref, - })), - constness: if self.is_const { ast::Const::Yes(DUMMY_SP) } else { ast::Const::No }, - self_ty: self_type, - items: methods.collect(), - }), + trait_generics, + self.safety, + self.is_const, + trait_ref, + self_type, + methods.collect(), ) } } @@ -1239,3 +1223,32 @@ fn create_struct_field_access_fields( .collect() }) } + +pub(crate) fn generic_param_to_arg(cx: &ExtCtxt<'_>, p: &GenericParam, span: Span) -> GenericArg { + match p.kind { + GenericParamKind::Lifetime => GenericArg::Lifetime(cx.lifetime(span, p.ident)), + GenericParamKind::Type { .. } => GenericArg::Type(cx.ty_ident(span, p.ident)), + GenericParamKind::Const { .. } => GenericArg::Const(cx.const_ident(span, p.ident)), + } +} + +pub(crate) fn generics_without_defaults(g: &Generics) -> Generics { + Generics { + params: g + .params + .iter() + .map(|p| { + let mut p = p.clone(); + match &mut p.kind { + ast::GenericParamKind::Const { default, .. } => *default = None, + ast::GenericParamKind::Type { default } => *default = None, + ast::GenericParamKind::Lifetime => {} + }; + p.attrs.clear(); + p + }) + .collect(), + where_clause: g.where_clause.clone(), + span: g.span, + } +} diff --git a/compiler/rustc_builtin_macros/src/deriving/hash.rs b/compiler/rustc_builtin_macros/src/deriving/hash.rs index 3d3023b39955d..3e0722988155c 100644 --- a/compiler/rustc_builtin_macros/src/deriving/hash.rs +++ b/compiler/rustc_builtin_macros/src/deriving/hash.rs @@ -21,7 +21,7 @@ pub(crate) fn expand_deriving_hash( let param = { let path = path_std!(cx, span, hash::Hasher); - cx.typaram(span, typaram, thin_vec![cx.trait_bound(path, false)], None) + cx.typaram(typaram, thin_vec![cx.trait_bound(path, false)], None) }; let generics = ast::Generics { diff --git a/compiler/rustc_builtin_macros/src/deriving/reborrow.rs b/compiler/rustc_builtin_macros/src/deriving/reborrow.rs index dc45b1a896bc9..05ad76dbd1ff9 100644 --- a/compiler/rustc_builtin_macros/src/deriving/reborrow.rs +++ b/compiler/rustc_builtin_macros/src/deriving/reborrow.rs @@ -1,13 +1,12 @@ -use rustc_ast::{self as ast, AttrArgs, GenericArg, GenericParamKind, Generics, ItemKind, token}; +use rustc_ast::{self as ast, AttrArgs, Generics, ItemKind, token}; use rustc_errors::E0802; use rustc_expand::base::ExtCtxt; use rustc_macros::Diagnostic; use rustc_span::{Ident, Span, Symbol, sym}; use thin_vec::ThinVec; -macro_rules! path { - ($span:expr, $($part:ident)::*) => { vec![$(Ident::new(sym::$part, $span),)*] } -} +use crate::deriving::generic::*; +use crate::deriving::new_path; pub(crate) fn expand_deriving_reborrow( cx: &ExtCtxt<'_>, @@ -37,15 +36,7 @@ pub(crate) fn expand_deriving_coerce_shared( return; }; - push_marker_impl( - cx, - span, - ident, - generics, - sym::CoerceShared, - vec![GenericArg::Type(target)], - push, - ); + push_marker_impl(cx, span, ident, generics, sym::CoerceShared, vec![target], push); } fn struct_def<'a>( @@ -114,78 +105,28 @@ fn push_marker_impl( ident: Ident, generics: &Generics, trait_name: Symbol, - trait_args: Vec, + trait_args: Vec>, push: &mut dyn FnMut(Box), ) { - let mut trait_parts = path!(span, core::marker); - trait_parts.push(Ident::new(trait_name, span)); - let trait_path = cx.path_all(span, true, trait_parts, trait_args); + let trait_path = new_path(cx, span, &[sym::core, sym::marker, trait_name], trait_args); let trait_ref = cx.trait_ref(trait_path); - let self_params: Vec<_> = generics - .params - .iter() - .map(|param| match param.kind { - GenericParamKind::Lifetime => { - GenericArg::Lifetime(cx.lifetime(param.span(), param.ident)) - } - GenericParamKind::Type { .. } => { - GenericArg::Type(cx.ty_ident(param.span(), param.ident)) - } - GenericParamKind::Const { .. } => { - GenericArg::Const(cx.const_ident(param.span(), param.ident)) - } - }) - .collect(); + let self_params: Vec<_> = + generics.params.iter().map(|p| generic_param_to_arg(cx, p, p.span())).collect(); let self_ty = cx.ty_path(cx.path_all(span, false, vec![ident], self_params)); - push(cx.item( + push(cx.item_trait_impl( span, thin_vec::thin_vec![cx.attr_word(sym::automatically_derived, span)], - ast::ItemKind::Impl(ast::Impl { - generics: impl_generics(cx, generics), - of_trait: Some(Box::new(ast::TraitImplHeader { - safety: ast::Safety::Default, - polarity: ast::ImplPolarity::Positive, - defaultness: ast::Defaultness::Implicit, - trait_ref, - })), - constness: ast::Const::No, - self_ty, - items: ThinVec::new(), - }), + generics_without_defaults(generics), + ast::Safety::Default, + false, + trait_ref, + self_ty, + ThinVec::new(), )); } -fn impl_generics(cx: &ExtCtxt<'_>, generics: &Generics) -> Generics { - // Rebuild the generic parameter declarations because defaults are allowed on structs but - // rejected on impls. Preserve lifetime, type, and const parameters and their bounds, const - // parameter types, and the where-clause, while omitting type and const defaults. - Generics { - params: generics - .params - .iter() - .map(|param| match ¶m.kind { - GenericParamKind::Lifetime => { - cx.lifetime_param(param.span(), param.ident, param.bounds.clone()) - } - GenericParamKind::Type { default: _ } => { - cx.typaram(param.span(), param.ident, param.bounds.clone(), None) - } - GenericParamKind::Const { ty, span: _, default: _ } => cx.const_param( - param.span(), - param.ident, - param.bounds.clone(), - ty.clone(), - None, - ), - }) - .collect(), - where_clause: generics.where_clause.clone(), - span: generics.span, - } -} - #[derive(Diagnostic)] #[diag("`derive({$trait_name})` is only supported for structs, not {$kind}s", code = E0802)] struct UnsupportedItem { diff --git a/compiler/rustc_builtin_macros/src/edition_panic.rs b/compiler/rustc_builtin_macros/src/edition_panic.rs index ac5c43c660088..4c99ef9a9da26 100644 --- a/compiler/rustc_builtin_macros/src/edition_panic.rs +++ b/compiler/rustc_builtin_macros/src/edition_panic.rs @@ -1,6 +1,5 @@ use rustc_ast::token::Delimiter; -use rustc_ast::tokenstream::{DelimSpan, TokenStream}; -use rustc_ast::*; +use rustc_ast::tokenstream::TokenStream; use rustc_expand::base::*; use rustc_span::edition::Edition; use rustc_span::{Span, sym}; @@ -44,26 +43,15 @@ fn expand<'cx>( ) -> MacroExpanderResult<'cx> { let sp = cx.with_call_site_ctxt(sp); - ExpandResult::Ready(MacEager::expr( - cx.expr( + ExpandResult::Ready(MacEager::expr(cx.expr_macro_call( + sp, + cx.macro_call( sp, - ExprKind::MacCall(Box::new(MacCall { - path: Path { - span: sp, - segments: cx - .std_path(&[sym::panic, mac]) - .into_iter() - .map(PathSegment::from_ident) - .collect(), - }, - args: Box::new(DelimArgs { - dspan: DelimSpan::from_single(sp), - delim: Delimiter::Parenthesis, - tokens: tts, - }), - })), + cx.path(sp, cx.std_path(&[sym::panic, mac])), + Delimiter::Parenthesis, + tts, ), - )) + ))) } pub(crate) fn use_panic_2021(mut span: Span) -> bool { diff --git a/compiler/rustc_builtin_macros/src/format.rs b/compiler/rustc_builtin_macros/src/format.rs index e23c057f8a651..e52da1136dd64 100644 --- a/compiler/rustc_builtin_macros/src/format.rs +++ b/compiler/rustc_builtin_macros/src/format.rs @@ -1107,7 +1107,7 @@ fn report_invalid_references( // for `println!("{7:7$}", 1);` indexes.sort(); indexes.dedup(); - let span: MultiSpan = if !parser.is_source_literal || parser.arg_places.is_empty() { + let span = if !parser.is_source_literal || parser.arg_places.is_empty() { MultiSpan::from_span(fmt_span) } else { MultiSpan::from_spans(invalid_refs.iter().filter_map(|&(_, span, _, _)| span).collect()) diff --git a/compiler/rustc_builtin_macros/src/gca.rs b/compiler/rustc_builtin_macros/src/gca.rs index ba26b16d06be5..9e117e06ea9fd 100644 --- a/compiler/rustc_builtin_macros/src/gca.rs +++ b/compiler/rustc_builtin_macros/src/gca.rs @@ -18,16 +18,9 @@ pub(crate) fn expand<'cx>( Err(err) => return ExpandResult::Ready(DummyResult::any(span, err)), }; - let id = ast::DUMMY_NODE_ID; ExpandResult::Ready(Box::new(base::MacEager { - expr: Some(Box::new(ast::Expr { - id, - kind: ast::ExprKind::GcaMacro(expr.clone()), - span, - attrs: Default::default(), - tokens: None, - })), - ty: Some(Box::new(ast::Ty { id, kind: ast::TyKind::GcaMacro(expr), span })), + expr: Some(cx.expr(span, ast::ExprKind::GcaMacro(expr.clone()))), + ty: Some(cx.ty(span, ast::TyKind::GcaMacro(expr))), ..Default::default() })) } diff --git a/compiler/rustc_builtin_macros/src/offload.rs b/compiler/rustc_builtin_macros/src/offload.rs index 53bf0f4ca6b86..4da4ce4e4a505 100644 --- a/compiler/rustc_builtin_macros/src/offload.rs +++ b/compiler/rustc_builtin_macros/src/offload.rs @@ -148,7 +148,7 @@ pub(crate) fn expand_kernel( } // inline(never) attr - let ts: Vec = vec![TokenTree::Token( + let ts = vec![TokenTree::Token( Token::new(TokenKind::Ident(sym::never, IdentKind::Normal), span), Spacing::Joint, )]; diff --git a/compiler/rustc_builtin_macros/src/proc_macro_harness.rs b/compiler/rustc_builtin_macros/src/proc_macro_harness.rs index 2fbce3638e021..ecf4f7e7fb1af 100644 --- a/compiler/rustc_builtin_macros/src/proc_macro_harness.rs +++ b/compiler/rustc_builtin_macros/src/proc_macro_harness.rs @@ -339,6 +339,7 @@ fn mk_decls(cx: &mut ExtCtxt<'_>, macros: &[ProcMacro]) -> Box { let mut decls_static = cx.item_static( span, + ast::AttrVec::new(), Ident::new(sym::_DECLS, span), cx.ty_ref( span, diff --git a/compiler/rustc_builtin_macros/src/test.rs b/compiler/rustc_builtin_macros/src/test.rs index 010462e5551e0..b444505027988 100644 --- a/compiler/rustc_builtin_macros/src/test.rs +++ b/compiler/rustc_builtin_macros/src/test.rs @@ -3,7 +3,7 @@ use std::{assert_matches, iter}; -use rustc_ast::{self as ast, GenericParamKind, Mutability, Safety, attr, join_path_idents}; +use rustc_ast::{self as ast, GenericParamKind, Mutability, attr, join_path_idents}; use rustc_ast_pretty::pprust; use rustc_attr_ir::{Attribute, AttributeKind}; use rustc_attr_parsing::AttributeParser; @@ -210,8 +210,9 @@ pub(crate) fn expand_test_or_bench( thin_vec![ // #[coverage(off)] // |__bench_fn_name| self::test::assert_test_result( - coverage_off(cx.lambda1( + coverage_off(cx.closure( sp, + vec![bencher_param], cx.expr_call( sp, cx.expr_path(test_path("assert_test_result")), @@ -224,7 +225,6 @@ pub(crate) fn expand_test_or_bench( ), ], ), - bencher_param, )), // ) ], ) @@ -235,8 +235,9 @@ pub(crate) fn expand_test_or_bench( thin_vec![ // #[coverage(off)] // || { - coverage_off(cx.lambda0( + coverage_off(cx.closure( sp, + vec![], // test::assert_test_result( cx.expr_call( sp, @@ -263,76 +264,74 @@ pub(crate) fn expand_test_or_bench( let location_info = get_location_info(cx, fn_); - let mut test_const = - cx.item( + // static $ident: test::TestDescAndFn = + // We use a static because these things only exist to have references taken + // to them for the test case array. No reason to introduce tons of promoteds for that. + // Promoteds have the advantage that they can be merged to save space, but every one + // of these points to a different function so that will not happen. + let mut test_const = cx.item_static( + sp, + thin_vec![ + // #[cfg(test)] + cx.attr_nested_word(sym::cfg, sym::test, attr_sp), + // #[rustc_test_marker = "test_case_sort_key"] + cx.attr_name_value_str(sym::rustc_test_marker, test_path_symbol, attr_sp), + // #[doc(hidden)] + cx.attr_nested_word(sym::doc, sym::hidden, attr_sp), + ], + Ident::new(fn_.ident.name, sp), + cx.ty(sp, ast::TyKind::Path(None, test_path("TestDescAndFn"))), + Mutability::Not, + // test::TestDescAndFn { + cx.expr_struct( sp, + test_path("TestDescAndFn"), thin_vec![ - // #[cfg(test)] - cx.attr_nested_word(sym::cfg, sym::test, attr_sp), - // #[rustc_test_marker = "test_case_sort_key"] - cx.attr_name_value_str(sym::rustc_test_marker, test_path_symbol, attr_sp), - // #[doc(hidden)] - cx.attr_nested_word(sym::doc, sym::hidden, attr_sp), - ], - // static $ident: test::TestDescAndFn = - // We use a static because these things only exist to have references taken - // to them for the test case array. No reason to introduce tons of promoteds for that. - // Promoteds have the advantage that they can be merged to save space, but every one - // of these points to a different function so that will not happen. - ast::ItemKind::Static( - ast::StaticItem { - ident: Ident::new(fn_.ident.name, sp), - ty: cx.ty(sp, ast::TyKind::Path(None, test_path("TestDescAndFn"))), - safety: Safety::Default, - mutability: Mutability::Not, - define_opaque: None, - eii_impl: None, - // test::TestDescAndFn { - expr: Some( - cx.expr_struct( - sp, - test_path("TestDescAndFn"), - thin_vec![ - // desc: test::TestDesc { - field( - "desc", - cx.expr_struct(sp, test_path("TestDesc"), thin_vec![ - // name: "path::to::test" - field( - "name", - cx.expr_call( - sp, - cx.expr_path(test_path("StaticTestName")), - thin_vec![cx.expr_str(sp, test_path_symbol)], - ), - ), - // ignore: true | false - field("ignore", cx.expr_bool(sp, should_ignore(&item)),), - // ignore_message: Some("...") | None - field( - "ignore_message", - if let Some(msg) = should_ignore_message(&item) { - cx.expr_some(sp, cx.expr_str(sp, msg)) - } else { - cx.expr_none(sp) - }, + // desc: test::TestDesc { + field( + "desc", + cx.expr_struct( + sp, + test_path("TestDesc"), + thin_vec![ + // name: "path::to::test" + field( + "name", + cx.expr_call( + sp, + cx.expr_path(test_path("StaticTestName")), + thin_vec![cx.expr_str(sp, test_path_symbol)], ), - // source_file: - field("source_file", cx.expr_str(sp, location_info.0)), - // start_line: start line of the test fn identifier. - field("start_line", cx.expr_usize(sp, location_info.1)), - // start_col: start column of the test fn identifier. - field("start_col", cx.expr_usize(sp, location_info.2)), - // end_line: end line of the test fn identifier. - field("end_line", cx.expr_usize(sp, location_info.3)), - // end_col: end column of the test fn identifier. - field("end_col", cx.expr_usize(sp, location_info.4)), - // compile_fail: true | false - field("compile_fail", cx.expr_bool(sp, false)), - // no_run: true | false - field("no_run", cx.expr_bool(sp, false)), - // should_panic: ... - field("should_panic", match should_panic(cx, &item) { + ), + // ignore: true | false + field("ignore", cx.expr_bool(sp, should_ignore(&item)),), + // ignore_message: Some("...") | None + field( + "ignore_message", + if let Some(msg) = should_ignore_message(&item) { + cx.expr_some(sp, cx.expr_str(sp, msg)) + } else { + cx.expr_none(sp) + }, + ), + // source_file: + field("source_file", cx.expr_str(sp, location_info.0)), + // start_line: start line of the test fn identifier. + field("start_line", cx.expr_usize(sp, location_info.1)), + // start_col: start column of the test fn identifier. + field("start_col", cx.expr_usize(sp, location_info.2)), + // end_line: end line of the test fn identifier. + field("end_line", cx.expr_usize(sp, location_info.3)), + // end_col: end column of the test fn identifier. + field("end_col", cx.expr_usize(sp, location_info.4)), + // compile_fail: true | false + field("compile_fail", cx.expr_bool(sp, false)), + // no_run: true | false + field("no_run", cx.expr_bool(sp, false)), + // should_panic: ... + field( + "should_panic", + match should_panic(cx, &item) { // test::ShouldPanic::No ShouldPanic::No => { cx.expr_path(should_panic_path("No")) @@ -347,9 +346,12 @@ pub(crate) fn expand_test_or_bench( cx.expr_path(should_panic_path("YesWithMessage")), thin_vec![cx.expr_str(sp, sym)], ), - },), - // test_type: ... - field("test_type", match test_type(cx) { + }, + ), + // test_type: ... + field( + "test_type", + match test_type(cx) { // test::TestType::UnitTest TestType::UnitTest => { cx.expr_path(test_type_path("UnitTest")) @@ -362,19 +364,18 @@ pub(crate) fn expand_test_or_bench( TestType::Unknown => { cx.expr_path(test_type_path("Unknown")) } - },), - // }, - ],), - ), - // testfn: test::StaticTestFn(...) | test::StaticBenchFn(...) - field("testfn", test_fn), // } - ], - ), // } + }, + ), + // }, + ], ), - } - .into(), - ), - ); + ), + // testfn: test::StaticTestFn(...) | test::StaticBenchFn(...) + field("testfn", test_fn), // } + ], + // } + ), + ); test_const.vis.kind = ast::VisibilityKind::Public; // extern crate test diff --git a/compiler/rustc_builtin_macros/src/test_binder_constraints.rs b/compiler/rustc_builtin_macros/src/test_binder_constraints.rs index d6a3649500c29..3e70e83bb0762 100644 --- a/compiler/rustc_builtin_macros/src/test_binder_constraints.rs +++ b/compiler/rustc_builtin_macros/src/test_binder_constraints.rs @@ -1,5 +1,5 @@ use rustc_ast::tokenstream::TokenStream; -use rustc_ast::{AttrVec, VisibilityKind, ast, token}; +use rustc_ast::{AttrVec, ast, token}; use rustc_expand::base::{DummyResult, ExpandResult, ExtCtxt, MacEager, MacroExpanderResult}; use rustc_span::Span; use smallvec::SmallVec; @@ -26,15 +26,8 @@ pub(crate) fn expand<'cx>( if p.token != token::Eof { cx.dcx().emit_err(diagnostics::OnlyOneArgument { span: p.token.span, name }); } - let item = Box::new(ast::Item { - attrs: AttrVec::default(), - id: ast::DUMMY_NODE_ID, - span, - vis: ast::Visibility { kind: VisibilityKind::Inherited, span: span.shrink_to_lo() }, - kind: ast::ItemKind::TestBinderConstraints(item), - tokens: None, - }); - rustc_expand::base::ExpandResult::Ready(Box::new(MacEager { + let item = cx.item(span, AttrVec::default(), ast::ItemKind::TestBinderConstraints(item)); + ExpandResult::Ready(Box::new(MacEager { expr: None, items: Some(SmallVec::from_buf([item])), ty: None, diff --git a/compiler/rustc_codegen_llvm/src/back/write.rs b/compiler/rustc_codegen_llvm/src/back/write.rs index deaa78fcda003..ea37fc9666ae8 100644 --- a/compiler/rustc_codegen_llvm/src/back/write.rs +++ b/compiler/rustc_codegen_llvm/src/back/write.rs @@ -22,7 +22,7 @@ use rustc_fs_util::{link_or_copy, path_to_c_string}; use rustc_middle::ty::TyCtxt; use rustc_session::Session; use rustc_session::config::{self, Lto, OutputType, Passes, SplitDwarfKind, SwitchWithOptPath}; -use rustc_span::{BytePos, InnerSpan, Pos, RemapPathScopeComponents, SpanData, SyntaxContext}; +use rustc_span::{BytePos, DUMMY_SP, InnerSpan, Pos, RemapPathScopeComponents}; use rustc_target::spec::{CodeModel, FloatAbi, RelocModel, SanitizerSet, SplitDebuginfo, TlsModel}; use tracing::{debug, trace}; @@ -406,15 +406,12 @@ fn report_inline_asm( // In LTO build we may get srcloc values from other crates which are invalid // since they use a different source map. To be safe we just suppress these // in LTO builds. - let span = if cookie == 0 || matches!(cgcx.lto, Lto::Fat | Lto::Thin) { - SpanData::default() + let (lo, hi) = if cookie == 0 || matches!(cgcx.lto, Lto::Fat | Lto::Thin) { + (DUMMY_SP.lo(), DUMMY_SP.hi()) } else { - SpanData { - lo: BytePos::from_u32(cookie as u32), - hi: BytePos::from_u32((cookie >> 32) as u32), - ctxt: SyntaxContext::root(), - parent: None, - } + let lo = BytePos::from_u32(cookie as u32); + let hi = BytePos::from_u32((cookie >> 32) as u32); + (lo, hi) }; let level = match level { llvm::DiagnosticLevel::Error => Level::Error, @@ -422,7 +419,7 @@ fn report_inline_asm( llvm::DiagnosticLevel::Note | llvm::DiagnosticLevel::Remark => Level::Note, }; let msg = msg.trim_prefix("error: ").to_string(); - InlineAsmError { span, msg, level, source } + InlineAsmError { lo, hi, msg, level, source } } unsafe extern "C" fn diagnostic_handler(info: &DiagnosticInfo, user: *mut c_void) { diff --git a/compiler/rustc_codegen_ssa/src/back/write.rs b/compiler/rustc_codegen_ssa/src/back/write.rs index 9f239bbb9ac98..d39ae5a1852d5 100644 --- a/compiler/rustc_codegen_ssa/src/back/write.rs +++ b/compiler/rustc_codegen_ssa/src/back/write.rs @@ -4,15 +4,15 @@ use std::panic::AssertUnwindSafe; use std::path::{Path, PathBuf}; use std::sync::Arc; use std::sync::mpsc::{Receiver, Sender, channel}; -use std::{assert_matches, fs, io, mem, str, thread}; +use std::{assert_matches, fs, io, str, thread}; use rustc_abi::Size; use rustc_data_structures::jobserver::{self, Acquired}; use rustc_data_structures::profiling::{SelfProfilerRef, VerboseTimingGuard}; use rustc_errors::emitter::Emitter; use rustc_errors::{ - Diag, DiagArgMap, DiagCtxt, DiagCtxtHandle, DiagMessage, ErrCode, FatalError, FatalErrorMarker, - Level, MultiSpan, Style, Sublevel, Suggestions, catch_fatal_errors, + Diag, DiagCtxt, DiagCtxtHandle, DiagInner, FatalError, FatalErrorMarker, Level, + catch_fatal_errors, }; use rustc_fs_util::link_or_copy; use rustc_incremental::{ @@ -27,7 +27,7 @@ use rustc_session::config::{ }; use rustc_session::{IncrCompSession, Session}; use rustc_span::source_map::SourceMap; -use rustc_span::{FileName, InnerSpan, Span, SpanData, bug}; +use rustc_span::{BytePos, FileName, InnerSpan, Span, SyntaxContext, bug}; use rustc_structures::CrateType; use rustc_target::spec::{MergeFunctions, SanitizerSet}; use tracing::debug; @@ -1186,31 +1186,6 @@ pub(crate) enum ThinLtoMessage { /// process another codegen unit. pub struct CguMessage; -// A cut-down version of `rustc_errors::DiagInner` that impls `Send`, which -// can be used to send diagnostics from codegen threads to the main thread. -// It's missing the following fields from `rustc_errors::DiagInner`. -// - `span`: it doesn't impl `Send`. -// - `suggestions`: it doesn't impl `Send`, and isn't used for codegen -// diagnostics. -// - `is_lint`: lints aren't relevant during codegen. -// - `emitted_at`: not used for codegen diagnostics. -struct Diagnostic { - span: Vec, - level: Level, - messages: Vec<(DiagMessage, Style)>, - code: Option, - children: Vec, - args: DiagArgMap, -} - -// A cut-down version of `rustc_errors::Subdiag` that impls `Send`. It's -// missing the following fields from `rustc_errors::Subdiag`. -// - `span`: it doesn't impl `Send`. -struct Subdiagnostic { - level: Sublevel, - messages: Vec<(DiagMessage, Style)>, -} - #[derive(PartialEq, Clone, Copy, Debug)] enum MainThreadState { /// Doing nothing. @@ -1947,13 +1922,18 @@ fn spawn_thin_lto_work( } enum SharedEmitterMessage { - Diagnostic(Diagnostic), + Diagnostic(DiagInner), InlineAsmError(InlineAsmError), Fatal(String), } pub struct InlineAsmError { - pub span: SpanData, + // We store byte positions rather than a `Span` because this error is created on a codegen + // thread which doesn't have access to the span interner within the session globals. The byte + // positions are converted to a `Span` once they reach a thread with access to the span + // interner. + pub lo: BytePos, + pub hi: BytePos, pub msg: String, pub level: Level, pub source: Option<(String, Vec)>, @@ -1985,29 +1965,8 @@ impl SharedEmitter { } impl Emitter for SharedEmitter { - fn emit_diagnostic(&mut self, mut diag: rustc_errors::DiagInner) { - // Check that we aren't missing anything interesting when converting to - // the cut-down local `DiagInner`. - assert!(!diag.span.has_span_labels()); - assert_eq!(diag.suggestions, Suggestions::Enabled(vec![])); - assert_eq!(diag.is_lint, None); - // No sensible check for `diag.emitted_at`. - - let args = mem::take(&mut diag.args); - drop( - self.sender.send(SharedEmitterMessage::Diagnostic(Diagnostic { - span: diag.span.primary_spans().iter().map(|span| span.data()).collect::>(), - level: diag.level(), - messages: diag.messages, - code: diag.code, - children: diag - .children - .into_iter() - .map(|child| Subdiagnostic { level: child.level, messages: child.messages }) - .collect(), - args, - })), - ); + fn emit_diagnostic(&mut self, diag: DiagInner) { + drop(self.sender.send(SharedEmitterMessage::Diagnostic(diag))); } fn source_map(&self) -> Option<&SourceMap> { @@ -2032,33 +1991,16 @@ impl SharedEmitterMain { match message { Ok(SharedEmitterMessage::Diagnostic(diag)) => { - // The diagnostic has been received on the main thread. - // Convert it back to a full `Diagnostic` and emit. let dcx = sess.dcx(); - let mut d = - rustc_errors::DiagInner::new_with_messages(diag.level, diag.messages); - d.span = MultiSpan::from_spans( - diag.span.into_iter().map(|span| span.span()).collect(), - ); - d.code = diag.code; // may be `None`, that's ok - d.children = diag - .children - .into_iter() - .map(|sub| rustc_errors::Subdiag { - level: sub.level, - messages: sub.messages, - span: MultiSpan::new(), - }) - .collect(); - d.args = diag.args; - dcx.emit_diagnostic(d); + dcx.emit_diagnostic(diag); sess.dcx().abort_if_errors(); } Ok(SharedEmitterMessage::InlineAsmError(inner)) => { assert_matches!(inner.level, Level::Error | Level::Warning(None) | Level::Note); let mut err = Diag::new(sess.dcx(), inner.level, inner.msg); - if !inner.span.is_dummy() { - err.span(inner.span.span()); + let span = Span::new(inner.lo, inner.hi, SyntaxContext::root(), None); + if !span.is_dummy() { + err.span(span); } // Point to the generated assembly if it is available. diff --git a/compiler/rustc_expand/src/base.rs b/compiler/rustc_expand/src/base.rs index fda75319b087b..01e8cef49e445 100644 --- a/compiler/rustc_expand/src/base.rs +++ b/compiler/rustc_expand/src/base.rs @@ -1,6 +1,5 @@ use std::any::Any; use std::default::Default; -use std::iter; use std::path::PathBuf; use std::rc::Rc; use std::sync::Arc; @@ -24,7 +23,7 @@ use rustc_span::def_id::{CrateNum, DefId, LocalDefId, ModId}; use rustc_span::edition::Edition; use rustc_span::hygiene::{AstPass, ExpnData, ExpnKind, LocalExpnId, MacroKind}; use rustc_span::source_map::SourceMap; -use rustc_span::{DUMMY_SP, Ident, Span, Symbol, kw}; +use rustc_span::{DUMMY_SP, Ident, Span, Symbol}; use rustc_structures::{CollapseMacroDebuginfo, Limit}; use smallvec::{SmallVec, smallvec}; use thin_vec::ThinVec; @@ -1324,16 +1323,6 @@ impl<'a> ExtCtxt<'a> { pub fn set_trace_macros(&mut self, x: bool) { self.ecfg.trace_mac = x } - pub fn std_path(&self, components: &[Symbol]) -> Vec { - let def_site = self.with_def_site_ctxt(DUMMY_SP); - iter::once(Ident::new(kw::DollarCrate, def_site)) - .chain(components.iter().map(|&s| Ident::new(s, def_site))) - .collect() - } - pub fn def_site_path(&self, components: &[Symbol]) -> Vec { - let def_site = self.with_def_site_ctxt(DUMMY_SP); - components.iter().map(|&s| Ident::new(s, def_site)).collect() - } pub fn check_unused_macros(&mut self) { self.resolver.check_unused_macros(); diff --git a/compiler/rustc_expand/src/build.rs b/compiler/rustc_expand/src/build.rs index 9a93d82a4fe4c..34d4343ba9ba0 100644 --- a/compiler/rustc_expand/src/build.rs +++ b/compiler/rustc_expand/src/build.rs @@ -1,3 +1,5 @@ +use std::iter; + use rustc_ast::token::Delimiter; use rustc_ast::tokenstream::TokenStream; use rustc_ast::util::literal; @@ -11,6 +13,13 @@ use thin_vec::{ThinVec, thin_vec}; use crate::base::ExtCtxt; impl<'a> ExtCtxt<'a> { + pub fn std_path(&self, components: &[Symbol]) -> Vec { + let def_site = self.with_def_site_ctxt(DUMMY_SP); + iter::once(Ident::new(kw::DollarCrate, def_site)) + .chain(components.iter().map(|&s| Ident::new(s, def_site))) + .collect() + } + pub fn path(&self, span: Span, strs: Vec) -> ast::Path { self.path_all(span, false, strs, vec![]) } @@ -138,13 +147,12 @@ impl<'a> ExtCtxt<'a> { pub fn typaram( &self, - span: Span, ident: Ident, bounds: ast::GenericBounds, default: Option>, ) -> ast::GenericParam { ast::GenericParam { - ident: ident.with_span_pos(span), + ident, id: ast::DUMMY_NODE_ID, attrs: AttrVec::new(), bounds, @@ -154,15 +162,10 @@ impl<'a> ExtCtxt<'a> { } } - pub fn lifetime_param( - &self, - span: Span, - ident: Ident, - bounds: ast::GenericBounds, - ) -> ast::GenericParam { + pub fn lifetime_param(&self, ident: Ident, bounds: ast::GenericBounds) -> ast::GenericParam { ast::GenericParam { id: ast::DUMMY_NODE_ID, - ident: ident.with_span_pos(span), + ident, attrs: AttrVec::new(), bounds, is_placeholder: false, @@ -173,7 +176,6 @@ impl<'a> ExtCtxt<'a> { pub fn const_param( &self, - span: Span, ident: Ident, bounds: ast::GenericBounds, ty: Box, @@ -181,7 +183,7 @@ impl<'a> ExtCtxt<'a> { ) -> ast::GenericParam { ast::GenericParam { id: ast::DUMMY_NODE_ID, - ident: ident.with_span_pos(span), + ident, attrs: AttrVec::new(), bounds, is_placeholder: false, @@ -275,10 +277,6 @@ impl<'a> ExtCtxt<'a> { self.stmt_local(local, span) } - pub fn stmt_semi(&self, expr: Box) -> ast::Stmt { - ast::Stmt { id: ast::DUMMY_NODE_ID, span: expr.span, kind: ast::StmtKind::Semi(expr) } - } - pub fn stmt_local(&self, local: Box, span: Span) -> ast::Stmt { ast::Stmt { id: ast::DUMMY_NODE_ID, kind: ast::StmtKind::Let(local), span } } @@ -378,12 +376,6 @@ impl<'a> ExtCtxt<'a> { ) -> Box { self.expr(span, ast::ExprKind::Call(expr, args)) } - pub fn expr_loop(&self, sp: Span, block: Box) -> Box { - self.expr(sp, ast::ExprKind::Loop(block, None, sp)) - } - pub fn expr_asm(&self, sp: Span, expr: Box) -> Box { - self.expr(sp, ast::ExprKind::InlineAsm(expr)) - } pub fn expr_call_ident( &self, span: Span, @@ -490,64 +482,17 @@ impl<'a> ExtCtxt<'a> { self.expr(sp, ast::ExprKind::Tup(exprs)) } - pub fn expr_unreachable(&self, span: Span) -> Box { - self.expr_macro_call( - span, - self.macro_call( - span, - self.path_global( - span, - [sym::std, sym::unreachable].map(|s| Ident::new(s, span)).to_vec(), - ), - Delimiter::Parenthesis, - TokenStream::default(), - ), - ) - } - pub fn expr_ok(&self, sp: Span, expr: Box) -> Box { let ok = self.std_path(&[sym::result, sym::Result, sym::Ok]); self.expr_call_global(sp, ok, thin_vec![expr]) } - pub fn expr_try(&self, sp: Span, head: Box) -> Box { - let ok = self.std_path(&[sym::result, sym::Result, sym::Ok]); - let ok_path = self.path_global(sp, ok); - let err = self.std_path(&[sym::result, sym::Result, sym::Err]); - let err_path = self.path_global(sp, err); - - let binding_variable = Ident::new(sym::__try_var, sp); - let binding_pat = self.pat_ident(sp, binding_variable); - let binding_expr = self.expr_ident(sp, binding_variable); - - // `Ok(__try_var)` pattern - let ok_pat = self.pat_tuple_struct(sp, ok_path, thin_vec![binding_pat.clone()]); - - // `Err(__try_var)` (pattern and expression respectively) - let err_pat = self.pat_tuple_struct(sp, err_path.clone(), thin_vec![binding_pat]); - let err_inner_expr = - self.expr_call(sp, self.expr_path(err_path), thin_vec![binding_expr.clone()]); - // `return Err(__try_var)` - let err_expr = self.expr(sp, ast::ExprKind::Ret(Some(err_inner_expr))); - - // `Ok(__try_var) => __try_var` - let ok_arm = self.arm(sp, ok_pat, binding_expr); - // `Err(__try_var) => return Err(__try_var)` - let err_arm = self.arm(sp, err_pat, err_expr); - - // `match head { Ok() => ..., Err() => ... }` - self.expr_match(sp, head, thin_vec![ok_arm, err_arm]) - } - pub fn pat(&self, span: Span, kind: PatKind) -> ast::Pat { ast::Pat { id: ast::DUMMY_NODE_ID, kind, span } } pub fn pat_wild(&self, span: Span) -> ast::Pat { self.pat(span, PatKind::Wild) } - pub fn pat_lit(&self, span: Span, expr: Box) -> ast::Pat { - self.pat(span, PatKind::Expr(expr)) - } pub fn pat_ident(&self, span: Span, ident: Ident) -> ast::Pat { self.pat_ident_binding_mode(span, ident, ast::BindingMode::NONE) } @@ -602,10 +547,6 @@ impl<'a> ExtCtxt<'a> { } } - pub fn arm_unreachable(&self, span: Span) -> ast::Arm { - self.arm(span, self.pat_wild(span), self.expr_unreachable(span)) - } - pub fn expr_match( &self, span: Span, @@ -626,15 +567,15 @@ impl<'a> ExtCtxt<'a> { self.expr(span, ast::ExprKind::If(cond, self.block_expr(then), els)) } - pub fn lambda(&self, span: Span, ids: Vec, body: Box) -> Box { + pub fn closure(&self, span: Span, ids: Vec, body: Box) -> Box { let fn_decl = self.fn_decl( ids.iter().map(|id| self.param(span, *id, self.ty(span, ast::TyKind::Infer))).collect(), ast::FnRetTy::Default(span), ); // FIXME -- We are using `span` as the span of the `|...|` - // part of the lambda, but it probably (maybe?) corresponds to - // the entire lambda body. Probably we should extend the API + // part of the closure, but it probably (maybe?) corresponds to + // the entire closure body. Probably we should extend the API // here, but that's not entirely clear. self.expr( span, @@ -654,23 +595,6 @@ impl<'a> ExtCtxt<'a> { ) } - pub fn lambda0(&self, span: Span, body: Box) -> Box { - self.lambda(span, Vec::new(), body) - } - - pub fn lambda1(&self, span: Span, body: Box, ident: Ident) -> Box { - self.lambda(span, vec![ident], body) - } - - pub fn lambda_stmts_1( - &self, - span: Span, - stmts: ThinVec, - ident: Ident, - ) -> Box { - self.lambda1(span, self.expr_block(self.block(span, stmts)), ident) - } - pub fn param(&self, span: Span, ident: Ident, ty: Box) -> ast::Param { let pat = Box::new(self.pat_ident(span, ident)); ast::Param { @@ -702,9 +626,39 @@ impl<'a> ExtCtxt<'a> { }) } + pub fn item_trait_impl( + &self, + span: Span, + attrs: ast::AttrVec, + generics: ast::Generics, + safety: ast::Safety, + is_const: bool, + trait_ref: ast::TraitRef, + self_ty: Box, + items: ThinVec>, + ) -> Box { + self.item( + span, + attrs, + ast::ItemKind::Impl(ast::Impl { + generics, + of_trait: Some(Box::new(ast::TraitImplHeader { + safety, + polarity: ast::ImplPolarity::Positive, + defaultness: ast::Defaultness::Implicit, + trait_ref, + })), + constness: if is_const { ast::Const::Yes(DUMMY_SP) } else { ast::Const::No }, + self_ty, + items, + }), + ) + } + pub fn item_static( &self, span: Span, + attrs: ast::AttrVec, ident: Ident, ty: Box, mutability: ast::Mutability, @@ -712,7 +666,7 @@ impl<'a> ExtCtxt<'a> { ) -> Box { self.item( span, - AttrVec::new(), + attrs, ast::ItemKind::Static( ast::StaticItem { ident, diff --git a/compiler/rustc_lint/src/diagnostics.rs b/compiler/rustc_lint/src/diagnostics.rs index 98a11f8e1df08..464423b303f4f 100644 --- a/compiler/rustc_lint/src/diagnostics.rs +++ b/compiler/rustc_lint/src/diagnostics.rs @@ -2709,6 +2709,27 @@ pub(crate) enum UnusedDefSuggestion { #[suggestion_part(code = ";")] after_span: Span, }, + #[suggestion( + "use `let _unused = ...` to ignore the resulting value without dropping it immediately", + style = "verbose", + code = "let _unused = ", + applicability = "maybe-incorrect" + )] + BindingExpr { + #[primary_span] + span: Span, + }, + #[multipart_suggestion( + "use `let _unused = ...` to ignore the resulting value without dropping it immediately", + style = "verbose", + applicability = "maybe-incorrect" + )] + BindingBlockTailExpr { + #[suggestion_part(code = "let _unused = ")] + before_span: Span, + #[suggestion_part(code = ";")] + after_span: Span, + }, } // Needed because of def_path_str diff --git a/compiler/rustc_lint/src/unused/must_use.rs b/compiler/rustc_lint/src/unused/must_use.rs index dab842a688ae1..89e3981b965f2 100644 --- a/compiler/rustc_lint/src/unused/must_use.rs +++ b/compiler/rustc_lint/src/unused/must_use.rs @@ -299,6 +299,9 @@ impl<'tcx> LateLintPass<'tcx> for UnusedResults { return; } + let ty = cx.typeck_results().expr_ty(expr); + let needs_binding = ty.has_significant_drop(cx.tcx, cx.typing_env()); + if let hir::ExprKind::Match(await_expr, _arms, hir::MatchSource::AwaitDesugar) = expr.kind && let ty = cx.typeck_results().expr_ty(await_expr) && let ty::Alias(_, ty::AliasTy { kind: ty::Opaque { def_id: future_def_id }, .. }) = ty.kind() @@ -314,6 +317,7 @@ impl<'tcx> LateLintPass<'tcx> for UnusedResults { "output of future returned by ", "", expr_is_from_block, + needs_binding, ) { // We have a bare `foo().await;` on an opaque type from an async function that was @@ -321,19 +325,26 @@ impl<'tcx> LateLintPass<'tcx> for UnusedResults { return; } - let ty = cx.typeck_results().expr_ty(expr); - let must_use_result = is_ty_must_use(cx, ty, expr); let type_lint_emitted_or_trivial = match must_use_result { IsTyMustUse::Yes(path) => { - emit_must_use_untranslated(cx, &path, "", "", 1, false, expr_is_from_block); + emit_must_use_untranslated( + cx, + &path, + "", + "", + 1, + false, + expr_is_from_block, + needs_binding, + ); true } IsTyMustUse::Trivial => true, IsTyMustUse::No => false, }; - let fn_warned = check_fn_must_use(cx, expr, expr_is_from_block); + let fn_warned = check_fn_must_use(cx, expr, expr_is_from_block, needs_binding); if !fn_warned && type_lint_emitted_or_trivial { // We don't warn about unused unit or uninhabited types. @@ -415,7 +426,12 @@ impl<'tcx> LateLintPass<'tcx> for UnusedResults { /// Checks if `expr` is a \[method\] call expression marked as `#[must_use]` and emits a lint if so. /// Returns `true` if the lint has been emitted. -fn check_fn_must_use(cx: &LateContext<'_>, expr: &hir::Expr<'_>, expr_is_from_block: bool) -> bool { +fn check_fn_must_use( + cx: &LateContext<'_>, + expr: &hir::Expr<'_>, + expr_is_from_block: bool, + needs_binding: bool, +) -> bool { let maybe_def_id = match expr.kind { hir::ExprKind::Call(callee, _) => { if let hir::ExprKind::Path(ref qpath) = callee.kind @@ -434,9 +450,15 @@ fn check_fn_must_use(cx: &LateContext<'_>, expr: &hir::Expr<'_>, expr_is_from_bl }; match maybe_def_id { - Some(def_id) => { - check_must_use_def(cx, def_id, expr.span, "return value of ", "", expr_is_from_block) - } + Some(def_id) => check_must_use_def( + cx, + def_id, + expr.span, + "return value of ", + "", + expr_is_from_block, + needs_binding, + ), None => false, } } @@ -455,6 +477,7 @@ fn check_must_use_def( descr_pre_path: &str, descr_post_path: &str, expr_is_from_block: bool, + needs_binding: bool, ) -> bool { is_def_must_use(cx, def_id, span) .map(|must_use_path| { @@ -466,6 +489,7 @@ fn check_must_use_def( 1, false, expr_is_from_block, + needs_binding, ) }) .is_some() @@ -480,6 +504,7 @@ fn emit_must_use_untranslated( plural_len: usize, is_inner: bool, expr_is_from_block: bool, + needs_binding: bool, ) { let plural_suffix = pluralize!(plural_len); @@ -494,6 +519,7 @@ fn emit_must_use_untranslated( plural_len, true, expr_is_from_block, + needs_binding, ); } MustUsePath::Pinned(path) => { @@ -506,6 +532,7 @@ fn emit_must_use_untranslated( plural_len, true, expr_is_from_block, + needs_binding, ); } MustUsePath::Opaque(path) => { @@ -518,6 +545,7 @@ fn emit_must_use_untranslated( plural_len, true, expr_is_from_block, + needs_binding, ); } MustUsePath::TraitObject(path) => { @@ -530,6 +558,7 @@ fn emit_must_use_untranslated( plural_len, true, expr_is_from_block, + needs_binding, ); } MustUsePath::TupleElement(elems) => { @@ -543,6 +572,7 @@ fn emit_must_use_untranslated( plural_len, true, expr_is_from_block, + needs_binding, ); } } @@ -556,6 +586,7 @@ fn emit_must_use_untranslated( plural_len, true, expr_is_from_block, + needs_binding, ); } MustUsePath::ControlFlow(path) => { @@ -568,6 +599,7 @@ fn emit_must_use_untranslated( plural_len, true, expr_is_from_block, + needs_binding, ); } MustUsePath::Array(path, len) => { @@ -580,6 +612,7 @@ fn emit_must_use_untranslated( plural_len.saturating_add(usize::try_from(*len).unwrap_or(usize::MAX)), true, expr_is_from_block, + needs_binding, ); } MustUsePath::Closure(span) => { @@ -615,14 +648,24 @@ fn emit_must_use_untranslated( cx, def_id: *def_id, note: *reason, - suggestion: (!is_inner).then_some(if expr_is_from_block { - UnusedDefSuggestion::BlockTailExpr { - before_span: suggestion_span.shrink_to_lo(), - after_span: suggestion_span.shrink_to_hi(), - } + suggestion: if is_inner { + None } else { - UnusedDefSuggestion::NormalExpr { span: suggestion_span.shrink_to_lo() } - }), + let lo = suggestion_span.shrink_to_lo(); + let hi = suggestion_span.shrink_to_hi(); + Some(match (needs_binding, expr_is_from_block) { + (true, true) => UnusedDefSuggestion::BindingBlockTailExpr { + before_span: lo, + after_span: hi, + }, + (true, false) => UnusedDefSuggestion::BindingExpr { span: lo }, + (false, true) => UnusedDefSuggestion::BlockTailExpr { + before_span: lo, + after_span: hi, + }, + (false, false) => UnusedDefSuggestion::NormalExpr { span: lo }, + }) + }, }, ); } diff --git a/compiler/rustc_resolve/src/diagnostics/impls.rs b/compiler/rustc_resolve/src/diagnostics/impls.rs index 2ea2f52c696ba..9defefee9637b 100644 --- a/compiler/rustc_resolve/src/diagnostics/impls.rs +++ b/compiler/rustc_resolve/src/diagnostics/impls.rs @@ -1042,6 +1042,7 @@ impl<'ra, 'tcx> Resolver<'ra, 'tcx> { Res::Def(k, _) => matches_kind(k), _ => false, }, + &|_| true, ) && let Res::Def(kind, mut def_id) = suggestion.res { if let DefKind::Ctor(_, _) = kind { @@ -1615,6 +1616,7 @@ impl<'ra, 'tcx> Resolver<'ra, 'tcx> { parent_scope: &ParentScope<'ra>, ident: Ident, filter_fn: &impl Fn(Res) -> bool, + suggestion_filter: &impl Fn(&TypoSuggestion) -> bool, ) -> Option { let mut suggestions = Vec::new(); self.add_scope_set_candidates( @@ -1625,6 +1627,11 @@ impl<'ra, 'tcx> Resolver<'ra, 'tcx> { filter_fn, ); + // Some candidates cannot be decided from the `Res` alone (e.g. they need + // re-resolution or visibility checks), filter them out before picking the + // best name match. + suggestions.retain(suggestion_filter); + // Make sure error reporting is deterministic. suggestions.sort_by(|a, b| a.candidate.as_str().cmp(b.candidate.as_str())); @@ -1977,6 +1984,7 @@ impl<'ra, 'tcx> Resolver<'ra, 'tcx> { parent_scope, ident, is_expected, + &|_| true, ); self.add_typo_suggestion(err, suggestion, ident.span); self.detect_derive_attribute(err, ident, parent_scope, sugg_span); @@ -3035,6 +3043,45 @@ impl<'ra, 'tcx> Resolver<'ra, 'tcx> { }; let message = format!("cannot find `{ident}` in {scope}"); + // we may have typo in the middle part of path, try find a candidate with a similar name + // and then check whether it contains a candidate that is accessible from the current scope + let typo_suggestion = if opt_ns.is_none() + && ignore_import.is_some() + && let Some(ModuleOrUniformRoot::Module(module)) = module + && let Some(candidate) = self.early_lookup_typo_candidate( + ScopeSet::Module(TypeNS, module), + parent_scope, + ident, + &|res| matches!(res, Res::Def(DefKind::Mod | DefKind::Enum, _)), + &|candidate| { + self.cm() + .resolve_ident_in_module( + ModuleOrUniformRoot::Module(module), + Ident::new(candidate.candidate, ident.span), + TypeNS, + parent_scope, + None, + ignore_decl, + ignore_import, + ) + .is_ok_and(|binding| { + self.is_accessible_from(binding.vis(), parent_scope.module) + }) + }, + ) { + Some(( + vec![(ident.span, Ident::new(candidate.candidate, ident.span).to_string())], + format!( + "{} {} with a similar name exists", + candidate.res.article(), + candidate.res.descr(), + ), + Applicability::MaybeIncorrect, + )) + } else { + None + }; + if module_def_id == Some(CRATE_DEF_ID.to_def_id()) { let is_mod = |res| matches!(res, Res::Def(DefKind::Mod, _)); let mut candidates = self.lookup_import_candidates(ident, TypeNS, parent_scope, is_mod); @@ -3061,6 +3108,13 @@ impl<'ra, 'tcx> Resolver<'ra, 'tcx> { )), None, ) + } else if let Some(suggestion) = typo_suggestion { + ( + message, + format!("could not find `{ident}` in the crate root"), + Some(suggestion), + None, + ) } else if ident.name == sym::core { ( message, @@ -3193,7 +3247,7 @@ impl<'ra, 'tcx> Resolver<'ra, 'tcx> { ); }; } - (message, msg, None, None) + (message, msg, typo_suggestion, None) } else if ident.name == kw::SelfUpper { // As mentioned above, `opt_ns` being `None` indicates a module path in import. // We can use this to improve a confusing error for, e.g. `use Self::Variant` in an diff --git a/compiler/rustc_ty_utils/src/layout.rs b/compiler/rustc_ty_utils/src/layout.rs index 8f63c96fad707..8d8e501391c43 100644 --- a/compiler/rustc_ty_utils/src/layout.rs +++ b/compiler/rustc_ty_utils/src/layout.rs @@ -5,8 +5,8 @@ use rustc_abi::Integer::{I8, I32}; use rustc_abi::Primitive::{self, Float, Int, Pointer}; use rustc_abi::{ AddressSpace, BackendRepr, FIRST_VARIANT, FieldIdx, FieldsShape, HasDataLayout, Layout, - LayoutCalculatorError, LayoutData, Niche, ReprOptions, Scalar, Size, StructKind, TagEncoding, - VariantIdx, Variants, WrappingRange, + LayoutCalculatorError, LayoutData, Niche, NicheOptimizations, ReprOptions, Scalar, Size, + StructKind, TagEncoding, VariantIdx, Variants, WrappingRange, }; use rustc_attr_ir::find_attr; use rustc_attr_ir::lang_items::LangItem; @@ -235,7 +235,7 @@ fn layout_of_uncached<'tcx>( let univariant = |tys: &[Ty<'tcx>], kind| { let fields = tys.iter().map(|ty| cx.layout_of(*ty)).try_collect::>()?; let repr = ReprOptions::default(); - map_layout(cx.calc.univariant(&fields, &repr, kind)) + map_layout(cx.calc.layout_of_univariant(&fields, &repr, kind)) }; debug_assert!(!ty.has_non_region_infer()); @@ -523,11 +523,11 @@ fn layout_of_uncached<'tcx>( .ok_or_else(|| error(cx, LayoutError::Unknown(ty)))?; let element = cx.layout_of(element)?; - map_layout(cx.calc.array_like(&element, Some(count)))? + map_layout(cx.calc.layout_of_array_like(&element, Some(count)))? } ty::Slice(element) => { let element = cx.layout_of(element)?; - map_layout(cx.calc.array_like(&element, None).map(|mut layout| { + map_layout(cx.calc.layout_of_array_like(&element, None).map(|mut layout| { // a randomly chosen value to distinguish slices layout.randomization_seed = Hash64::new(0x2dcba99c39784102); layout @@ -535,7 +535,7 @@ fn layout_of_uncached<'tcx>( } ty::Str => { let element = scalar(Int(I8, false)); - map_layout(cx.calc.array_like(&element, None).map(|mut layout| { + map_layout(cx.calc.layout_of_array_like(&element, None).map(|mut layout| { // another random value layout.randomization_seed = Hash64::new(0xc1325f37d127be22); layout @@ -586,7 +586,7 @@ fn layout_of_uncached<'tcx>( let layout = cx .calc - .coroutine( + .layout_of_coroutine( &local_layouts, prefix_layouts, &info.variant_fields, @@ -638,7 +638,7 @@ fn layout_of_uncached<'tcx>( }; let element_layout = cx.layout_of(element_ty)?; - map_layout(cx.calc.scalable_vector_type( + map_layout(cx.calc.layout_of_scalable_vector_type( element_layout, element_count as u64, number_of_vectors, @@ -683,7 +683,7 @@ fn layout_of_uncached<'tcx>( } } - map_layout(cx.calc.simd_type(e_ly, e_len, def.repr().packed()))? + map_layout(cx.calc.layout_of_simd_type(e_ly, e_len, def.repr().packed()))? } // ADTs. @@ -713,7 +713,10 @@ fn layout_of_uncached<'tcx>( } // UnsafeCell and UnsafePinned both disable niche optimizations - let is_special_no_niche = def.is_unsafe_cell() || def.is_unsafe_pinned(); + let niche_optimizations = match def.is_unsafe_cell() || def.is_unsafe_pinned() { + true => NicheOptimizations::Disabled, + false => NicheOptimizations::Enabled, + }; let discr_range_of_repr = |min: RangeFrom, max: RangeToInclusive| { abi::Integer::discr_range_of_repr(tcx, ty, &def.repr(), min.start, max.last) @@ -755,7 +758,7 @@ fn layout_of_uncached<'tcx>( &def.repr(), &variants, def.is_enum(), - is_special_no_niche, + niche_optimizations, discr_range_of_repr, discriminants_iter(), !maybe_unsized, @@ -784,7 +787,7 @@ fn layout_of_uncached<'tcx>( &def.repr(), &variants, def.is_enum(), - is_special_no_niche, + niche_optimizations, discr_range_of_repr, discriminants_iter(), !maybe_unsized, diff --git a/library/alloc/src/collections/vec_deque/macros.rs b/library/alloc/src/collections/vec_deque/macros.rs index 5c7913073fe87..dbc1fa3f11578 100644 --- a/library/alloc/src/collections/vec_deque/macros.rs +++ b/library/alloc/src/collections/vec_deque/macros.rs @@ -17,3 +17,23 @@ macro_rules! __impl_slice_eq1 { } } } + +macro_rules! __impl_slice_eq2 { + ($(#[$stability:meta])+, [$($vars:tt)*] $lhs:ty, $rhs:ty, $($constraints:tt)*) => { + $(#[$stability])+ + impl PartialEq<$rhs> for $lhs + where + T: PartialEq, + $($constraints)* + { + fn eq(&self, other: &$rhs) -> bool { + if self.len() != other.len() { + return false; + } + let (oa, ob) = other.as_slices(); + let (sa, sb) = self[..].split_at(oa.len()); + sa == oa && sb == ob + } + } + } +} diff --git a/library/alloc/src/collections/vec_deque/mod.rs b/library/alloc/src/collections/vec_deque/mod.rs index 8e4507c6fd0aa..545c6ca59cc32 100644 --- a/library/alloc/src/collections/vec_deque/mod.rs +++ b/library/alloc/src/collections/vec_deque/mod.rs @@ -3907,6 +3907,13 @@ __impl_slice_eq1! { [const N: usize] VecDeque, [U; N], } __impl_slice_eq1! { [const N: usize] VecDeque, &[U; N], } __impl_slice_eq1! { [const N: usize] VecDeque, &mut [U; N], } +__impl_slice_eq2! { #[stable(feature = "slice_partial_eq_vec_deque", since = "CURRENT_RUSTC_VERSION")], [] Vec, VecDeque, } +__impl_slice_eq2! { #[stable(feature = "slice_partial_eq_vec_deque", since = "CURRENT_RUSTC_VERSION")], [] &[T], VecDeque, } +__impl_slice_eq2! { #[stable(feature = "slice_partial_eq_vec_deque", since = "CURRENT_RUSTC_VERSION")], [] &mut [T], VecDeque, } +__impl_slice_eq2! { #[stable(feature = "slice_partial_eq_vec_deque", since = "CURRENT_RUSTC_VERSION")], [const N: usize] [T; N], VecDeque, } +__impl_slice_eq2! { #[stable(feature = "slice_partial_eq_vec_deque", since = "CURRENT_RUSTC_VERSION")], [const N: usize] &[T; N], VecDeque, } +__impl_slice_eq2! { #[stable(feature = "slice_partial_eq_vec_deque", since = "CURRENT_RUSTC_VERSION")], [const N: usize] &mut [T; N], VecDeque, } + #[stable(feature = "rust1", since = "1.0.0")] impl PartialOrd for VecDeque { fn partial_cmp(&self, other: &Self) -> Option { diff --git a/library/alloctests/tests/vec_deque.rs b/library/alloctests/tests/vec_deque.rs index 00b2c2e34d569..3925a1235d3e7 100644 --- a/library/alloctests/tests/vec_deque.rs +++ b/library/alloctests/tests/vec_deque.rs @@ -631,6 +631,27 @@ fn test_partial_eq_array() { assert!(d == ['a', 'b']); } +#[test] +fn test_partial_eq_vecdeque_reverse() { + let mut d = VecDeque::with_capacity(4); + d.push_back(1); + d.push_back(2); + d.push_back(3); + d.pop_front(); + d.push_back(4); + + let v = vec![2, 3, 4]; + let a = [2, 3, 4]; + let mut b = [2, 3, 4]; + + assert!(v == d); + assert!(&v[..] == d); + assert!(&mut b[..] == d); + assert!(a == d); + assert!(&a == d); + assert!(&mut b == d); +} + #[test] fn test_hash() { let mut x = VecDeque::new(); diff --git a/library/core/src/fmt/num_buffer.rs b/library/core/src/fmt/num_buffer.rs index 5c29964b1cff8..62089e30a06e2 100644 --- a/library/core/src/fmt/num_buffer.rs +++ b/library/core/src/fmt/num_buffer.rs @@ -84,3 +84,10 @@ impl NumBuffer { NumBuffer { buf: T::DEFAULT, phantom: core::marker::PhantomData } } } + +#[stable(feature = "num_buffer_default", since = "CURRENT_RUSTC_VERSION")] +impl Default for NumBuffer { + fn default() -> Self { + Self::new() + } +} diff --git a/library/core/src/intrinsics/fallback.rs b/library/core/src/intrinsics/fallback.rs index d2794a5b1202d..3e6829ab16b18 100644 --- a/library/core/src/intrinsics/fallback.rs +++ b/library/core/src/intrinsics/fallback.rs @@ -112,8 +112,13 @@ const impl CarryingMulAdd for i128 { #[rustc_const_unstable(feature = "core_intrinsics_fallbacks", issue = "none")] pub const trait DisjointBitOr: Copy + 'static { - /// See [`super::disjoint_bitor`]; we just need the trait indirection to handle - /// different types since calling intrinsics with generics doesn't work. + /// We just need the trait indirection to handle different types + /// since calling intrinsics with generics doesn't work. + /// + /// # Safety + /// + /// See [`super::disjoint_bitor`], with `self` corresponding to `a` and + /// `other` corresponding to `b`. unsafe fn disjoint_bitor(self, other: Self) -> Self; } macro_rules! zero { @@ -149,12 +154,22 @@ impl_disjoint_bitor! { #[rustc_const_unstable(feature = "core_intrinsics_fallbacks", issue = "none")] pub const trait FunnelShift: Copy + 'static { - /// See [`super::unchecked_funnel_shl`]; we just need the trait indirection to handle - /// different types since calling intrinsics with generics doesn't work. + /// We just need the trait indirection to handle different types + /// since calling intrinsics with generics doesn't work. + /// + /// # Safety + /// + /// See [`super::unchecked_funnel_shl`], with `self` corresponding to `a` and + /// `right` corresponding to `b`. unsafe fn unchecked_funnel_shl(self, right: Self, shift: u32) -> Self; - /// See [`super::unchecked_funnel_shr`]; we just need the trait indirection to handle - /// different types since calling intrinsics with generics doesn't work. + /// We just need the trait indirection to handle different types + /// since calling intrinsics with generics doesn't work. + /// + /// # Safety + /// + /// See [`super::unchecked_funnel_shr`], with `self` corresponding to `a` and + /// `right` corresponding to `b`. unsafe fn unchecked_funnel_shr(self, right: Self, shift: u32) -> Self; } diff --git a/src/ci/docker/scripts/musl.sh b/src/ci/docker/scripts/musl.sh index 370b243dd4551..2402ec6ae34bf 100644 --- a/src/ci/docker/scripts/musl.sh +++ b/src/ci/docker/scripts/musl.sh @@ -78,12 +78,14 @@ EOF # project, so we just apply them directly on top of the version we were distributing already. The # patches should be removed once we upgrade to musl >= 1.2.7. # + SCRIPT_DIR=$(cd -- "$(dirname -- "$0")" && pwd) + MUSL_PATCH_DIR="$SCRIPT_DIR" # Advisory: https://www.openwall.com/lists/oss-security/2026/04/09/19 # Patches: https://www.openwall.com/lists/musl/2026/04/03/2/1 - patch -p1 -d $MUSL SBValue: return ptr if ptr.TypeIsPointerType() else ptr.GetChildAtIndex(0) -def unwrap_scalar_wrappers(wrapper: SBValue) -> SBValue: - while (wrapper.type.GetTypeFlags() & eTypeIsInteger) == 0: - wrapper = wrapper.GetChildAtIndex(0) - return wrapper - - class DefaultSyntheticProvider: def __init__(self, valobj: SBValue, _dict: LLDBOpaque): # logger = Logger.Logger() @@ -1549,9 +1542,17 @@ def has_children(self) -> bool: def StdRcSummaryProvider(valobj: SBValue, _dict: LLDBOpaque) -> str: - strong = valobj.GetChildMemberWithName("strong").GetValueAsUnsigned() - weak = valobj.GetChildMemberWithName("weak").GetValueAsUnsigned() - return "strong={}, weak={}".format(strong, weak) + strong = valobj.GetChildMemberWithName("strong") + weak = valobj.GetChildMemberWithName("weak") + + if not (strong.IsValid() and weak.IsValid()): + strong = "?" + weak = "?" + else: + strong = strong.GetValueAsUnsigned() + weak = weak.GetValueAsUnsigned() + + return f"strong={strong}, weak={weak}" class StdRcSyntheticProvider: @@ -1574,8 +1575,24 @@ def __init__(self, valobj: SBValue, _dict: LLDBOpaque, is_atomic: bool = False): self.value = self.ptr.GetChildMemberWithName("data" if is_atomic else "value") - self.strong = unwrap_scalar_wrappers(self.ptr.GetChildMemberWithName("strong")) - self.weak = unwrap_scalar_wrappers(self.ptr.GetChildMemberWithName("weak")) + # infallibly gets an unsigned integer type of at least 64 bits. We don't need to worry about + # whether or not `usize` is actually smaller than that since we don't ever display the + # underlying type to the user anyway + usize_type = valobj.GetTarget().GetBasicType(eBasicTypeUnsignedLongLong) + + self.strong = self.ptr.GetChildMemberWithName("strong").Cast(usize_type) + self.weak = self.ptr.GetChildMemberWithName("weak").Cast(usize_type) + + # If the usize type isn't valid due to llvm/llvm-project#196812, not even the type's fields + # will populate. Luckily, `RcInner` is `#[repr(C)]`, so we can infallibly find the strong + # and weak values in memory + if not self.strong.IsValid() or not self.weak.IsValid(): + raw_ptr = self.ptr.Cast(usize_type.GetPointerType()) + addr = raw_ptr.GetValueAsAddress() + self.strong = self.valobj.CreateValueFromAddress("strong", addr, usize_type) + self.weak = self.valobj.CreateValueFromAddress( + "weak", addr + usize_type.GetByteSize(), usize_type + ) self.value_builder = ValueBuilder(valobj) @@ -1598,15 +1615,14 @@ def get_child_at_index(self, index: int) -> Optional[SBValue]: if index == 0: return self.value if index == 1: - return self.value_builder.from_uint("strong", self.strong_count) + return self.strong if index == 2: - return self.value_builder.from_uint("weak", self.weak_count) + return self.weak return None def update(self): - self.strong_count = self.strong.GetValueAsUnsigned() - self.weak_count = self.weak.GetValueAsUnsigned() - 1 + pass def has_children(self) -> bool: return True diff --git a/tests/debuginfo/rc_arc.rs b/tests/debuginfo/rc_arc.rs index b22b7e0d1611d..4399dfe54e7a5 100644 --- a/tests/debuginfo/rc_arc.rs +++ b/tests/debuginfo/rc_arc.rs @@ -18,9 +18,9 @@ //@ lldb-command:run //@ lldb-command:v rc -//@ lldb-check:[...] strong=11, weak=1 { value = 111 } +//@ lldb-check:[...] strong=11, weak=2 { value = 111 } //@ lldb-command:v arc -//@ lldb-check:[...] strong=21, weak=1 { data = 222 } +//@ lldb-check:[...] strong=21, weak=2 { data = 222 } // === CDB TESTS ================================================================================== diff --git a/tests/debuginfo/strings-and-strs.rs b/tests/debuginfo/strings-and-strs.rs index 4ad61e29d3ec0..81e3037f1e566 100644 --- a/tests/debuginfo/strings-and-strs.rs +++ b/tests/debuginfo/strings-and-strs.rs @@ -43,7 +43,7 @@ //@ lldb-check:[...] str_in_tuple = ("Hello", "World") //@ lldb-command:v str_in_rc -//@ lldb-check:[...] str_in_rc = strong=1, weak=0 { value = "Hello" { [0] = 'H' [1] = 'e' [2] = 'l' [3] = 'l' [4] = 'o' } } +//@ lldb-check:[...] str_in_rc = strong=1, weak=1 { value = "Hello" { [0] = 'H' [1] = 'e' [2] = 'l' [3] = 'l' [4] = 'o' } } //@ lldb-command:v box_str //@ lldb-check:[...] box_str = "World" { [0] = 'W' [1] = 'o' [2] = 'r' [3] = 'l' [4] = 'd' } @@ -56,7 +56,7 @@ // lldb-command:v rc_str // ignore-tidy-linelength -// lldb-check:(alloc::rc::Rc) rc_str = strong=1, weak=0 { value = "World" } +// lldb-check:(alloc::rc::Rc) rc_str = strong=1, weak=1 { value = "World" } #![allow(unused_variables)] diff --git a/tests/pretty/autodiff/autodiff_forward.pp b/tests/pretty/autodiff/autodiff_forward.pp index 746754637f5cd..0fb60061f6982 100644 --- a/tests/pretty/autodiff/autodiff_forward.pp +++ b/tests/pretty/autodiff/autodiff_forward.pp @@ -35,8 +35,8 @@ } #[rustc_autodiff(Forward, 1, Dual, Const, Dual)] pub fn df1(x: &[f64], bx_0: &[f64], y: f64) -> (f64, f64) { - ::core::intrinsics::autodiff(f1::<> as fn(_: &[f64], _: f64) -> f64, - df1::<>, (x, bx_0, y)) + ::core::intrinsics::autodiff(f1 as fn(_: &[f64], _: f64) -> f64, df1, + (x, bx_0, y)) } #[rustc_autodiff] pub fn f2(x: &[f64], y: f64) -> f64 { @@ -44,8 +44,8 @@ } #[rustc_autodiff(Forward, 1, Dual, Const, Const)] pub fn df2(x: &[f64], bx_0: &[f64], y: f64) -> f64 { - ::core::intrinsics::autodiff(f2::<> as fn(_: &[f64], _: f64) -> f64, - df2::<>, (x, bx_0, y)) + ::core::intrinsics::autodiff(f2 as fn(_: &[f64], _: f64) -> f64, df2, + (x, bx_0, y)) } #[rustc_autodiff] pub fn f3(x: &[f64], y: f64) -> f64 { @@ -53,33 +53,31 @@ } #[rustc_autodiff(Forward, 1, Dual, Const, Const)] pub fn df3(x: &[f64], bx_0: &[f64], y: f64) -> f64 { - ::core::intrinsics::autodiff(f3::<> as fn(_: &[f64], _: f64) -> f64, - df3::<>, (x, bx_0, y)) + ::core::intrinsics::autodiff(f3 as fn(_: &[f64], _: f64) -> f64, df3, + (x, bx_0, y)) } #[rustc_autodiff] pub fn f4() {} #[rustc_autodiff(Forward, 1, None)] -pub fn df4() -> () { - ::core::intrinsics::autodiff(f4::<> as fn(), df4::<>, ()) -} +pub fn df4() -> () { ::core::intrinsics::autodiff(f4 as fn(), df4, ()) } #[rustc_autodiff] pub fn f5(x: &[f64], y: f64) -> f64 { ::core::panicking::panic("not implemented") } #[rustc_autodiff(Forward, 1, Const, Dual, Const)] pub fn df5_y(x: &[f64], y: f64, by_0: f64) -> f64 { - ::core::intrinsics::autodiff(f5::<> as fn(_: &[f64], _: f64) -> f64, - df5_y::<>, (x, y, by_0)) + ::core::intrinsics::autodiff(f5 as fn(_: &[f64], _: f64) -> f64, df5_y, + (x, y, by_0)) } #[rustc_autodiff(Forward, 1, Dual, Const, Const)] pub fn df5_x(x: &[f64], bx_0: &[f64], y: f64) -> f64 { - ::core::intrinsics::autodiff(f5::<> as fn(_: &[f64], _: f64) -> f64, - df5_x::<>, (x, bx_0, y)) + ::core::intrinsics::autodiff(f5 as fn(_: &[f64], _: f64) -> f64, df5_x, + (x, bx_0, y)) } #[rustc_autodiff(Reverse, 1, Duplicated, Const, Active)] pub fn df5_rev(x: &[f64], dx_0: &mut [f64], y: f64, dret: f64) -> f64 { - ::core::intrinsics::autodiff(f5::<> as fn(_: &[f64], _: f64) -> f64, - df5_rev::<>, (x, dx_0, y, dret)) + ::core::intrinsics::autodiff(f5 as fn(_: &[f64], _: f64) -> f64, df5_rev, + (x, dx_0, y, dret)) } struct DoesNotImplDefault; #[rustc_autodiff] @@ -88,14 +86,13 @@ } #[rustc_autodiff(Forward, 1, Const)] pub fn df6() -> DoesNotImplDefault { - ::core::intrinsics::autodiff(f6::<> as fn() -> DoesNotImplDefault, - df6::<>, ()) + ::core::intrinsics::autodiff(f6 as fn() -> DoesNotImplDefault, df6, ()) } #[rustc_autodiff] pub fn f7(x: f32) -> () {} #[rustc_autodiff(Forward, 1, Const, None)] pub fn df7(x: f32) -> () { - ::core::intrinsics::autodiff(f7::<> as fn(_: f32) -> (), df7::<>, (x,)) + ::core::intrinsics::autodiff(f7 as fn(_: f32) -> (), df7, (x,)) } #[no_mangle] #[rustc_autodiff] @@ -103,32 +100,31 @@ #[rustc_autodiff(Forward, 4, Dual, Dual)] fn f8_3(x: &f32, bx_0: &f32, bx_1: &f32, bx_2: &f32, bx_3: &f32) -> [f32; 5usize] { - ::core::intrinsics::autodiff(f8::<> as fn(_: &f32) -> f32, f8_3::<>, + ::core::intrinsics::autodiff(f8 as fn(_: &f32) -> f32, f8_3, (x, bx_0, bx_1, bx_2, bx_3)) } #[rustc_autodiff(Forward, 4, Dual, DualOnly)] fn f8_2(x: &f32, bx_0: &f32, bx_1: &f32, bx_2: &f32, bx_3: &f32) -> [f32; 4usize] { - ::core::intrinsics::autodiff(f8::<> as fn(_: &f32) -> f32, f8_2::<>, + ::core::intrinsics::autodiff(f8 as fn(_: &f32) -> f32, f8_2, (x, bx_0, bx_1, bx_2, bx_3)) } #[rustc_autodiff(Forward, 1, Dual, DualOnly)] fn f8_1(x: &f32, bx_0: &f32) -> f32 { - ::core::intrinsics::autodiff(f8::<> as fn(_: &f32) -> f32, f8_1::<>, - (x, bx_0)) + ::core::intrinsics::autodiff(f8 as fn(_: &f32) -> f32, f8_1, (x, bx_0)) } pub fn f9() { #[rustc_autodiff] fn inner(x: f32) -> f32 { x * x } #[rustc_autodiff(Forward, 1, Dual, Dual)] fn d_inner_2(x: f32, bx_0: f32) -> (f32, f32) { - ::core::intrinsics::autodiff(inner::<> as fn(_: f32) -> f32, - d_inner_2::<>, (x, bx_0)) + ::core::intrinsics::autodiff(inner as fn(_: f32) -> f32, d_inner_2, + (x, bx_0)) } #[rustc_autodiff(Forward, 1, Dual, DualOnly)] fn d_inner_1(x: f32, bx_0: f32) -> f32 { - ::core::intrinsics::autodiff(inner::<> as fn(_: f32) -> f32, - d_inner_1::<>, (x, bx_0)) + ::core::intrinsics::autodiff(inner as fn(_: f32) -> f32, d_inner_1, + (x, bx_0)) } } #[rustc_autodiff] diff --git a/tests/pretty/autodiff/autodiff_reverse.pp b/tests/pretty/autodiff/autodiff_reverse.pp index e2088e0ac13db..01ac5a5888cfc 100644 --- a/tests/pretty/autodiff/autodiff_reverse.pp +++ b/tests/pretty/autodiff/autodiff_reverse.pp @@ -28,21 +28,21 @@ } #[rustc_autodiff(Reverse, 1, Duplicated, Const, Active)] pub fn df1(x: &[f64], dx_0: &mut [f64], y: f64, dret: f64) -> f64 { - ::core::intrinsics::autodiff(f1::<> as fn(_: &[f64], _: f64) -> f64, - df1::<>, (x, dx_0, y, dret)) + ::core::intrinsics::autodiff(f1 as fn(_: &[f64], _: f64) -> f64, df1, + (x, dx_0, y, dret)) } #[rustc_autodiff] pub fn f2() {} #[rustc_autodiff(Reverse, 1, None)] -pub fn df2() { ::core::intrinsics::autodiff(f2::<> as fn(), df2::<>, ()) } +pub fn df2() { ::core::intrinsics::autodiff(f2 as fn(), df2, ()) } #[rustc_autodiff] pub fn f3(x: &[f64], y: f64) -> f64 { ::core::panicking::panic("not implemented") } #[rustc_autodiff(Reverse, 1, Duplicated, Const, Active)] pub fn df3(x: &[f64], dx_0: &mut [f64], y: f64, dret: f64) -> f64 { - ::core::intrinsics::autodiff(f3::<> as fn(_: &[f64], _: f64) -> f64, - df3::<>, (x, dx_0, y, dret)) + ::core::intrinsics::autodiff(f3 as fn(_: &[f64], _: f64) -> f64, df3, + (x, dx_0, y, dret)) } enum Foo { Reverse, } use Foo::Reverse; @@ -50,7 +50,7 @@ pub fn f4(x: f32) { ::core::panicking::panic("not implemented") } #[rustc_autodiff(Reverse, 1, Const, None)] pub fn df4(x: f32) { - ::core::intrinsics::autodiff(f4::<> as fn(_: f32), df4::<>, (x,)) + ::core::intrinsics::autodiff(f4 as fn(_: f32), df4, (x,)) } #[rustc_autodiff] pub fn f5(x: *const f32, y: &f32) { @@ -58,7 +58,7 @@ } #[rustc_autodiff(Reverse, 1, DuplicatedOnly, Duplicated, None)] pub unsafe fn df5(x: *const f32, dx_0: *mut f32, y: &f32, dy_0: &mut f32) { - ::core::intrinsics::autodiff(f5::<> as fn(_: *const f32, _: &f32), - df5::<>, (x, dx_0, y, dy_0)) + ::core::intrinsics::autodiff(f5 as fn(_: *const f32, _: &f32), df5, + (x, dx_0, y, dy_0)) } fn main() {} diff --git a/tests/pretty/autodiff/inherent_impl.pp b/tests/pretty/autodiff/inherent_impl.pp index d3a5a71b8bcbf..d175fbdecf1e0 100644 --- a/tests/pretty/autodiff/inherent_impl.pp +++ b/tests/pretty/autodiff/inherent_impl.pp @@ -30,7 +30,7 @@ } #[rustc_autodiff(Reverse, 1, Const, Active, Active)] fn df(&self, x: f64, dret: f64) -> (f64, f64) { - ::core::intrinsics::autodiff(Self::f::<> as - fn(_: &Self, _: f64) -> f64, Self::df::<>, (self, x, dret)) + ::core::intrinsics::autodiff(Self::f as fn(_: &Self, _: f64) -> f64, + Self::df, (self, x, dret)) } } diff --git a/tests/ui/consts/too_generic_eval_ice.current.stderr b/tests/ui/consts/too_generic_eval_ice.current.stderr index 061945e344ede..dd5c3bd51bc52 100644 --- a/tests/ui/consts/too_generic_eval_ice.current.stderr +++ b/tests/ui/consts/too_generic_eval_ice.current.stderr @@ -30,15 +30,15 @@ LL | [5; Self::HOST_SIZE] == [6; 0] | = help: the trait `PartialEq<[{integer}; 0]>` is not implemented for `[{integer}; Self::HOST_SIZE]` = help: the following other types implement trait `PartialEq`: + `&[T; N]` implements `PartialEq>` `&[T]` implements `PartialEq>` `&[T]` implements `PartialEq>` + `&[T]` implements `PartialEq>` `&[T]` implements `PartialEq<[U; N]>` `&[u8; N]` implements `PartialEq` `&[u8; N]` implements `PartialEq` `&[u8]` implements `PartialEq` - `&[u8]` implements `PartialEq` - `&mut [T]` implements `PartialEq>` - and 13 others + and 18 others error: aborting due to 4 previous errors diff --git a/tests/ui/imports/nested-module-typo-inaccessible-issue-131366.rs b/tests/ui/imports/nested-module-typo-inaccessible-issue-131366.rs new file mode 100644 index 0000000000000..39dc8cd381268 --- /dev/null +++ b/tests/ui/imports/nested-module-typo-inaccessible-issue-131366.rs @@ -0,0 +1,19 @@ +//! Regression test for https://github.com/rust-lang/rust/issues/131366. +//! Similar spelling does not make a private module or a non-module importable. + +//@ edition: 2021 +#![allow(unused_imports, dead_code)] + +mod private { + mod collections { pub struct Item; } +} +use private::collection::Item; +//~^ ERROR unresolved import `private::collection` + +mod non_module { + pub struct Collections; +} +use non_module::Collection::Item; +//~^ ERROR unresolved import `non_module::Collection` + +fn main() {} diff --git a/tests/ui/imports/nested-module-typo-inaccessible-issue-131366.stderr b/tests/ui/imports/nested-module-typo-inaccessible-issue-131366.stderr new file mode 100644 index 0000000000000..020711207ef38 --- /dev/null +++ b/tests/ui/imports/nested-module-typo-inaccessible-issue-131366.stderr @@ -0,0 +1,15 @@ +error[E0432]: unresolved import `private::collection` + --> $DIR/nested-module-typo-inaccessible-issue-131366.rs:10:14 + | +LL | use private::collection::Item; + | ^^^^^^^^^^ could not find `collection` in `private` + +error[E0432]: unresolved import `non_module::Collection` + --> $DIR/nested-module-typo-inaccessible-issue-131366.rs:16:17 + | +LL | use non_module::Collection::Item; + | ^^^^^^^^^^ could not find `Collection` in `non_module` + +error: aborting due to 2 previous errors + +For more information about this error, try `rustc --explain E0432`. diff --git a/tests/ui/imports/nested-module-typo-issue-131366.fixed b/tests/ui/imports/nested-module-typo-issue-131366.fixed new file mode 100644 index 0000000000000..ff1c4eb2532b2 --- /dev/null +++ b/tests/ui/imports/nested-module-typo-issue-131366.fixed @@ -0,0 +1,46 @@ +//! Regression test for https://github.com/rust-lang/rust/issues/131366. +//! Suggest accessible, similarly named modules within the resolved import prefix. + +//@ edition: 2021 +//@ run-rustfix +#![allow(unused_imports, dead_code)] + +use std::collections::HashMap; +//~^ ERROR unresolved import `std::collection` + +mod local { + pub mod collections { + pub struct Item; + } + pub use collections as containers; + pub enum Choices { First } +} + +use local::collections::Item; +//~^ ERROR unresolved import `local::collection` +use local::containers::Item as Alias; +//~^ ERROR unresolved import `local::container` +use local::Choices::First; +//~^ ERROR unresolved import `local::Choice` + +mod root_module {} +use crate::root_module::*; +//~^ ERROR unresolved import `crate::root_modul` + +macro_rules! import { + ($module:ident) => { use local::$module::Item as MacroItem; }; +} +import!(collections); +//~^ ERROR unresolved import `local::collection` + +mod accessible { + pub mod collections { + pub struct Item; + } + use collections as collection; +} +// The closer match is a private alias, so suggest the accessible module instead. +use accessible::collections::Item as AccessibleItem; +//~^ ERROR unresolved import `accessible::collectio` + +fn main() {} diff --git a/tests/ui/imports/nested-module-typo-issue-131366.rs b/tests/ui/imports/nested-module-typo-issue-131366.rs new file mode 100644 index 0000000000000..2d0e81e2e0e3a --- /dev/null +++ b/tests/ui/imports/nested-module-typo-issue-131366.rs @@ -0,0 +1,46 @@ +//! Regression test for https://github.com/rust-lang/rust/issues/131366. +//! Suggest accessible, similarly named modules within the resolved import prefix. + +//@ edition: 2021 +//@ run-rustfix +#![allow(unused_imports, dead_code)] + +use std::collection::HashMap; +//~^ ERROR unresolved import `std::collection` + +mod local { + pub mod collections { + pub struct Item; + } + pub use collections as containers; + pub enum Choices { First } +} + +use local::collection::Item; +//~^ ERROR unresolved import `local::collection` +use local::container::Item as Alias; +//~^ ERROR unresolved import `local::container` +use local::Choice::First; +//~^ ERROR unresolved import `local::Choice` + +mod root_module {} +use crate::root_modul::*; +//~^ ERROR unresolved import `crate::root_modul` + +macro_rules! import { + ($module:ident) => { use local::$module::Item as MacroItem; }; +} +import!(collection); +//~^ ERROR unresolved import `local::collection` + +mod accessible { + pub mod collections { + pub struct Item; + } + use collections as collection; +} +// The closer match is a private alias, so suggest the accessible module instead. +use accessible::collectio::Item as AccessibleItem; +//~^ ERROR unresolved import `accessible::collectio` + +fn main() {} diff --git a/tests/ui/imports/nested-module-typo-issue-131366.stderr b/tests/ui/imports/nested-module-typo-issue-131366.stderr new file mode 100644 index 0000000000000..1173fc1fb5c57 --- /dev/null +++ b/tests/ui/imports/nested-module-typo-issue-131366.stderr @@ -0,0 +1,80 @@ +error[E0432]: unresolved import `std::collection` + --> $DIR/nested-module-typo-issue-131366.rs:8:10 + | +LL | use std::collection::HashMap; + | ^^^^^^^^^^ could not find `collection` in `std` + | +help: a module with a similar name exists + | +LL | use std::collections::HashMap; + | + + +error[E0432]: unresolved import `local::collection` + --> $DIR/nested-module-typo-issue-131366.rs:19:12 + | +LL | use local::collection::Item; + | ^^^^^^^^^^ could not find `collection` in `local` + | +help: a module with a similar name exists + | +LL | use local::collections::Item; + | + + +error[E0432]: unresolved import `local::container` + --> $DIR/nested-module-typo-issue-131366.rs:21:12 + | +LL | use local::container::Item as Alias; + | ^^^^^^^^^ could not find `container` in `local` + | +help: a module with a similar name exists + | +LL | use local::containers::Item as Alias; + | + + +error[E0432]: unresolved import `local::Choice` + --> $DIR/nested-module-typo-issue-131366.rs:23:12 + | +LL | use local::Choice::First; + | ^^^^^^ could not find `Choice` in `local` + | +help: an enum with a similar name exists + | +LL | use local::Choices::First; + | + + +error[E0432]: unresolved import `accessible::collectio` + --> $DIR/nested-module-typo-issue-131366.rs:43:17 + | +LL | use accessible::collectio::Item as AccessibleItem; + | ^^^^^^^^^ could not find `collectio` in `accessible` + | +help: a module with a similar name exists + | +LL | use accessible::collections::Item as AccessibleItem; + | ++ + +error[E0432]: unresolved import `crate::root_modul` + --> $DIR/nested-module-typo-issue-131366.rs:27:12 + | +LL | use crate::root_modul::*; + | ^^^^^^^^^^ could not find `root_modul` in the crate root + | +help: a module with a similar name exists + | +LL | use crate::root_module::*; + | + + +error[E0432]: unresolved import `local::collection` + --> $DIR/nested-module-typo-issue-131366.rs:33:9 + | +LL | import!(collection); + | ^^^^^^^^^^ could not find `collection` in `local` + | +help: a module with a similar name exists + | +LL | import!(collections); + | + + +error: aborting due to 7 previous errors + +For more information about this error, try `rustc --explain E0432`. diff --git a/tests/ui/lint/unused/must-use-box-from-raw.stderr b/tests/ui/lint/unused/must-use-box-from-raw.stderr index 4898db7fe3ddd..7eab99e97cd82 100644 --- a/tests/ui/lint/unused/must-use-box-from-raw.stderr +++ b/tests/ui/lint/unused/must-use-box-from-raw.stderr @@ -10,10 +10,10 @@ note: the lint level is defined here | LL | #![warn(unused_must_use)] | ^^^^^^^^^^^^^^^ -help: use `let _ = ...` to ignore the resulting value +help: use `let _unused = ...` to ignore the resulting value without dropping it immediately | -LL | let _ = Box::from_raw(ptr); - | +++++++ +LL | let _unused = Box::from_raw(ptr); + | +++++++++++++ warning: 1 warning emitted diff --git a/tests/ui/lint/unused/must-use-lock-guard-issue-162843.fixed b/tests/ui/lint/unused/must-use-lock-guard-issue-162843.fixed new file mode 100644 index 0000000000000..13289df3677fd --- /dev/null +++ b/tests/ui/lint/unused/must-use-lock-guard-issue-162843.fixed @@ -0,0 +1,41 @@ +//@ run-rustfix +//! Regression test for https://github.com/rust-lang/rust/issues/162843. +//! Must-use values with nontrivial drop should suggest a binding that preserves drop timing. +#![deny(unused_must_use)] + +use std::sync::Mutex; + +struct Guard; + +impl Drop for Guard { + fn drop(&mut self) {} +} + +#[must_use] +fn guard() -> Guard { + Guard +} + +#[must_use] +fn value() -> u8 { + 0 +} + +#[must_use] +fn vec_values() -> Vec { + vec![1, 2, 3] +} + +#[must_use] +fn box_value() -> Box { + Box::new(0) +} + +fn main() { + let mutex = Mutex::new(0); + let _unused = mutex.lock().unwrap(); //~ ERROR unused `std::sync::MutexGuard` that must be used + let _unused = guard(); //~ ERROR unused return value of `guard` that must be used + let _ = value(); //~ ERROR unused return value of `value` that must be used + let _ = vec_values(); //~ ERROR unused return value of `vec_values` that must be used + let _ = box_value(); //~ ERROR unused return value of `box_value` that must be used +} diff --git a/tests/ui/lint/unused/must-use-lock-guard-issue-162843.rs b/tests/ui/lint/unused/must-use-lock-guard-issue-162843.rs new file mode 100644 index 0000000000000..1b0de8242a7a7 --- /dev/null +++ b/tests/ui/lint/unused/must-use-lock-guard-issue-162843.rs @@ -0,0 +1,41 @@ +//@ run-rustfix +//! Regression test for https://github.com/rust-lang/rust/issues/162843. +//! Must-use values with nontrivial drop should suggest a binding that preserves drop timing. +#![deny(unused_must_use)] + +use std::sync::Mutex; + +struct Guard; + +impl Drop for Guard { + fn drop(&mut self) {} +} + +#[must_use] +fn guard() -> Guard { + Guard +} + +#[must_use] +fn value() -> u8 { + 0 +} + +#[must_use] +fn vec_values() -> Vec { + vec![1, 2, 3] +} + +#[must_use] +fn box_value() -> Box { + Box::new(0) +} + +fn main() { + let mutex = Mutex::new(0); + mutex.lock().unwrap(); //~ ERROR unused `std::sync::MutexGuard` that must be used + guard(); //~ ERROR unused return value of `guard` that must be used + value(); //~ ERROR unused return value of `value` that must be used + vec_values(); //~ ERROR unused return value of `vec_values` that must be used + box_value(); //~ ERROR unused return value of `box_value` that must be used +} diff --git a/tests/ui/lint/unused/must-use-lock-guard-issue-162843.stderr b/tests/ui/lint/unused/must-use-lock-guard-issue-162843.stderr new file mode 100644 index 0000000000000..8fa5c693f2561 --- /dev/null +++ b/tests/ui/lint/unused/must-use-lock-guard-issue-162843.stderr @@ -0,0 +1,63 @@ +error: unused `std::sync::MutexGuard` that must be used + --> $DIR/must-use-lock-guard-issue-162843.rs:36:5 + | +LL | mutex.lock().unwrap(); + | ^^^^^^^^^^^^^^^^^^^^^ + | + = note: if unused the Mutex will immediately unlock +note: the lint level is defined here + --> $DIR/must-use-lock-guard-issue-162843.rs:4:9 + | +LL | #![deny(unused_must_use)] + | ^^^^^^^^^^^^^^^ +help: use `let _unused = ...` to ignore the resulting value without dropping it immediately + | +LL | let _unused = mutex.lock().unwrap(); + | +++++++++++++ + +error: unused return value of `guard` that must be used + --> $DIR/must-use-lock-guard-issue-162843.rs:37:5 + | +LL | guard(); + | ^^^^^^^ + | +help: use `let _unused = ...` to ignore the resulting value without dropping it immediately + | +LL | let _unused = guard(); + | +++++++++++++ + +error: unused return value of `value` that must be used + --> $DIR/must-use-lock-guard-issue-162843.rs:38:5 + | +LL | value(); + | ^^^^^^^ + | +help: use `let _ = ...` to ignore the resulting value + | +LL | let _ = value(); + | +++++++ + +error: unused return value of `vec_values` that must be used + --> $DIR/must-use-lock-guard-issue-162843.rs:39:5 + | +LL | vec_values(); + | ^^^^^^^^^^^^ + | +help: use `let _ = ...` to ignore the resulting value + | +LL | let _ = vec_values(); + | +++++++ + +error: unused return value of `box_value` that must be used + --> $DIR/must-use-lock-guard-issue-162843.rs:40:5 + | +LL | box_value(); + | ^^^^^^^^^^^ + | +help: use `let _ = ...` to ignore the resulting value + | +LL | let _ = box_value(); + | +++++++ + +error: aborting due to 5 previous errors + diff --git a/tests/ui/lint/unused/must_use-result-unit-uninhabited.stderr b/tests/ui/lint/unused/must_use-result-unit-uninhabited.stderr index 230c97092b526..13c51a588fb03 100644 --- a/tests/ui/lint/unused/must_use-result-unit-uninhabited.stderr +++ b/tests/ui/lint/unused/must_use-result-unit-uninhabited.stderr @@ -75,10 +75,10 @@ LL | self.generate(); | ^^^^^^^^^^^^^^^ | = note: this `Result` may be an `Err` variant, which should be handled -help: use `let _ = ...` to ignore the resulting value +help: use `let _unused = ...` to ignore the resulting value without dropping it immediately | -LL | let _ = self.generate(); - | +++++++ +LL | let _unused = self.generate(); + | +++++++++++++ error: aborting due to 7 previous errors diff --git a/tests/ui/lint/unused/unused-async.stderr b/tests/ui/lint/unused/unused-async.stderr index e93a40658f3c2..43bc73d2758c1 100644 --- a/tests/ui/lint/unused/unused-async.stderr +++ b/tests/ui/lint/unused/unused-async.stderr @@ -17,10 +17,10 @@ error: unused return value of `foo` that must be used LL | foo(); | ^^^^^ | -help: use `let _ = ...` to ignore the resulting value +help: use `let _unused = ...` to ignore the resulting value without dropping it immediately | -LL | let _ = foo(); - | +++++++ +LL | let _unused = foo(); + | +++++++++++++ error: unused output of future returned by `foo` that must be used --> $DIR/unused-async.rs:33:5 @@ -47,10 +47,10 @@ error: unused return value of `bar` that must be used LL | bar(); | ^^^^^ | -help: use `let _ = ...` to ignore the resulting value +help: use `let _unused = ...` to ignore the resulting value without dropping it immediately | -LL | let _ = bar(); - | +++++++ +LL | let _unused = bar(); + | +++++++++++++ error: unused implementer of `Future` that must be used --> $DIR/unused-async.rs:37:5 diff --git a/tests/ui/macros/assert-ne-no-invalid-help-issue-146204.stderr b/tests/ui/macros/assert-ne-no-invalid-help-issue-146204.stderr index 8c3451af7235f..6d36dbdee7ba4 100644 --- a/tests/ui/macros/assert-ne-no-invalid-help-issue-146204.stderr +++ b/tests/ui/macros/assert-ne-no-invalid-help-issue-146204.stderr @@ -6,15 +6,15 @@ LL | assert_ne!(buf, b"----"); | = help: the trait `PartialEq<&[u8; 4]>` is not implemented for `[u8; 4]` = help: the following other types implement trait `PartialEq`: + `&[T; N]` implements `PartialEq>` `&[T]` implements `PartialEq>` `&[T]` implements `PartialEq>` + `&[T]` implements `PartialEq>` `&[T]` implements `PartialEq<[U; N]>` `&[u8; N]` implements `PartialEq` `&[u8; N]` implements `PartialEq` `&[u8]` implements `PartialEq` - `&[u8]` implements `PartialEq` - `&mut [T]` implements `PartialEq>` - and 13 others + and 18 others error[E0277]: can't compare `[u8; 4]` with `&[u8; 4]` --> $DIR/assert-ne-no-invalid-help-issue-146204.rs:19:5 @@ -24,15 +24,15 @@ LL | assert_eq!(buf, b"----"); | = help: the trait `PartialEq<&[u8; 4]>` is not implemented for `[u8; 4]` = help: the following other types implement trait `PartialEq`: + `&[T; N]` implements `PartialEq>` `&[T]` implements `PartialEq>` `&[T]` implements `PartialEq>` + `&[T]` implements `PartialEq>` `&[T]` implements `PartialEq<[U; N]>` `&[u8; N]` implements `PartialEq` `&[u8; N]` implements `PartialEq` `&[u8]` implements `PartialEq` - `&[u8]` implements `PartialEq` - `&mut [T]` implements `PartialEq>` - and 13 others + and 18 others error[E0277]: can't compare `[u8; 4]` with `&[u8; 4]` --> $DIR/assert-ne-no-invalid-help-issue-146204.rs:5:30 diff --git a/tests/ui/unresolved/unresolved-import.fixed b/tests/ui/unresolved/unresolved-import.fixed new file mode 100644 index 0000000000000..2132e5e21859f --- /dev/null +++ b/tests/ui/unresolved/unresolved-import.fixed @@ -0,0 +1,70 @@ +//@ edition:2015 +//@ run-rustfix + +#![allow(unused_imports, dead_code)] + +use food::beans; +//~^ ERROR unresolved import `foo` [E0432] +//~| NOTE could not find `foo` in the crate root +//~| HELP a module with a similar name exists +//~| SUGGESTION food + +use bar::Bar as x; +//~^ ERROR unresolved import `bar::Baz` [E0432] +//~| NOTE no `Baz` in `bar` +//~| HELP a similar name exists in the module +//~| SUGGESTION Bar + +use food::bag; +//~^ ERROR unresolved import `food::baz` +//~| NOTE no `baz` in `food` +//~| HELP a similar name exists in the module +//~| SUGGESTION bag + +use food::{beans as Foo}; +//~^ ERROR unresolved import `food::beens` [E0432] +//~| NOTE no `beens` in `food` +//~| HELP a similar name exists in the module +//~| SUGGESTION beans + +mod bar { + pub struct Bar; +} + +mod food { + pub use self::zug::baz::{self as bag, Foobar as beans}; + + mod zug { + pub mod baz { + //~^ NOTE module `food::zug::baz` exists but is inaccessible + //~| NOTE not accessible + pub struct Foobar; + } + } +} + +mod m { + enum MyEnum { + MyVariant + } + + use self::MyEnum::*; + //~^ ERROR unresolved import `MyEnum` [E0432] + //~| HELP a similar path exists + //~| SUGGESTION self::MyEnum +} + +mod items { + enum Enum { + Variant + } + + use self::Enum::*; + //~^ ERROR unresolved import `Enum` [E0432] + //~| HELP a similar path exists + //~| SUGGESTION self::Enum + + fn item() {} +} + +fn main() {} diff --git a/tests/ui/unresolved/unresolved-import.rs b/tests/ui/unresolved/unresolved-import.rs index 8795a5342b2fd..ce9bf73537492 100644 --- a/tests/ui/unresolved/unresolved-import.rs +++ b/tests/ui/unresolved/unresolved-import.rs @@ -1,9 +1,13 @@ //@ edition:2015 -use foo::bar; +//@ run-rustfix + +#![allow(unused_imports, dead_code)] + +use foo::beans; //~^ ERROR unresolved import `foo` [E0432] -//~| NOTE use of unresolved module or unlinked crate `foo` -//~| HELP you might be missing a crate named `foo` -//~| SUGGESTION extern crate foo; +//~| NOTE could not find `foo` in the crate root +//~| HELP a module with a similar name exists +//~| SUGGESTION food use bar::Baz as x; //~^ ERROR unresolved import `bar::Baz` [E0432] diff --git a/tests/ui/unresolved/unresolved-import.stderr b/tests/ui/unresolved/unresolved-import.stderr index a5704787688a9..7aac9dc683349 100644 --- a/tests/ui/unresolved/unresolved-import.stderr +++ b/tests/ui/unresolved/unresolved-import.stderr @@ -1,16 +1,16 @@ error[E0432]: unresolved import `foo` - --> $DIR/unresolved-import.rs:2:5 + --> $DIR/unresolved-import.rs:6:5 | -LL | use foo::bar; - | ^^^ use of unresolved module or unlinked crate `foo` +LL | use foo::beans; + | ^^^ could not find `foo` in the crate root | -help: you might be missing a crate named `foo`, add it to your project and import it in your code - | -LL + extern crate foo; +help: a module with a similar name exists | +LL | use food::beans; + | + error[E0432]: unresolved import `bar::Baz` - --> $DIR/unresolved-import.rs:8:5 + --> $DIR/unresolved-import.rs:12:5 | LL | use bar::Baz as x; | ^^^^^---^^^^^ @@ -24,7 +24,7 @@ LL + use bar::Bar as x; | error[E0432]: unresolved import `food::baz` - --> $DIR/unresolved-import.rs:14:5 + --> $DIR/unresolved-import.rs:18:5 | LL | use food::baz; | ^^^^^^--- @@ -32,7 +32,7 @@ LL | use food::baz; | no `baz` in `food` | note: module `food::zug::baz` exists but is inaccessible - --> $DIR/unresolved-import.rs:34:9 + --> $DIR/unresolved-import.rs:38:9 | LL | pub mod baz { | ^^^^^^^^^^^ not accessible @@ -43,7 +43,7 @@ LL + use food::bag; | error[E0432]: unresolved import `food::beens` - --> $DIR/unresolved-import.rs:20:12 + --> $DIR/unresolved-import.rs:24:12 | LL | use food::{beens as Foo}; | -----^^^^^^^ @@ -57,7 +57,7 @@ LL + use food::{beans as Foo}; | error[E0432]: unresolved import `MyEnum` - --> $DIR/unresolved-import.rs:47:9 + --> $DIR/unresolved-import.rs:51:9 | LL | use MyEnum::*; | ^^^^^^ @@ -68,7 +68,7 @@ LL | use self::MyEnum::*; | ++++++ error[E0432]: unresolved import `Enum` - --> $DIR/unresolved-import.rs:58:9 + --> $DIR/unresolved-import.rs:62:9 | LL | use Enum::*; | ^^^^