diff options
Diffstat (limited to 'compiler')
58 files changed, 625 insertions, 505 deletions
diff --git a/compiler/rustc_arena/src/lib.rs b/compiler/rustc_arena/src/lib.rs index 06eb8a185be..bf8a7eb293e 100644 --- a/compiler/rustc_arena/src/lib.rs +++ b/compiler/rustc_arena/src/lib.rs @@ -15,7 +15,6 @@ #![feature(dropck_eyepatch)] #![feature(new_uninit)] #![feature(maybe_uninit_slice)] -#![feature(min_specialization)] #![feature(decl_macro)] #![feature(pointer_byte_offsets)] #![feature(rustc_attrs)] @@ -44,23 +43,6 @@ fn outline<F: FnOnce() -> R, R>(f: F) -> R { f() } -/// An arena that can hold objects of only one type. -pub struct TypedArena<T> { - /// A pointer to the next object to be allocated. - ptr: Cell<*mut T>, - - /// A pointer to the end of the allocated area. When this pointer is - /// reached, a new chunk is allocated. - end: Cell<*mut T>, - - /// A vector of arena chunks. - chunks: RefCell<Vec<ArenaChunk<T>>>, - - /// Marker indicating that dropping the arena causes its owned - /// instances of `T` to be dropped. - _own: PhantomData<T>, -} - struct ArenaChunk<T = u8> { /// The raw storage for the arena chunk. storage: NonNull<[MaybeUninit<T>]>, @@ -130,6 +112,23 @@ impl<T> ArenaChunk<T> { const PAGE: usize = 4096; const HUGE_PAGE: usize = 2 * 1024 * 1024; +/// An arena that can hold objects of only one type. +pub struct TypedArena<T> { + /// A pointer to the next object to be allocated. + ptr: Cell<*mut T>, + + /// A pointer to the end of the allocated area. When this pointer is + /// reached, a new chunk is allocated. + end: Cell<*mut T>, + + /// A vector of arena chunks. + chunks: RefCell<Vec<ArenaChunk<T>>>, + + /// Marker indicating that dropping the arena causes its owned + /// instances of `T` to be dropped. + _own: PhantomData<T>, +} + impl<T> Default for TypedArena<T> { /// Creates a new `TypedArena`. fn default() -> TypedArena<T> { @@ -144,77 +143,6 @@ impl<T> Default for TypedArena<T> { } } -trait IterExt<T> { - fn alloc_from_iter(self, arena: &TypedArena<T>) -> &mut [T]; -} - -impl<I, T> IterExt<T> for I -where - I: IntoIterator<Item = T>, -{ - // This default collects into a `SmallVec` and then allocates by copying - // from it. The specializations below for types like `Vec` are more - // efficient, copying directly without the intermediate collecting step. - // This default could be made more efficient, like - // `DroplessArena::alloc_from_iter`, but it's not hot enough to bother. - #[inline] - default fn alloc_from_iter(self, arena: &TypedArena<T>) -> &mut [T] { - let vec: SmallVec<[_; 8]> = self.into_iter().collect(); - vec.alloc_from_iter(arena) - } -} - -impl<T, const N: usize> IterExt<T> for std::array::IntoIter<T, N> { - #[inline] - fn alloc_from_iter(self, arena: &TypedArena<T>) -> &mut [T] { - let len = self.len(); - if len == 0 { - return &mut []; - } - // Move the content to the arena by copying and then forgetting it. - let start_ptr = arena.alloc_raw_slice(len); - unsafe { - self.as_slice().as_ptr().copy_to_nonoverlapping(start_ptr, len); - mem::forget(self); - slice::from_raw_parts_mut(start_ptr, len) - } - } -} - -impl<T> IterExt<T> for Vec<T> { - #[inline] - fn alloc_from_iter(mut self, arena: &TypedArena<T>) -> &mut [T] { - let len = self.len(); - if len == 0 { - return &mut []; - } - // Move the content to the arena by copying and then forgetting it. - let start_ptr = arena.alloc_raw_slice(len); - unsafe { - self.as_ptr().copy_to_nonoverlapping(start_ptr, len); - self.set_len(0); - slice::from_raw_parts_mut(start_ptr, len) - } - } -} - -impl<A: smallvec::Array> IterExt<A::Item> for SmallVec<A> { - #[inline] - fn alloc_from_iter(mut self, arena: &TypedArena<A::Item>) -> &mut [A::Item] { - let len = self.len(); - if len == 0 { - return &mut []; - } - // Move the content to the arena by copying and then forgetting it. - let start_ptr = arena.alloc_raw_slice(len); - unsafe { - self.as_ptr().copy_to_nonoverlapping(start_ptr, len); - self.set_len(0); - slice::from_raw_parts_mut(start_ptr, len) - } - } -} - impl<T> TypedArena<T> { /// Allocates an object in the `TypedArena`, returning a reference to it. #[inline] @@ -270,8 +198,35 @@ impl<T> TypedArena<T> { #[inline] pub fn alloc_from_iter<I: IntoIterator<Item = T>>(&self, iter: I) -> &mut [T] { + // This implementation is entirely separate to + // `DroplessIterator::alloc_from_iter`, even though conceptually they + // are the same. + // + // `DroplessIterator` (in the fast case) writes elements from the + // iterator one at a time into the allocated memory. That's easy + // because the elements don't implement `Drop`. But for `TypedArena` + // they do implement `Drop`, which means that if the iterator panics we + // could end up with some allocated-but-uninitialized elements, which + // will then cause UB in `TypedArena::drop`. + // + // Instead we use an approach where any iterator panic will occur + // before the memory is allocated. This function is much less hot than + // `DroplessArena::alloc_from_iter`, so it doesn't need to be + // hyper-optimized. assert!(mem::size_of::<T>() != 0); - iter.alloc_from_iter(self) + + let mut vec: SmallVec<[_; 8]> = iter.into_iter().collect(); + if vec.is_empty() { + return &mut []; + } + // Move the content to the arena by copying and then forgetting it. + let len = vec.len(); + let start_ptr = self.alloc_raw_slice(len); + unsafe { + vec.as_ptr().copy_to_nonoverlapping(start_ptr, len); + vec.set_len(0); + slice::from_raw_parts_mut(start_ptr, len) + } } /// Grows the arena. diff --git a/compiler/rustc_ast/src/token.rs b/compiler/rustc_ast/src/token.rs index 300b1486f9b..09bfbd02198 100644 --- a/compiler/rustc_ast/src/token.rs +++ b/compiler/rustc_ast/src/token.rs @@ -446,7 +446,7 @@ impl Token { } } - /// Returns `true` if the token can appear at the start of an pattern. + /// Returns `true` if the token can appear at the start of a pattern. /// /// Shamelessly borrowed from `can_begin_expr`, only used for diagnostics right now. pub fn can_begin_pattern(&self) -> bool { diff --git a/compiler/rustc_ast_lowering/messages.ftl b/compiler/rustc_ast_lowering/messages.ftl index 8115c4b55b0..aaeef1ff77d 100644 --- a/compiler/rustc_ast_lowering/messages.ftl +++ b/compiler/rustc_ast_lowering/messages.ftl @@ -99,7 +99,7 @@ ast_lowering_misplaced_double_dot = .note = only allowed in tuple, tuple struct, and slice patterns ast_lowering_misplaced_impl_trait = - `impl Trait` only allowed in function and inherent method return types, not in {$position} + `impl Trait` only allowed in function and inherent method argument and return types, not in {$position} ast_lowering_misplaced_relax_trait_bound = `?Trait` bounds are only permitted at the point where a type parameter is declared diff --git a/compiler/rustc_ast_lowering/src/format.rs b/compiler/rustc_ast_lowering/src/format.rs index afcf8b15cd8..45a9bebfcf6 100644 --- a/compiler/rustc_ast_lowering/src/format.rs +++ b/compiler/rustc_ast_lowering/src/format.rs @@ -410,15 +410,11 @@ fn expand_format_args<'hir>( let format_options = use_format_options.then(|| { // Generate: // &[format_spec_0, format_spec_1, format_spec_2] - let elements: Vec<_> = fmt - .template - .iter() - .filter_map(|piece| { - let FormatArgsPiece::Placeholder(placeholder) = piece else { return None }; - Some(make_format_spec(ctx, macsp, placeholder, &mut argmap)) - }) - .collect(); - ctx.expr_array_ref(macsp, ctx.arena.alloc_from_iter(elements)) + let elements = ctx.arena.alloc_from_iter(fmt.template.iter().filter_map(|piece| { + let FormatArgsPiece::Placeholder(placeholder) = piece else { return None }; + Some(make_format_spec(ctx, macsp, placeholder, &mut argmap)) + })); + ctx.expr_array_ref(macsp, elements) }); let arguments = fmt.arguments.all_args(); @@ -477,10 +473,8 @@ fn expand_format_args<'hir>( // <core::fmt::Argument>::new_debug(&arg2), // … // ] - let elements: Vec<_> = arguments - .iter() - .zip(argmap) - .map(|(arg, ((_, ty), placeholder_span))| { + let elements = ctx.arena.alloc_from_iter(arguments.iter().zip(argmap).map( + |(arg, ((_, ty), placeholder_span))| { let placeholder_span = placeholder_span.unwrap_or(arg.expr.span).with_ctxt(macsp.ctxt()); let arg_span = match arg.kind { @@ -493,9 +487,9 @@ fn expand_format_args<'hir>( hir::ExprKind::AddrOf(hir::BorrowKind::Ref, hir::Mutability::Not, arg), )); make_argument(ctx, placeholder_span, ref_arg, ty) - }) - .collect(); - ctx.expr_array_ref(macsp, ctx.arena.alloc_from_iter(elements)) + }, + )); + ctx.expr_array_ref(macsp, elements) } else { // Generate: // &match (&arg0, &arg1, &…) { @@ -528,19 +522,14 @@ fn expand_format_args<'hir>( make_argument(ctx, placeholder_span, arg, ty) }, )); - let elements: Vec<_> = arguments - .iter() - .map(|arg| { - let arg_expr = ctx.lower_expr(&arg.expr); - ctx.expr( - arg.expr.span.with_ctxt(macsp.ctxt()), - hir::ExprKind::AddrOf(hir::BorrowKind::Ref, hir::Mutability::Not, arg_expr), - ) - }) - .collect(); - let args_tuple = ctx - .arena - .alloc(ctx.expr(macsp, hir::ExprKind::Tup(ctx.arena.alloc_from_iter(elements)))); + let elements = ctx.arena.alloc_from_iter(arguments.iter().map(|arg| { + let arg_expr = ctx.lower_expr(&arg.expr); + ctx.expr( + arg.expr.span.with_ctxt(macsp.ctxt()), + hir::ExprKind::AddrOf(hir::BorrowKind::Ref, hir::Mutability::Not, arg_expr), + ) + })); + let args_tuple = ctx.arena.alloc(ctx.expr(macsp, hir::ExprKind::Tup(elements))); let array = ctx.arena.alloc(ctx.expr(macsp, hir::ExprKind::Array(args))); let match_arms = ctx.arena.alloc_from_iter([ctx.arm(args_pat, array)]); let match_expr = ctx.arena.alloc(ctx.expr_match( diff --git a/compiler/rustc_attr/Cargo.toml b/compiler/rustc_attr/Cargo.toml index 2c4c3a0c263..a14d2796817 100644 --- a/compiler/rustc_attr/Cargo.toml +++ b/compiler/rustc_attr/Cargo.toml @@ -6,14 +6,14 @@ edition = "2021" [lib] [dependencies] +rustc_ast = { path = "../rustc_ast" } rustc_ast_pretty = { path = "../rustc_ast_pretty" } -rustc_serialize = { path = "../rustc_serialize" } -rustc_errors = { path = "../rustc_errors" } -rustc_fluent_macro = { path = "../rustc_fluent_macro" } -rustc_span = { path = "../rustc_span" } rustc_data_structures = { path = "../rustc_data_structures" } +rustc_errors = { path = "../rustc_errors" } rustc_feature = { path = "../rustc_feature" } +rustc_fluent_macro = { path = "../rustc_fluent_macro" } rustc_lexer = { path = "../rustc_lexer" } rustc_macros = { path = "../rustc_macros" } +rustc_serialize = { path = "../rustc_serialize" } rustc_session = { path = "../rustc_session" } -rustc_ast = { path = "../rustc_ast" } +rustc_span = { path = "../rustc_span" } diff --git a/compiler/rustc_attr/src/builtin.rs b/compiler/rustc_attr/src/builtin.rs index ca4b3662a08..6f82d6f9323 100644 --- a/compiler/rustc_attr/src/builtin.rs +++ b/compiler/rustc_attr/src/builtin.rs @@ -162,7 +162,7 @@ pub enum StabilityLevel { is_soft: bool, /// If part of a feature is stabilized and a new feature is added for the remaining parts, /// then the `implied_by` attribute is used to indicate which now-stable feature previously - /// contained a item. + /// contained an item. /// /// ```pseudo-Rust /// #[unstable(feature = "foo", issue = "...")] @@ -846,7 +846,7 @@ pub fn find_deprecation( ), ); } else { - sess.emit_err(session_diagnostics::IncorrectMetaItem2 { + sess.emit_err(session_diagnostics::IncorrectMetaItem { span: meta.span, }); } diff --git a/compiler/rustc_attr/src/session_diagnostics.rs b/compiler/rustc_attr/src/session_diagnostics.rs index ee79545e304..86f27254db2 100644 --- a/compiler/rustc_attr/src/session_diagnostics.rs +++ b/compiler/rustc_attr/src/session_diagnostics.rs @@ -165,15 +165,6 @@ pub(crate) struct MissingIssue { pub span: Span, } -// FIXME: This diagnostic is identical to `IncorrectMetaItem`, barring the error code. Consider -// changing this to `IncorrectMetaItem`. See #51489. -#[derive(Diagnostic)] -#[diag(attr_incorrect_meta_item, code = "E0551")] -pub(crate) struct IncorrectMetaItem2 { - #[primary_span] - pub span: Span, -} - // FIXME: Why is this the same error code as `InvalidReprHintNoParen` and `InvalidReprHintNoValue`? // It is more similar to `IncorrectReprFormatGeneric`. #[derive(Diagnostic)] diff --git a/compiler/rustc_borrowck/src/diagnostics/conflict_errors.rs b/compiler/rustc_borrowck/src/diagnostics/conflict_errors.rs index d676906ff5e..4488276e0e7 100644 --- a/compiler/rustc_borrowck/src/diagnostics/conflict_errors.rs +++ b/compiler/rustc_borrowck/src/diagnostics/conflict_errors.rs @@ -1364,7 +1364,7 @@ impl<'cx, 'tcx> MirBorrowckCtxt<'cx, 'tcx> { err.note(format!( "a for loop advances the iterator for you, the result is stored in `{loop_bind}`." )); - err.help("if you want to call `next` on a iterator within the loop, consider using `while let`."); + err.help("if you want to call `next` on an iterator within the loop, consider using `while let`."); } } diff --git a/compiler/rustc_borrowck/src/diagnostics/mutability_errors.rs b/compiler/rustc_borrowck/src/diagnostics/mutability_errors.rs index 8ca57383e82..e6bde6a8c54 100644 --- a/compiler/rustc_borrowck/src/diagnostics/mutability_errors.rs +++ b/compiler/rustc_borrowck/src/diagnostics/mutability_errors.rs @@ -1359,9 +1359,9 @@ fn suggest_ampmut<'tcx>( None => (false, decl_span), }; - // if the binding already exists and is a reference with a explicit + // if the binding already exists and is a reference with an explicit // lifetime, then we can suggest adding ` mut`. this is special-cased from - // the path without a explicit lifetime. + // the path without an explicit lifetime. if let Ok(src) = tcx.sess.source_map().span_to_snippet(span) && src.starts_with("&'") // note that `& 'a T` is invalid so this is correct. diff --git a/compiler/rustc_borrowck/src/lib.rs b/compiler/rustc_borrowck/src/lib.rs index 990f098efc5..9c77767e7a7 100644 --- a/compiler/rustc_borrowck/src/lib.rs +++ b/compiler/rustc_borrowck/src/lib.rs @@ -1967,7 +1967,7 @@ impl<'cx, 'tcx> MirBorrowckCtxt<'cx, 'tcx> { Reservation(WriteKind::MutableBorrow(BorrowKind::Mut { kind: mut_borrow_kind })) | Write(WriteKind::MutableBorrow(BorrowKind::Mut { kind: mut_borrow_kind })) => { let is_local_mutation_allowed = match mut_borrow_kind { - // `ClosureCapture` is used for mutable variable with a immutable binding. + // `ClosureCapture` is used for mutable variable with an immutable binding. // This is only behaviour difference between `ClosureCapture` and mutable borrows. MutBorrowKind::ClosureCapture => LocalMutationIsAllowed::Yes, MutBorrowKind::Default | MutBorrowKind::TwoPhaseBorrow => { diff --git a/compiler/rustc_borrowck/src/universal_regions.rs b/compiler/rustc_borrowck/src/universal_regions.rs index af437f36b9f..c73192f4404 100644 --- a/compiler/rustc_borrowck/src/universal_regions.rs +++ b/compiler/rustc_borrowck/src/universal_regions.rs @@ -164,7 +164,7 @@ struct UniversalRegionIndices<'tcx> { /// be able to map them to our internal `RegionVid`. This is /// basically equivalent to an `GenericArgs`, except that it also /// contains an entry for `ReStatic` -- it might be nice to just - /// use a args, and then handle `ReStatic` another way. + /// use an args, and then handle `ReStatic` another way. indices: FxHashMap<ty::Region<'tcx>, RegionVid>, /// The vid assigned to `'static`. Used only for diagnostics. @@ -290,7 +290,7 @@ impl<'tcx> UniversalRegions<'tcx> { (FIRST_GLOBAL_INDEX..self.num_universals).map(RegionVid::from_usize) } - /// Returns `true` if `r` is classified as an local region. + /// Returns `true` if `r` is classified as a local region. pub fn is_local_free_region(&self, r: RegionVid) -> bool { self.region_classification(r) == Some(RegionClassification::Local) } diff --git a/compiler/rustc_codegen_cranelift/src/abi/mod.rs b/compiler/rustc_codegen_cranelift/src/abi/mod.rs index 5d775b9b532..5c7d7b20c5d 100644 --- a/compiler/rustc_codegen_cranelift/src/abi/mod.rs +++ b/compiler/rustc_codegen_cranelift/src/abi/mod.rs @@ -30,7 +30,7 @@ fn clif_sig_from_fn_abi<'tcx>( let inputs = fn_abi.args.iter().flat_map(|arg_abi| arg_abi.get_abi_param(tcx).into_iter()); let (return_ptr, returns) = fn_abi.ret.get_abi_return(tcx); - // Sometimes the first param is an pointer to the place where the return value needs to be stored. + // Sometimes the first param is a pointer to the place where the return value needs to be stored. let params: Vec<_> = return_ptr.into_iter().chain(inputs).collect(); Signature { params, returns, call_conv } diff --git a/compiler/rustc_codegen_llvm/src/type_.rs b/compiler/rustc_codegen_llvm/src/type_.rs index 8db6195d931..06b7703672f 100644 --- a/compiler/rustc_codegen_llvm/src/type_.rs +++ b/compiler/rustc_codegen_llvm/src/type_.rs @@ -112,7 +112,7 @@ impl<'ll> CodegenCx<'ll, '_> { } } - /// Return a LLVM type that has at most the required alignment, + /// Return an LLVM type that has at most the required alignment, /// and exactly the required size, as a best-effort padding array. pub(crate) fn type_padding_filler(&self, size: Size, align: Align) -> &'ll Type { let unit = Integer::approximate_align(self, align); diff --git a/compiler/rustc_codegen_ssa/src/traits/type_.rs b/compiler/rustc_codegen_ssa/src/traits/type_.rs index dc3dbd9d819..b1fde8e4d86 100644 --- a/compiler/rustc_codegen_ssa/src/traits/type_.rs +++ b/compiler/rustc_codegen_ssa/src/traits/type_.rs @@ -30,7 +30,7 @@ pub trait BaseTypeMethods<'tcx>: Backend<'tcx> { fn type_ptr_ext(&self, address_space: AddressSpace) -> Self::Type; fn element_type(&self, ty: Self::Type) -> Self::Type; - /// Returns the number of elements in `self` if it is a LLVM vector type. + /// Returns the number of elements in `self` if it is an LLVM vector type. fn vector_length(&self, ty: Self::Type) -> usize; fn float_width(&self, ty: Self::Type) -> usize; diff --git a/compiler/rustc_const_eval/src/transform/check_consts/check.rs b/compiler/rustc_const_eval/src/transform/check_consts/check.rs index d380849fefe..c4d806c5161 100644 --- a/compiler/rustc_const_eval/src/transform/check_consts/check.rs +++ b/compiler/rustc_const_eval/src/transform/check_consts/check.rs @@ -237,7 +237,7 @@ impl<'mir, 'tcx> Checker<'mir, 'tcx> { if self.const_kind() == hir::ConstContext::ConstFn { for (idx, local) in body.local_decls.iter_enumerated() { // Handle the return place below. - if idx == RETURN_PLACE || local.internal { + if idx == RETURN_PLACE { continue; } diff --git a/compiler/rustc_error_codes/src/error_codes/E0551.md b/compiler/rustc_error_codes/src/error_codes/E0551.md index 53db559a4fc..0e078fe71bf 100644 --- a/compiler/rustc_error_codes/src/error_codes/E0551.md +++ b/compiler/rustc_error_codes/src/error_codes/E0551.md @@ -1,8 +1,10 @@ +#### Note: this error code is no longer emitted by the compiler + An invalid meta-item was used inside an attribute. Erroneous code example: -```compile_fail,E0551 +```compile_fail,E0539 #[deprecated(note)] // error! fn i_am_deprecated() {} ``` diff --git a/compiler/rustc_errors/src/lib.rs b/compiler/rustc_errors/src/lib.rs index b747a62b864..665b5d6adec 100644 --- a/compiler/rustc_errors/src/lib.rs +++ b/compiler/rustc_errors/src/lib.rs @@ -1376,16 +1376,16 @@ impl HandlerInner { self.emitted_diagnostic_codes.insert(code.clone()); } - let already_emitted = |this: &mut Self| { + let already_emitted = { let mut hasher = StableHasher::new(); diagnostic.hash(&mut hasher); let diagnostic_hash = hasher.finish(); - !this.emitted_diagnostics.insert(diagnostic_hash) + !self.emitted_diagnostics.insert(diagnostic_hash) }; // Only emit the diagnostic if we've been asked to deduplicate or // haven't already emitted an equivalent diagnostic. - if !(self.flags.deduplicate_diagnostics && already_emitted(self)) { + if !(self.flags.deduplicate_diagnostics && already_emitted) { debug!(?diagnostic); debug!(?self.emitted_diagnostics); let already_emitted_sub = |sub: &mut SubDiagnostic| { @@ -1401,6 +1401,11 @@ impl HandlerInner { }; diagnostic.children.extract_if(already_emitted_sub).for_each(|_| {}); + if already_emitted { + diagnostic.note( + "duplicate diagnostic emitted due to `-Z deduplicate-diagnostics=no`", + ); + } self.emitter.emit_diagnostic(diagnostic); if diagnostic.is_error() { diff --git a/compiler/rustc_hir_analysis/src/check/compare_impl_item.rs b/compiler/rustc_hir_analysis/src/check/compare_impl_item.rs index b5a3437c992..6a1da615055 100644 --- a/compiler/rustc_hir_analysis/src/check/compare_impl_item.rs +++ b/compiler/rustc_hir_analysis/src/check/compare_impl_item.rs @@ -1189,7 +1189,7 @@ fn report_trait_method_mismatch<'tcx>( let ap = Applicability::MachineApplicable; match sig.decl.output { hir::FnRetTy::DefaultReturn(sp) => { - let sugg = format!("-> {} ", trait_sig.output()); + let sugg = format!(" -> {}", trait_sig.output()); diag.span_suggestion_verbose(sp, msg, sugg, ap); } hir::FnRetTy::Return(hir_ty) => { diff --git a/compiler/rustc_hir_analysis/src/check/compare_impl_item/refine.rs b/compiler/rustc_hir_analysis/src/check/compare_impl_item/refine.rs index d9e0e87eb47..bc5029a1d5e 100644 --- a/compiler/rustc_hir_analysis/src/check/compare_impl_item/refine.rs +++ b/compiler/rustc_hir_analysis/src/check/compare_impl_item/refine.rs @@ -23,8 +23,12 @@ pub(super) fn check_refining_return_position_impl_trait_in_trait<'tcx>( if !tcx.impl_method_has_trait_impl_trait_tys(impl_m.def_id) { return; } - // crate-private traits don't have any library guarantees, there's no need to do this check. - if !tcx.visibility(trait_m.container_id(tcx)).is_public() { + // unreachable traits don't have any library guarantees, there's no need to do this check. + if trait_m + .container_id(tcx) + .as_local() + .is_some_and(|trait_def_id| !tcx.effective_visibilities(()).is_reachable(trait_def_id)) + { return; } diff --git a/compiler/rustc_hir_analysis/src/variance/mod.rs b/compiler/rustc_hir_analysis/src/variance/mod.rs index 85e0000ab47..9fb39a0e93b 100644 --- a/compiler/rustc_hir_analysis/src/variance/mod.rs +++ b/compiler/rustc_hir_analysis/src/variance/mod.rs @@ -192,5 +192,5 @@ fn variance_of_opaque(tcx: TyCtxt<'_>, item_def_id: LocalDefId) -> &[ty::Varianc } } } - tcx.arena.alloc_from_iter(collector.variances.into_iter()) + tcx.arena.alloc_from_iter(collector.variances) } diff --git a/compiler/rustc_hir_typeck/src/check.rs b/compiler/rustc_hir_typeck/src/check.rs index 1fa0ec173a7..c8ffd7d1506 100644 --- a/compiler/rustc_hir_typeck/src/check.rs +++ b/compiler/rustc_hir_typeck/src/check.rs @@ -113,7 +113,11 @@ pub(super) fn check_fn<'a, 'tcx>( fcx.typeck_results.borrow_mut().liberated_fn_sigs_mut().insert(fn_id, fn_sig); - fcx.require_type_is_sized(declared_ret_ty, decl.output.span(), traits::SizedReturnType); + let return_or_body_span = match decl.output { + hir::FnRetTy::DefaultReturn(_) => body.value.span, + hir::FnRetTy::Return(ty) => ty.span, + }; + fcx.require_type_is_sized(declared_ret_ty, return_or_body_span, traits::SizedReturnType); fcx.check_return_expr(&body.value, false); // We insert the deferred_generator_interiors entry after visiting the body. diff --git a/compiler/rustc_hir_typeck/src/errors.rs b/compiler/rustc_hir_typeck/src/errors.rs index 1526988fbd9..8efccd5ba3e 100644 --- a/compiler/rustc_hir_typeck/src/errors.rs +++ b/compiler/rustc_hir_typeck/src/errors.rs @@ -110,7 +110,7 @@ pub struct AddressOfTemporaryTaken { pub enum AddReturnTypeSuggestion { #[suggestion( hir_typeck_add_return_type_add, - code = "-> {found} ", + code = " -> {found}", applicability = "machine-applicable" )] Add { @@ -120,7 +120,7 @@ pub enum AddReturnTypeSuggestion { }, #[suggestion( hir_typeck_add_return_type_missing_here, - code = "-> _ ", + code = " -> _", applicability = "has-placeholders" )] MissingHere { diff --git a/compiler/rustc_hir_typeck/src/expr.rs b/compiler/rustc_hir_typeck/src/expr.rs index eead4da5e3e..d9d0dd93010 100644 --- a/compiler/rustc_hir_typeck/src/expr.rs +++ b/compiler/rustc_hir_typeck/src/expr.rs @@ -41,7 +41,6 @@ use rustc_infer::infer::DefineOpaqueTypes; use rustc_infer::infer::InferOk; use rustc_infer::traits::query::NoSolution; use rustc_infer::traits::ObligationCause; -use rustc_middle::middle::stability; use rustc_middle::ty::adjustment::{Adjust, Adjustment, AllowTwoPhase}; use rustc_middle::ty::error::{ ExpectedFound, @@ -1585,12 +1584,11 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { self.check_expr_struct_fields( adt_ty, expected, - expr.hir_id, + expr, qpath.span(), variant, fields, base_expr, - expr.span, ); self.require_type_is_sized(adt_ty, expr.span, traits::StructInitializerSized); @@ -1601,12 +1599,11 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { &self, adt_ty: Ty<'tcx>, expected: Expectation<'tcx>, - expr_id: hir::HirId, + expr: &hir::Expr<'_>, span: Span, variant: &'tcx ty::VariantDef, ast_fields: &'tcx [hir::ExprField<'tcx>], base_expr: &'tcx Option<&'tcx hir::Expr<'tcx>>, - expr_span: Span, ) { let tcx = self.tcx; @@ -1646,7 +1643,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { // struct-like enums (yet...), but it's definitely not // a bug to have constructed one. if adt_kind != AdtKind::Enum { - tcx.check_stability(v_field.did, Some(expr_id), field.span, None); + tcx.check_stability(v_field.did, Some(expr.hir_id), field.span, None); } self.field_ty(field.span, v_field, args) @@ -1662,10 +1659,10 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { self.report_unknown_field( adt_ty, variant, + expr, field, ast_fields, adt.variant_descr(), - expr_span, ) }; @@ -1731,7 +1728,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { .iter() .map(|f| { let fru_ty = self - .normalize(expr_span, self.field_ty(base_expr.span, f, fresh_args)); + .normalize(expr.span, self.field_ty(base_expr.span, f, fresh_args)); let ident = self.tcx.adjust_ident(f.ident(self.tcx), variant.def_id); if let Some(_) = remaining_fields.remove(&ident) { let target_ty = self.field_ty(base_expr.span, f, args); @@ -1814,7 +1811,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { ty::Adt(adt, args) if adt.is_struct() => variant .fields .iter() - .map(|f| self.normalize(expr_span, f.ty(self.tcx, args))) + .map(|f| self.normalize(expr.span, f.ty(self.tcx, args))) .collect(), _ => { self.tcx @@ -1824,13 +1821,13 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { } } }; - self.typeck_results.borrow_mut().fru_field_types_mut().insert(expr_id, fru_tys); + self.typeck_results.borrow_mut().fru_field_types_mut().insert(expr.hir_id, fru_tys); } else if adt_kind != AdtKind::Union && !remaining_fields.is_empty() { debug!(?remaining_fields); let private_fields: Vec<&ty::FieldDef> = variant .fields .iter() - .filter(|field| !field.vis.is_accessible_from(tcx.parent_module(expr_id), tcx)) + .filter(|field| !field.vis.is_accessible_from(tcx.parent_module(expr.hir_id), tcx)) .collect(); if !private_fields.is_empty() { @@ -2049,16 +2046,16 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { &self, ty: Ty<'tcx>, variant: &'tcx ty::VariantDef, + expr: &hir::Expr<'_>, field: &hir::ExprField<'_>, skip_fields: &[hir::ExprField<'_>], kind_name: &str, - expr_span: Span, ) -> ErrorGuaranteed { if variant.is_recovered() { let guar = self .tcx .sess - .delay_span_bug(expr_span, "parser recovered but no error was emitted"); + .delay_span_bug(expr.span, "parser recovered but no error was emitted"); self.set_tainted_by_errors(guar); return guar; } @@ -2102,7 +2099,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { ); err.span_label(field.ident.span, "field does not exist"); err.span_suggestion_verbose( - expr_span, + expr.span, format!( "`{adt}::{variant}` is a tuple {kind_name}, use the appropriate syntax", adt = ty, @@ -2120,7 +2117,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { err.span_label(variant_ident_span, format!("`{ty}` defined here")); err.span_label(field.ident.span, "field does not exist"); err.span_suggestion_verbose( - expr_span, + expr.span, format!("`{ty}` is a tuple {kind_name}, use the appropriate syntax",), format!("{ty}(/* fields */)"), Applicability::HasPlaceholders, @@ -2129,9 +2126,9 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { }, _ => { // prevent all specified fields from being suggested - let skip_fields: Vec<_> = skip_fields.iter().map(|x| x.ident.name).collect(); + let available_field_names = self.available_field_names(variant, expr, skip_fields); if let Some(field_name) = - self.suggest_field_name(variant, field.ident.name, &skip_fields, expr_span) + find_best_match_for_name(&available_field_names, field.ident.name, None) { err.span_suggestion( field.ident.span, @@ -2153,10 +2150,6 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { format!("`{ty}` does not have this field"), ); } - let mut available_field_names = - self.available_field_names(variant, expr_span); - available_field_names - .retain(|name| skip_fields.iter().all(|skip| name != skip)); if available_field_names.is_empty() { err.note("all struct fields are already assigned"); } else { @@ -2174,63 +2167,19 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { err.emit() } - // Return a hint about the closest match in field names - fn suggest_field_name( - &self, - variant: &'tcx ty::VariantDef, - field: Symbol, - skip: &[Symbol], - // The span where stability will be checked - span: Span, - ) -> Option<Symbol> { - let names = variant - .fields - .iter() - .filter_map(|field| { - // ignore already set fields and private fields from non-local crates - // and unstable fields. - if skip.iter().any(|&x| x == field.name) - || (!variant.def_id.is_local() && !field.vis.is_public()) - || matches!( - self.tcx.eval_stability(field.did, None, span, None), - stability::EvalResult::Deny { .. } - ) - { - None - } else { - Some(field.name) - } - }) - .collect::<Vec<Symbol>>(); - - find_best_match_for_name(&names, field, None) - } - fn available_field_names( &self, variant: &'tcx ty::VariantDef, - access_span: Span, + expr: &hir::Expr<'_>, + skip_fields: &[hir::ExprField<'_>], ) -> Vec<Symbol> { - let body_owner_hir_id = self.tcx.hir().local_def_id_to_hir_id(self.body_id); variant .fields .iter() .filter(|field| { - let def_scope = self - .tcx - .adjust_ident_and_get_scope( - field.ident(self.tcx), - variant.def_id, - body_owner_hir_id, - ) - .1; - field.vis.is_accessible_from(def_scope, self.tcx) - && !matches!( - self.tcx.eval_stability(field.did, None, access_span, None), - stability::EvalResult::Deny { .. } - ) + skip_fields.iter().all(|&skip| skip.ident.name != field.name) + && self.is_field_suggestable(field, expr.hir_id, expr.span) }) - .filter(|field| !self.tcx.is_doc_hidden(field.did)) .map(|field| field.name) .collect() } @@ -2460,7 +2409,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { self.suggest_first_deref_field(&mut err, expr, base, ident); } ty::Adt(def, _) if !def.is_enum() => { - self.suggest_fields_on_recordish(&mut err, def, ident, expr.span); + self.suggest_fields_on_recordish(&mut err, expr, def, ident); } ty::Param(param_ty) => { self.point_at_param_definition(&mut err, param_ty); @@ -2622,12 +2571,13 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { fn suggest_fields_on_recordish( &self, err: &mut Diagnostic, + expr: &hir::Expr<'_>, def: ty::AdtDef<'tcx>, field: Ident, - access_span: Span, ) { + let available_field_names = self.available_field_names(def.non_enum_variant(), expr, &[]); if let Some(suggested_field_name) = - self.suggest_field_name(def.non_enum_variant(), field.name, &[], access_span) + find_best_match_for_name(&available_field_names, field.name, None) { err.span_suggestion( field.span, @@ -2637,12 +2587,10 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { ); } else { err.span_label(field.span, "unknown field"); - let struct_variant_def = def.non_enum_variant(); - let field_names = self.available_field_names(struct_variant_def, access_span); - if !field_names.is_empty() { + if !available_field_names.is_empty() { err.note(format!( "available fields are: {}", - self.name_series_display(field_names), + self.name_series_display(available_field_names), )); } } diff --git a/compiler/rustc_hir_typeck/src/fn_ctxt/suggestions.rs b/compiler/rustc_hir_typeck/src/fn_ctxt/suggestions.rs index abb68989218..9999fa2e59c 100644 --- a/compiler/rustc_hir_typeck/src/fn_ctxt/suggestions.rs +++ b/compiler/rustc_hir_typeck/src/fn_ctxt/suggestions.rs @@ -782,8 +782,6 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { } } hir::FnRetTy::Return(hir_ty) => { - let span = hir_ty.span; - if let hir::TyKind::OpaqueDef(item_id, ..) = hir_ty.kind && let hir::Node::Item(hir::Item { kind: hir::ItemKind::OpaqueTy(op_ty), @@ -799,28 +797,28 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { debug!(?found); if found.is_suggestable(self.tcx, false) { if term.span.is_empty() { - err.subdiagnostic(errors::AddReturnTypeSuggestion::Add { span, found: found.to_string() }); + err.subdiagnostic(errors::AddReturnTypeSuggestion::Add { span: term.span, found: found.to_string() }); return true; } else { - err.subdiagnostic(errors::ExpectedReturnTypeLabel::Other { span, expected }); + err.subdiagnostic(errors::ExpectedReturnTypeLabel::Other { span: term.span, expected }); } } - } - - // Only point to return type if the expected type is the return type, as if they - // are not, the expectation must have been caused by something else. - debug!("return type {:?}", hir_ty); - let ty = self.astconv().ast_ty_to_ty(hir_ty); - debug!("return type {:?}", ty); - debug!("expected type {:?}", expected); - let bound_vars = self.tcx.late_bound_vars(hir_ty.hir_id.owner.into()); - let ty = Binder::bind_with_vars(ty, bound_vars); - let ty = self.normalize(span, ty); - let ty = self.tcx.erase_late_bound_regions(ty); - if self.can_coerce(expected, ty) { - err.subdiagnostic(errors::ExpectedReturnTypeLabel::Other { span, expected }); - self.try_suggest_return_impl_trait(err, expected, ty, fn_id); - return true; + } else { + // Only point to return type if the expected type is the return type, as if they + // are not, the expectation must have been caused by something else. + debug!("return type {:?}", hir_ty); + let ty = self.astconv().ast_ty_to_ty(hir_ty); + debug!("return type {:?}", ty); + debug!("expected type {:?}", expected); + let bound_vars = self.tcx.late_bound_vars(hir_ty.hir_id.owner.into()); + let ty = Binder::bind_with_vars(ty, bound_vars); + let ty = self.normalize(hir_ty.span, ty); + let ty = self.tcx.erase_late_bound_regions(ty); + if self.can_coerce(expected, ty) { + err.subdiagnostic(errors::ExpectedReturnTypeLabel::Other { span: hir_ty.span, expected }); + self.try_suggest_return_impl_trait(err, expected, ty, fn_id); + return true; + } } } _ => {} @@ -1687,4 +1685,23 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { false } } + + pub(crate) fn is_field_suggestable( + &self, + field: &ty::FieldDef, + hir_id: HirId, + span: Span, + ) -> bool { + // The field must be visible in the containing module. + field.vis.is_accessible_from(self.tcx.parent_module(hir_id), self.tcx) + // The field must not be unstable. + && !matches!( + self.tcx.eval_stability(field.did, None, rustc_span::DUMMY_SP, None), + rustc_middle::middle::stability::EvalResult::Deny { .. } + ) + // If the field is from an external crate it must not be `doc(hidden)`. + && (field.did.is_local() || !self.tcx.is_doc_hidden(field.did)) + // If the field is hygienic it must come from the same syntax context. + && self.tcx.def_ident_span(field.did).unwrap().normalize_to_macros_2_0().eq_ctxt(span) + } } diff --git a/compiler/rustc_hir_typeck/src/lib.rs b/compiler/rustc_hir_typeck/src/lib.rs index 6873382c4ac..cd6adb345e7 100644 --- a/compiler/rustc_hir_typeck/src/lib.rs +++ b/compiler/rustc_hir_typeck/src/lib.rs @@ -5,7 +5,6 @@ #![feature(box_patterns)] #![feature(min_specialization)] #![feature(control_flow_enum)] -#![feature(option_as_slice)] #![recursion_limit = "256"] #[macro_use] diff --git a/compiler/rustc_hir_typeck/src/pat.rs b/compiler/rustc_hir_typeck/src/pat.rs index 8fc236f46b2..3f9c9b3381b 100644 --- a/compiler/rustc_hir_typeck/src/pat.rs +++ b/compiler/rustc_hir_typeck/src/pat.rs @@ -12,7 +12,6 @@ use rustc_hir::pat_util::EnumerateAndAdjustIterator; use rustc_hir::{HirId, Pat, PatKind}; use rustc_infer::infer; use rustc_infer::infer::type_variable::{TypeVariableOrigin, TypeVariableOriginKind}; -use rustc_middle::middle::stability::EvalResult; use rustc_middle::ty::{self, Adt, BindingMode, Ty, TypeVisitableExt}; use rustc_session::lint::builtin::NON_EXHAUSTIVE_OMITTED_PATTERNS; use rustc_span::edit_distance::find_best_match_for_name; @@ -1408,6 +1407,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { adt.variant_descr(), &inexistent_fields, &mut unmentioned_fields, + pat, variant, args, )) @@ -1434,15 +1434,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { let accessible_unmentioned_fields: Vec<_> = unmentioned_fields .iter() .copied() - .filter(|(field, _)| { - field.vis.is_accessible_from(tcx.parent_module(pat.hir_id), tcx) - && !matches!( - tcx.eval_stability(field.did, None, DUMMY_SP, None), - EvalResult::Deny { .. } - ) - // We only want to report the error if it is hidden and not local - && !(tcx.is_doc_hidden(field.did) && !field.did.is_local()) - }) + .filter(|(field, _)| self.is_field_suggestable(field, pat.hir_id, pat.span)) .collect(); if !has_rest_pat { @@ -1578,12 +1570,13 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { kind_name: &str, inexistent_fields: &[&hir::PatField<'tcx>], unmentioned_fields: &mut Vec<(&'tcx ty::FieldDef, Ident)>, + pat: &'tcx Pat<'tcx>, variant: &ty::VariantDef, args: &'tcx ty::List<ty::GenericArg<'tcx>>, ) -> DiagnosticBuilder<'tcx, ErrorGuaranteed> { let tcx = self.tcx; - let (field_names, t, plural) = if inexistent_fields.len() == 1 { - (format!("a field named `{}`", inexistent_fields[0].ident), "this", "") + let (field_names, t, plural) = if let [field] = inexistent_fields { + (format!("a field named `{}`", field.ident), "this", "") } else { ( format!( @@ -1620,10 +1613,11 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { ), ); - if unmentioned_fields.len() == 1 { - let input = - unmentioned_fields.iter().map(|(_, field)| field.name).collect::<Vec<_>>(); - let suggested_name = find_best_match_for_name(&input, pat_field.ident.name, None); + if let [(field_def, field)] = unmentioned_fields.as_slice() + && self.is_field_suggestable(field_def, pat.hir_id, pat.span) + { + let suggested_name = + find_best_match_for_name(&[field.name], pat_field.ident.name, None); if let Some(suggested_name) = suggested_name { err.span_suggestion( pat_field.ident.span, @@ -1646,22 +1640,17 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { PatKind::Lit(expr) if !self.can_coerce( self.typeck_results.borrow().expr_ty(expr), - self.field_ty( - unmentioned_fields[0].1.span, - unmentioned_fields[0].0, - args, - ), + self.field_ty(field.span, field_def, args), ) => {} _ => { - let unmentioned_field = unmentioned_fields[0].1.name; err.span_suggestion_short( pat_field.ident.span, format!( "`{}` has a field named `{}`", tcx.def_path_str(variant.def_id), - unmentioned_field + field.name, ), - unmentioned_field.to_string(), + field.name, Applicability::MaybeIncorrect, ); } @@ -1871,8 +1860,8 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { fields: &'tcx [hir::PatField<'tcx>], ) -> DiagnosticBuilder<'tcx, ErrorGuaranteed> { let inaccessible = if have_inaccessible_fields { " and inaccessible fields" } else { "" }; - let field_names = if unmentioned_fields.len() == 1 { - format!("field `{}`{}", unmentioned_fields[0].1, inaccessible) + let field_names = if let [(_, field)] = unmentioned_fields { + format!("field `{field}`{inaccessible}") } else { let fields = unmentioned_fields .iter() diff --git a/compiler/rustc_infer/src/errors/mod.rs b/compiler/rustc_infer/src/errors/mod.rs index ad4525c922b..3ff1a5c0c14 100644 --- a/compiler/rustc_infer/src/errors/mod.rs +++ b/compiler/rustc_infer/src/errors/mod.rs @@ -194,13 +194,13 @@ impl<'a> SourceKindMultiSuggestion<'a> { data: &'a FnRetTy<'a>, should_wrap_expr: Option<Span>, ) -> Self { - let (arrow, post) = match data { - FnRetTy::DefaultReturn(_) => ("-> ", " "), - _ => ("", ""), + let arrow = match data { + FnRetTy::DefaultReturn(_) => " -> ", + _ => "", }; let (start_span, start_span_code, end_span) = match should_wrap_expr { - Some(end_span) => (data.span(), format!("{arrow}{ty_info}{post}{{ "), Some(end_span)), - None => (data.span(), format!("{arrow}{ty_info}{post}"), None), + Some(end_span) => (data.span(), format!("{arrow}{ty_info} {{"), Some(end_span)), + None => (data.span(), format!("{arrow}{ty_info}"), None), }; Self::ClosureReturn { start_span, start_span_code, end_span } } diff --git a/compiler/rustc_lint/messages.ftl b/compiler/rustc_lint/messages.ftl index 7377c6e2f35..4cabb5c3266 100644 --- a/compiler/rustc_lint/messages.ftl +++ b/compiler/rustc_lint/messages.ftl @@ -5,6 +5,10 @@ lint_array_into_iter = .use_explicit_into_iter_suggestion = or use `IntoIterator::into_iter(..)` instead of `.into_iter()` to explicitly iterate by value +lint_async_fn_in_trait = use of `async fn` in public traits is discouraged as auto trait bounds cannot be specified + .note = you can suppress this lint if you plan to use the trait only in your own code, or do not care about auto traits like `Send` on the `Future` + .suggestion = you can alternatively desugar to a normal `fn` that returns `impl Future` and add any desired bounds such as `Send` + lint_atomic_ordering_fence = memory fences cannot have `Relaxed` ordering .help = consider using ordering modes `Acquire`, `Release`, `AcqRel` or `SeqCst` diff --git a/compiler/rustc_lint/src/async_fn_in_trait.rs b/compiler/rustc_lint/src/async_fn_in_trait.rs new file mode 100644 index 00000000000..ff4c81e2fc9 --- /dev/null +++ b/compiler/rustc_lint/src/async_fn_in_trait.rs @@ -0,0 +1,128 @@ +use crate::lints::AsyncFnInTraitDiag; +use crate::LateContext; +use crate::LateLintPass; +use rustc_hir as hir; +use rustc_trait_selection::traits::error_reporting::suggestions::suggest_desugaring_async_fn_to_impl_future_in_trait; + +declare_lint! { + /// The `async_fn_in_trait` lint detects use of `async fn` in the + /// definition of a publicly-reachable trait. + /// + /// ### Example + /// + /// ```rust + /// # #![feature(async_fn_in_trait)] + /// pub trait Trait { + /// async fn method(&self); + /// } + /// # fn main() {} + /// ``` + /// + /// {{produces}} + /// + /// ### Explanation + /// + /// When `async fn` is used in a trait definition, the trait does not + /// promise that the opaque [`Future`] returned by the associated function + /// or method will implement any [auto traits] such as [`Send`]. This may + /// be surprising and may make the associated functions or methods on the + /// trait less useful than intended. On traits exposed publicly from a + /// crate, this may affect downstream crates whose authors cannot alter + /// the trait definition. + /// + /// For example, this code is invalid: + /// + /// ```rust,compile_fail + /// # #![feature(async_fn_in_trait)] + /// pub trait Trait { + /// async fn method(&self) {} + /// } + /// + /// fn test<T: Trait>(x: T) { + /// fn spawn<T: Send>(_: T) {} + /// spawn(x.method()); // Not OK. + /// } + /// ``` + /// + /// This lint exists to warn authors of publicly-reachable traits that + /// they may want to consider desugaring the `async fn` to a normal `fn` + /// that returns an opaque `impl Future<..> + Send` type. + /// + /// For example, instead of: + /// + /// ```rust + /// # #![feature(async_fn_in_trait)] + /// pub trait Trait { + /// async fn method(&self) {} + /// } + /// ``` + /// + /// The author of the trait may want to write: + /// + /// + /// ```rust + /// # #![feature(return_position_impl_trait_in_trait)] + /// use core::future::Future; + /// pub trait Trait { + /// fn method(&self) -> impl Future<Output = ()> + Send { async {} } + /// } + /// ``` + /// + /// This still allows the use of `async fn` within impls of the trait. + /// However, it also means that the trait will never be compatible with + /// impls where the returned [`Future`] of the method does not implement + /// `Send`. + /// + /// Conversely, if the trait is used only locally, if it is never used in + /// generic functions, or if it is only used in single-threaded contexts + /// that do not care whether the returned [`Future`] implements [`Send`], + /// then the lint may be suppressed. + /// + /// [`Future`]: https://doc.rust-lang.org/core/future/trait.Future.html + /// [`Send`]: https://doc.rust-lang.org/core/marker/trait.Send.html + /// [auto traits]: https://doc.rust-lang.org/reference/special-types-and-traits.html#auto-traits + pub ASYNC_FN_IN_TRAIT, + Warn, + "use of `async fn` in definition of a publicly-reachable trait" +} + +declare_lint_pass!( + /// Lint for use of `async fn` in the definition of a publicly-reachable + /// trait. + AsyncFnInTrait => [ASYNC_FN_IN_TRAIT] +); + +impl<'tcx> LateLintPass<'tcx> for AsyncFnInTrait { + fn check_trait_item(&mut self, cx: &LateContext<'tcx>, item: &'tcx hir::TraitItem<'tcx>) { + if let hir::TraitItemKind::Fn(sig, body) = item.kind + && let hir::IsAsync::Async(async_span) = sig.header.asyncness + { + // RTN can be used to bound `async fn` in traits in a better way than "always" + if cx.tcx.features().return_type_notation { + return; + } + + // Only need to think about library implications of reachable traits + if !cx.tcx.effective_visibilities(()).is_reachable(item.owner_id.def_id) { + return; + } + + let hir::FnRetTy::Return(hir::Ty { kind: hir::TyKind::OpaqueDef(def, ..), .. }) = + sig.decl.output + else { + // This should never happen, but let's not ICE. + return; + }; + let sugg = suggest_desugaring_async_fn_to_impl_future_in_trait( + cx.tcx, + sig, + body, + def.owner_id.def_id, + " + Send", + ); + cx.tcx.emit_spanned_lint(ASYNC_FN_IN_TRAIT, item.hir_id(), async_span, AsyncFnInTraitDiag { + sugg + }); + } + } +} diff --git a/compiler/rustc_lint/src/lib.rs b/compiler/rustc_lint/src/lib.rs index 72c103f2d4a..af2132fb899 100644 --- a/compiler/rustc_lint/src/lib.rs +++ b/compiler/rustc_lint/src/lib.rs @@ -50,6 +50,7 @@ extern crate rustc_session; extern crate tracing; mod array_into_iter; +mod async_fn_in_trait; pub mod builtin; mod context; mod deref_into_dyn_supertrait; @@ -96,6 +97,7 @@ use rustc_session::lint::builtin::{ }; use array_into_iter::ArrayIntoIter; +use async_fn_in_trait::AsyncFnInTrait; use builtin::*; use deref_into_dyn_supertrait::*; use drop_forget_useless::*; @@ -234,6 +236,7 @@ late_lint_methods!( MapUnitFn: MapUnitFn, MissingDebugImplementations: MissingDebugImplementations, MissingDoc: MissingDoc, + AsyncFnInTrait: AsyncFnInTrait, ] ] ); diff --git a/compiler/rustc_lint/src/lints.rs b/compiler/rustc_lint/src/lints.rs index c091c260a47..12694aa0bed 100644 --- a/compiler/rustc_lint/src/lints.rs +++ b/compiler/rustc_lint/src/lints.rs @@ -1818,3 +1818,24 @@ pub struct UnusedAllocationDiag; #[derive(LintDiagnostic)] #[diag(lint_unused_allocation_mut)] pub struct UnusedAllocationMutDiag; + +pub struct AsyncFnInTraitDiag { + pub sugg: Option<Vec<(Span, String)>>, +} + +impl<'a> DecorateLint<'a, ()> for AsyncFnInTraitDiag { + fn decorate_lint<'b>( + self, + diag: &'b mut rustc_errors::DiagnosticBuilder<'a, ()>, + ) -> &'b mut rustc_errors::DiagnosticBuilder<'a, ()> { + diag.note(fluent::lint_note); + if let Some(sugg) = self.sugg { + diag.multipart_suggestion(fluent::lint_suggestion, sugg, Applicability::MaybeIncorrect); + } + diag + } + + fn msg(&self) -> rustc_errors::DiagnosticMessage { + fluent::lint_async_fn_in_trait + } +} diff --git a/compiler/rustc_middle/src/mir/mod.rs b/compiler/rustc_middle/src/mir/mod.rs index 0bb1c66da0c..7534c9c0a68 100644 --- a/compiler/rustc_middle/src/mir/mod.rs +++ b/compiler/rustc_middle/src/mir/mod.rs @@ -830,22 +830,6 @@ pub struct LocalDecl<'tcx> { // FIXME(matthewjasper) Don't store in this in `Body` pub local_info: ClearCrossCrate<Box<LocalInfo<'tcx>>>, - /// `true` if this is an internal local. - /// - /// These locals are not based on types in the source code and are only used - /// for a few desugarings at the moment. - /// - /// The generator transformation will sanity check the locals which are live - /// across a suspension point against the type components of the generator - /// which type checking knows are live across a suspension point. We need to - /// flag drop flags to avoid triggering this check as they are introduced - /// outside of type inference. - /// - /// This should be sound because the drop flags are fully algebraic, and - /// therefore don't affect the auto-trait or outlives properties of the - /// generator. - pub internal: bool, - /// The type of this local. pub ty: Ty<'tcx>, @@ -1058,7 +1042,7 @@ impl<'tcx> LocalDecl<'tcx> { self.source_info.span.desugaring_kind().is_some() } - /// Creates a new `LocalDecl` for a temporary: mutable, non-internal. + /// Creates a new `LocalDecl` for a temporary, mutable. #[inline] pub fn new(ty: Ty<'tcx>, span: Span) -> Self { Self::with_source_info(ty, SourceInfo::outermost(span)) @@ -1070,20 +1054,12 @@ impl<'tcx> LocalDecl<'tcx> { LocalDecl { mutability: Mutability::Mut, local_info: ClearCrossCrate::Set(Box::new(LocalInfo::Boring)), - internal: false, ty, user_ty: None, source_info, } } - /// Converts `self` into same `LocalDecl` except tagged as internal. - #[inline] - pub fn internal(mut self) -> Self { - self.internal = true; - self - } - /// Converts `self` into same `LocalDecl` except tagged as immutable. #[inline] pub fn immutable(mut self) -> Self { diff --git a/compiler/rustc_middle/src/mir/patch.rs b/compiler/rustc_middle/src/mir/patch.rs index da486c3465a..ce2ddec0116 100644 --- a/compiler/rustc_middle/src/mir/patch.rs +++ b/compiler/rustc_middle/src/mir/patch.rs @@ -127,7 +127,7 @@ impl<'tcx> MirPatch<'tcx> { Location { block: bb, statement_index: offset } } - pub fn new_internal_with_info( + pub fn new_local_with_info( &mut self, ty: Ty<'tcx>, span: Span, @@ -135,7 +135,7 @@ impl<'tcx> MirPatch<'tcx> { ) -> Local { let index = self.next_local; self.next_local += 1; - let mut new_decl = LocalDecl::new(ty, span).internal(); + let mut new_decl = LocalDecl::new(ty, span); **new_decl.local_info.as_mut().assert_crate_local() = local_info; self.new_locals.push(new_decl); Local::new(index) @@ -148,13 +148,6 @@ impl<'tcx> MirPatch<'tcx> { Local::new(index) } - pub fn new_internal(&mut self, ty: Ty<'tcx>, span: Span) -> Local { - let index = self.next_local; - self.next_local += 1; - self.new_locals.push(LocalDecl::new(ty, span).internal()); - Local::new(index) - } - pub fn new_block(&mut self, data: BasicBlockData<'tcx>) -> BasicBlock { let block = BasicBlock::new(self.patch_map.len()); debug!("MirPatch: new_block: {:?}: {:?}", block, data); diff --git a/compiler/rustc_middle/src/mir/visit.rs b/compiler/rustc_middle/src/mir/visit.rs index 60f78bef0af..9bd682d37ab 100644 --- a/compiler/rustc_middle/src/mir/visit.rs +++ b/compiler/rustc_middle/src/mir/visit.rs @@ -815,7 +815,6 @@ macro_rules! make_mir_visitor { ty, user_ty, source_info, - internal: _, local_info: _, } = local_decl; diff --git a/compiler/rustc_middle/src/ty/codec.rs b/compiler/rustc_middle/src/ty/codec.rs index dff7ff8c66b..e4069e11df2 100644 --- a/compiler/rustc_middle/src/ty/codec.rs +++ b/compiler/rustc_middle/src/ty/codec.rs @@ -348,9 +348,10 @@ impl<'tcx, D: TyDecoder<I = TyCtxt<'tcx>>> Decodable<D> for ty::Const<'tcx> { impl<'tcx, D: TyDecoder<I = TyCtxt<'tcx>>> RefDecodable<'tcx, D> for [ty::ValTree<'tcx>] { fn decode(decoder: &mut D) -> &'tcx Self { - decoder.interner().arena.alloc_from_iter( - (0..decoder.read_usize()).map(|_| Decodable::decode(decoder)).collect::<Vec<_>>(), - ) + decoder + .interner() + .arena + .alloc_from_iter((0..decoder.read_usize()).map(|_| Decodable::decode(decoder))) } } @@ -368,9 +369,10 @@ impl<'tcx, D: TyDecoder<I = TyCtxt<'tcx>>> Decodable<D> for AdtDef<'tcx> { impl<'tcx, D: TyDecoder<I = TyCtxt<'tcx>>> RefDecodable<'tcx, D> for [(ty::Clause<'tcx>, Span)] { fn decode(decoder: &mut D) -> &'tcx Self { - decoder.interner().arena.alloc_from_iter( - (0..decoder.read_usize()).map(|_| Decodable::decode(decoder)).collect::<Vec<_>>(), - ) + decoder + .interner() + .arena + .alloc_from_iter((0..decoder.read_usize()).map(|_| Decodable::decode(decoder))) } } diff --git a/compiler/rustc_mir_build/src/build/expr/as_rvalue.rs b/compiler/rustc_mir_build/src/build/expr/as_rvalue.rs index d4089eef483..afb65ffbe8c 100644 --- a/compiler/rustc_mir_build/src/build/expr/as_rvalue.rs +++ b/compiler/rustc_mir_build/src/build/expr/as_rvalue.rs @@ -183,7 +183,7 @@ impl<'a, 'tcx> Builder<'a, 'tcx> { // The `Box<T>` temporary created here is not a part of the HIR, // and therefore is not considered during generator auto-trait // determination. See the comment about `box` at `yield_in_scope`. - let result = this.local_decls.push(LocalDecl::new(expr.ty, expr_span).internal()); + let result = this.local_decls.push(LocalDecl::new(expr.ty, expr_span)); this.cfg.push( block, Statement { source_info, kind: StatementKind::StorageLive(result) }, diff --git a/compiler/rustc_mir_build/src/build/expr/as_temp.rs b/compiler/rustc_mir_build/src/build/expr/as_temp.rs index c8910c272b1..a4ab365fa9a 100644 --- a/compiler/rustc_mir_build/src/build/expr/as_temp.rs +++ b/compiler/rustc_mir_build/src/build/expr/as_temp.rs @@ -52,12 +52,10 @@ impl<'a, 'tcx> Builder<'a, 'tcx> { let local_info = match expr.kind { ExprKind::StaticRef { def_id, .. } => { assert!(!this.tcx.is_thread_local_static(def_id)); - local_decl.internal = true; LocalInfo::StaticRef { def_id, is_thread_local: false } } ExprKind::ThreadLocalRef(def_id) => { assert!(this.tcx.is_thread_local_static(def_id)); - local_decl.internal = true; LocalInfo::StaticRef { def_id, is_thread_local: true } } ExprKind::NamedConst { def_id, .. } | ExprKind::ConstParam { def_id, .. } => { diff --git a/compiler/rustc_mir_build/src/build/expr/mod.rs b/compiler/rustc_mir_build/src/build/expr/mod.rs index f5ae060d603..dfe85b858cd 100644 --- a/compiler/rustc_mir_build/src/build/expr/mod.rs +++ b/compiler/rustc_mir_build/src/build/expr/mod.rs @@ -44,7 +44,7 @@ //! the most suitable spot to implement it, and then just let the //! other fns cycle around. The handoff works like this: //! -//! - `into(place)` -> fallback is to create a rvalue with `as_rvalue` and assign it to `place` +//! - `into(place)` -> fallback is to create an rvalue with `as_rvalue` and assign it to `place` //! - `as_rvalue` -> fallback is to create an Operand with `as_operand` and use `Rvalue::use` //! - `as_operand` -> either invokes `as_constant` or `as_temp` //! - `as_constant` -> (no fallback) diff --git a/compiler/rustc_mir_build/src/build/matches/mod.rs b/compiler/rustc_mir_build/src/build/matches/mod.rs index 921a5ca1175..eb1c6a9824a 100644 --- a/compiler/rustc_mir_build/src/build/matches/mod.rs +++ b/compiler/rustc_mir_build/src/build/matches/mod.rs @@ -1798,7 +1798,6 @@ impl<'a, 'tcx> Builder<'a, 'tcx> { let fake_borrow_ty = Ty::new_imm_ref(tcx, tcx.lifetimes.re_erased, fake_borrow_deref_ty); let mut fake_borrow_temp = LocalDecl::new(fake_borrow_ty, temp_span); - fake_borrow_temp.internal = self.local_decls[matched_place.local].internal; fake_borrow_temp.local_info = ClearCrossCrate::Set(Box::new(LocalInfo::FakeBorrow)); let fake_borrow_temp = self.local_decls.push(fake_borrow_temp); @@ -2268,7 +2267,6 @@ impl<'a, 'tcx> Builder<'a, 'tcx> { ty: var_ty, user_ty: if user_ty.is_empty() { None } else { Some(Box::new(user_ty)) }, source_info, - internal: false, local_info: ClearCrossCrate::Set(Box::new(LocalInfo::User(BindingForm::Var( VarBindingForm { binding_mode, @@ -2298,7 +2296,6 @@ impl<'a, 'tcx> Builder<'a, 'tcx> { ty: Ty::new_imm_ref(tcx, tcx.lifetimes.re_erased, var_ty), user_ty: None, source_info, - internal: false, local_info: ClearCrossCrate::Set(Box::new(LocalInfo::User( BindingForm::RefForGuard, ))), diff --git a/compiler/rustc_mir_build/src/build/misc.rs b/compiler/rustc_mir_build/src/build/misc.rs index c96e99ef0e7..c263de79c3b 100644 --- a/compiler/rustc_mir_build/src/build/misc.rs +++ b/compiler/rustc_mir_build/src/build/misc.rs @@ -15,9 +15,7 @@ impl<'a, 'tcx> Builder<'a, 'tcx> { /// N.B., **No cleanup is scheduled for this temporary.** You should /// call `schedule_drop` once the temporary is initialized. pub(crate) fn temp(&mut self, ty: Ty<'tcx>, span: Span) -> Place<'tcx> { - // Mark this local as internal to avoid temporaries with types not present in the - // user's code resulting in ICEs from the generator transform. - let temp = self.local_decls.push(LocalDecl::new(ty, span).internal()); + let temp = self.local_decls.push(LocalDecl::new(ty, span)); let place = Place::from(temp); debug!("temp: created temp {:?} with type {:?}", place, self.local_decls[temp].ty); place diff --git a/compiler/rustc_mir_build/src/build/scope.rs b/compiler/rustc_mir_build/src/build/scope.rs index 4cf6a349af7..bc151cc7058 100644 --- a/compiler/rustc_mir_build/src/build/scope.rs +++ b/compiler/rustc_mir_build/src/build/scope.rs @@ -725,7 +725,7 @@ impl<'a, 'tcx> Builder<'a, 'tcx> { // Add a dummy `Assign` statement to the CFG, with the span for the source code's `continue` // statement. fn add_dummy_assignment(&mut self, span: Span, block: BasicBlock, source_info: SourceInfo) { - let local_decl = LocalDecl::new(Ty::new_unit(self.tcx), span).internal(); + let local_decl = LocalDecl::new(Ty::new_unit(self.tcx), span); let temp_place = Place::from(self.local_decls.push(local_decl)); self.cfg.push_assign_unit(block, source_info, temp_place, self.tcx); } diff --git a/compiler/rustc_mir_transform/src/add_subtyping_projections.rs b/compiler/rustc_mir_transform/src/add_subtyping_projections.rs index 1cc049d5a22..e5be7c0ca76 100644 --- a/compiler/rustc_mir_transform/src/add_subtyping_projections.rs +++ b/compiler/rustc_mir_transform/src/add_subtyping_projections.rs @@ -24,6 +24,11 @@ impl<'a, 'tcx> MutVisitor<'tcx> for SubTypeChecker<'a, 'tcx> { rvalue: &mut Rvalue<'tcx>, location: Location, ) { + // We don't need to do anything for deref temps as they are + // not part of the source code, but used for desugaring purposes. + if self.local_decls[place.local].is_deref_temp() { + return; + } let mut place_ty = place.ty(self.local_decls, self.tcx).ty; let mut rval_ty = rvalue.ty(self.local_decls, self.tcx); // Not erasing this causes `Free Regions` errors in validator, @@ -48,7 +53,6 @@ impl<'a, 'tcx> MutVisitor<'tcx> for SubTypeChecker<'a, 'tcx> { // // gets transformed to // let temp: rval_ty = rval; // let place: place_ty = temp as place_ty; -// pub fn subtype_finder<'tcx>(tcx: TyCtxt<'tcx>, body: &mut Body<'tcx>) { let patch = MirPatch::new(body); let mut checker = SubTypeChecker { tcx, patcher: patch, local_decls: &body.local_decls }; diff --git a/compiler/rustc_mir_transform/src/check_unsafety.rs b/compiler/rustc_mir_transform/src/check_unsafety.rs index bacabc62ee4..c428007707e 100644 --- a/compiler/rustc_mir_transform/src/check_unsafety.rs +++ b/compiler/rustc_mir_transform/src/check_unsafety.rs @@ -179,7 +179,7 @@ impl<'tcx> Visitor<'tcx> for UnsafetyChecker<'_, 'tcx> { // Check the base local: it might be an unsafe-to-access static. We only check derefs of the // temporary holding the static pointer to avoid duplicate errors // <https://github.com/rust-lang/rust/pull/78068#issuecomment-731753506>. - if decl.internal && place.projection.first() == Some(&ProjectionElem::Deref) { + if place.projection.first() == Some(&ProjectionElem::Deref) { // If the projection root is an artificial local that we introduced when // desugaring `static`, give a more specific error message // (avoid the general "raw pointer" clause below, that would only be confusing). diff --git a/compiler/rustc_mir_transform/src/deref_separator.rs b/compiler/rustc_mir_transform/src/deref_separator.rs index 95898b5b73c..42be7457018 100644 --- a/compiler/rustc_mir_transform/src/deref_separator.rs +++ b/compiler/rustc_mir_transform/src/deref_separator.rs @@ -37,7 +37,7 @@ impl<'a, 'tcx> MutVisitor<'tcx> for DerefChecker<'a, 'tcx> { for (idx, (p_ref, p_elem)) in place.iter_projections().enumerate() { if !p_ref.projection.is_empty() && p_elem == ProjectionElem::Deref { let ty = p_ref.ty(self.local_decls, self.tcx).ty; - let temp = self.patcher.new_internal_with_info( + let temp = self.patcher.new_local_with_info( ty, self.local_decls[p_ref.local].source_info.span, LocalInfo::DerefTemp, diff --git a/compiler/rustc_mir_transform/src/elaborate_box_derefs.rs b/compiler/rustc_mir_transform/src/elaborate_box_derefs.rs index e51f771e00d..1c917a85c03 100644 --- a/compiler/rustc_mir_transform/src/elaborate_box_derefs.rs +++ b/compiler/rustc_mir_transform/src/elaborate_box_derefs.rs @@ -69,7 +69,7 @@ impl<'tcx, 'a> MutVisitor<'tcx> for ElaborateBoxDerefVisitor<'tcx, 'a> { let (unique_ty, nonnull_ty, ptr_ty) = build_ptr_tys(tcx, base_ty.boxed_ty(), self.unique_did, self.nonnull_did); - let ptr_local = self.patch.new_internal(ptr_ty, source_info.span); + let ptr_local = self.patch.new_temp(ptr_ty, source_info.span); self.patch.add_assign( location, diff --git a/compiler/rustc_mir_transform/src/elaborate_drops.rs b/compiler/rustc_mir_transform/src/elaborate_drops.rs index b62d7da2a4c..d18fdaaf22f 100644 --- a/compiler/rustc_mir_transform/src/elaborate_drops.rs +++ b/compiler/rustc_mir_transform/src/elaborate_drops.rs @@ -271,7 +271,7 @@ impl<'b, 'tcx> ElaborateDropsCtxt<'b, 'tcx> { let tcx = self.tcx; let patch = &mut self.patch; debug!("create_drop_flag({:?})", self.body.span); - self.drop_flags[index].get_or_insert_with(|| patch.new_internal(tcx.types.bool, span)); + self.drop_flags[index].get_or_insert_with(|| patch.new_temp(tcx.types.bool, span)); } fn drop_flag(&mut self, index: MovePathIndex) -> Option<Place<'tcx>> { diff --git a/compiler/rustc_mir_transform/src/generator.rs b/compiler/rustc_mir_transform/src/generator.rs index 8a807d786a5..c16f07a453c 100644 --- a/compiler/rustc_mir_transform/src/generator.rs +++ b/compiler/rustc_mir_transform/src/generator.rs @@ -321,7 +321,7 @@ impl<'tcx> TransformVisitor<'tcx> { // Create a statement which reads the discriminant into a temporary fn get_discr(&self, body: &mut Body<'tcx>) -> (Statement<'tcx>, Place<'tcx>) { - let temp_decl = LocalDecl::new(self.discr_ty, body.span).internal(); + let temp_decl = LocalDecl::new(self.discr_ty, body.span); let local_decls_len = body.local_decls.push(temp_decl); let temp = Place::from(local_decls_len); diff --git a/compiler/rustc_mir_transform/src/inline.rs b/compiler/rustc_mir_transform/src/inline.rs index b53e0852c09..32dfb743905 100644 --- a/compiler/rustc_mir_transform/src/inline.rs +++ b/compiler/rustc_mir_transform/src/inline.rs @@ -616,9 +616,7 @@ impl<'tcx> Inliner<'tcx> { // If there are any locals without storage markers, give them storage only for the // duration of the call. for local in callee_body.vars_and_temps_iter() { - if !callee_body.local_decls[local].internal - && integrator.always_live_locals.contains(local) - { + if integrator.always_live_locals.contains(local) { let new_local = integrator.map_local(local); caller_body[callsite.block].statements.push(Statement { source_info: callsite.source_info, @@ -641,9 +639,7 @@ impl<'tcx> Inliner<'tcx> { n += 1; } for local in callee_body.vars_and_temps_iter().rev() { - if !callee_body.local_decls[local].internal - && integrator.always_live_locals.contains(local) - { + if integrator.always_live_locals.contains(local) { let new_local = integrator.map_local(local); caller_body[block].statements.push(Statement { source_info: callsite.source_info, diff --git a/compiler/rustc_mir_transform/src/lib.rs b/compiler/rustc_mir_transform/src/lib.rs index 22381844d6d..c0a09b7a761 100644 --- a/compiler/rustc_mir_transform/src/lib.rs +++ b/compiler/rustc_mir_transform/src/lib.rs @@ -467,7 +467,6 @@ pub fn run_analysis_to_runtime_passes<'tcx>(tcx: TyCtxt<'tcx>, body: &mut Body<' /// After this series of passes, no lifetime analysis based on borrowing can be done. fn run_analysis_cleanup_passes<'tcx>(tcx: TyCtxt<'tcx>, body: &mut Body<'tcx>) { let passes: &[&dyn MirPass<'tcx>] = &[ - &add_subtyping_projections::Subtyper, &cleanup_post_borrowck::CleanupPostBorrowck, &remove_noop_landing_pads::RemoveNoopLandingPads, &simplify::SimplifyCfg::EarlyOpt, @@ -483,6 +482,7 @@ fn run_runtime_lowering_passes<'tcx>(tcx: TyCtxt<'tcx>, body: &mut Body<'tcx>) { // These next passes must be executed together &add_call_guards::CriticalCallEdges, &reveal_all::RevealAll, // has to be done before drop elaboration, since we need to drop opaque types, too. + &add_subtyping_projections::Subtyper, // calling this after reveal_all ensures that we don't deal with opaque types &elaborate_drops::ElaborateDrops, // This will remove extraneous landing pads which are no longer // necessary as well as well as forcing any call in a non-unwinding diff --git a/compiler/rustc_mir_transform/src/reveal_all.rs b/compiler/rustc_mir_transform/src/reveal_all.rs index 55f1eac6f84..1626cf3c035 100644 --- a/compiler/rustc_mir_transform/src/reveal_all.rs +++ b/compiler/rustc_mir_transform/src/reveal_all.rs @@ -46,16 +46,18 @@ impl<'tcx> MutVisitor<'tcx> for RevealAllVisitor<'tcx> { .filter(|elem| !matches!(elem, ProjectionElem::OpaqueCast(_))) .collect::<Vec<_>>(), ); + self.super_place(place, _context, _location); } #[inline] - fn visit_constant(&mut self, constant: &mut ConstOperand<'tcx>, _: Location) { + fn visit_constant(&mut self, constant: &mut ConstOperand<'tcx>, location: Location) { // We have to use `try_normalize_erasing_regions` here, since it's // possible that we visit impossible-to-satisfy where clauses here, // see #91745 if let Ok(c) = self.tcx.try_normalize_erasing_regions(self.param_env, constant.const_) { constant.const_ = c; } + self.super_constant(constant, location); } #[inline] diff --git a/compiler/rustc_parse/src/parser/ty.rs b/compiler/rustc_parse/src/parser/ty.rs index a25b0f1f893..0a64b2f806a 100644 --- a/compiler/rustc_parse/src/parser/ty.rs +++ b/compiler/rustc_parse/src/parser/ty.rs @@ -247,7 +247,7 @@ impl<'a> Parser<'a> { )?; FnRetTy::Ty(ty) } else { - FnRetTy::Default(self.token.span.shrink_to_lo()) + FnRetTy::Default(self.prev_token.span.shrink_to_hi()) }) } diff --git a/compiler/rustc_passes/src/dead.rs b/compiler/rustc_passes/src/dead.rs index 493daf314ce..f853039f72c 100644 --- a/compiler/rustc_passes/src/dead.rs +++ b/compiler/rustc_passes/src/dead.rs @@ -1,6 +1,7 @@ -// This implements the dead-code warning pass. It follows middle::reachable -// closely. The idea is that all reachable symbols are live, codes called -// from live codes are live, and everything else is dead. +// This implements the dead-code warning pass. +// All reachable symbols are live, code called from live code is live, code with certain lint +// expectations such as `#[expect(unused)]` and `#[expect(dead_code)]` is live, and everything else +// is dead. use hir::def_id::{LocalDefIdMap, LocalDefIdSet}; use itertools::Itertools; @@ -747,7 +748,7 @@ fn live_symbols_and_ignored_derived_traits( (symbol_visitor.live_symbols, symbol_visitor.ignored_derived_traits) } -struct DeadVariant { +struct DeadItem { def_id: LocalDefId, name: Symbol, level: lint::Level, @@ -785,7 +786,13 @@ impl<'tcx> DeadVisitor<'tcx> { ShouldWarnAboutField::Yes(is_positional) } - fn warn_multiple_dead_codes( + // # Panics + // All `dead_codes` must have the same lint level, otherwise we will intentionally ICE. + // This is because we emit a multi-spanned lint using the lint level of the `dead_codes`'s + // first local def id. + // Prefer calling `Self.warn_dead_code` or `Self.warn_dead_code_grouped_by_lint_level` + // since those methods group by lint level before calling this method. + fn lint_at_single_level( &self, dead_codes: &[LocalDefId], participle: &str, @@ -796,6 +803,15 @@ impl<'tcx> DeadVisitor<'tcx> { return; }; let tcx = self.tcx; + + let first_hir_id = tcx.hir().local_def_id_to_hir_id(first_id); + let first_lint_level = tcx.lint_level_at_node(lint::builtin::DEAD_CODE, first_hir_id).0; + assert!(dead_codes.iter().skip(1).all(|id| { + let hir_id = tcx.hir().local_def_id_to_hir_id(*id); + let level = tcx.lint_level_at_node(lint::builtin::DEAD_CODE, hir_id).0; + level == first_lint_level + })); + let names: Vec<_> = dead_codes.iter().map(|&def_id| tcx.item_name(def_id.to_def_id())).collect(); let spans: Vec<_> = dead_codes @@ -876,31 +892,26 @@ impl<'tcx> DeadVisitor<'tcx> { } }; - self.tcx.emit_spanned_lint( - lint, - tcx.hir().local_def_id_to_hir_id(first_id), - MultiSpan::from_spans(spans), - diag, - ); + self.tcx.emit_spanned_lint(lint, first_hir_id, MultiSpan::from_spans(spans), diag); } - fn warn_dead_fields_and_variants( + fn warn_multiple( &self, def_id: LocalDefId, participle: &str, - dead_codes: Vec<DeadVariant>, + dead_codes: Vec<DeadItem>, is_positional: bool, ) { let mut dead_codes = dead_codes .iter() .filter(|v| !v.name.as_str().starts_with('_')) - .collect::<Vec<&DeadVariant>>(); + .collect::<Vec<&DeadItem>>(); if dead_codes.is_empty() { return; } dead_codes.sort_by_key(|v| v.level); for (_, group) in &dead_codes.into_iter().group_by(|v| v.level) { - self.warn_multiple_dead_codes( + self.lint_at_single_level( &group.map(|v| v.def_id).collect::<Vec<_>>(), participle, Some(def_id), @@ -910,7 +921,7 @@ impl<'tcx> DeadVisitor<'tcx> { } fn warn_dead_code(&mut self, id: LocalDefId, participle: &str) { - self.warn_multiple_dead_codes(&[id], participle, None, false); + self.lint_at_single_level(&[id], participle, None, false); } fn check_definition(&mut self, def_id: LocalDefId) { @@ -954,17 +965,16 @@ fn check_mod_deathness(tcx: TyCtxt<'_>, module: LocalModDefId) { if let hir::ItemKind::Impl(impl_item) = tcx.hir().item(item).kind { let mut dead_items = Vec::new(); for item in impl_item.items { - let did = item.id.owner_id.def_id; - if !visitor.is_live_code(did) { - dead_items.push(did) + let def_id = item.id.owner_id.def_id; + if !visitor.is_live_code(def_id) { + let name = tcx.item_name(def_id.to_def_id()); + let hir_id = tcx.hir().local_def_id_to_hir_id(def_id); + let level = tcx.lint_level_at_node(lint::builtin::DEAD_CODE, hir_id).0; + + dead_items.push(DeadItem { def_id, name, level }) } } - visitor.warn_multiple_dead_codes( - &dead_items, - "used", - Some(item.owner_id.def_id), - false, - ); + visitor.warn_multiple(item.owner_id.def_id, "used", dead_items, false); } if !live_symbols.contains(&item.owner_id.def_id) { @@ -988,7 +998,7 @@ fn check_mod_deathness(tcx: TyCtxt<'_>, module: LocalModDefId) { // Record to group diagnostics. let hir_id = tcx.hir().local_def_id_to_hir_id(def_id); let level = tcx.lint_level_at_node(lint::builtin::DEAD_CODE, hir_id).0; - dead_variants.push(DeadVariant { def_id, name: variant.name, level }); + dead_variants.push(DeadItem { def_id, name: variant.name, level }); continue; } @@ -1013,21 +1023,16 @@ fn check_mod_deathness(tcx: TyCtxt<'_>, module: LocalModDefId) { hir_id, ) .0; - Some(DeadVariant { def_id, name: field.name, level }) + Some(DeadItem { def_id, name: field.name, level }) } else { None } }) .collect(); - visitor.warn_dead_fields_and_variants(def_id, "read", dead_fields, is_positional) + visitor.warn_multiple(def_id, "read", dead_fields, is_positional); } - visitor.warn_dead_fields_and_variants( - item.owner_id.def_id, - "constructed", - dead_variants, - false, - ); + visitor.warn_multiple(item.owner_id.def_id, "constructed", dead_variants, false); } } diff --git a/compiler/rustc_smir/src/rustc_smir/mod.rs b/compiler/rustc_smir/src/rustc_smir/mod.rs index c6c97ce35e8..7d1122c2fd2 100644 --- a/compiler/rustc_smir/src/rustc_smir/mod.rs +++ b/compiler/rustc_smir/src/rustc_smir/mod.rs @@ -15,7 +15,7 @@ use rustc_middle::mir::interpret::{alloc_range, AllocId}; use rustc_middle::ty::{self, Ty, TyCtxt, Variance}; use rustc_span::def_id::{CrateNum, DefId, LOCAL_CRATE}; use rustc_target::abi::FieldIdx; -use stable_mir::mir::{CopyNonOverlapping, UserTypeProjection, VariantIdx}; +use stable_mir::mir::{CopyNonOverlapping, Statement, UserTypeProjection, VariantIdx}; use stable_mir::ty::{FloatTy, GenericParamDef, IntTy, Movability, RigidTy, Span, TyKind, UintTy}; use stable_mir::{self, opaque, Context}; use tracing::debug; @@ -106,7 +106,14 @@ impl<'tcx> Context for Tables<'tcx> { .collect(), }) .collect(), - locals: mir.local_decls.iter().map(|decl| self.intern_ty(decl.ty)).collect(), + locals: mir + .local_decls + .iter() + .map(|decl| stable_mir::mir::LocalDecl { + ty: self.intern_ty(decl.ty), + span: decl.source_info.span.stable(self), + }) + .collect(), } } @@ -223,41 +230,64 @@ pub(crate) trait Stable<'tcx> { impl<'tcx> Stable<'tcx> for mir::Statement<'tcx> { type T = stable_mir::mir::Statement; fn stable(&self, tables: &mut Tables<'tcx>) -> Self::T { - use rustc_middle::mir::StatementKind::*; - match &self.kind { - Assign(assign) => { - stable_mir::mir::Statement::Assign(assign.0.stable(tables), assign.1.stable(tables)) - } - FakeRead(fake_read_place) => stable_mir::mir::Statement::FakeRead( - fake_read_place.0.stable(tables), - fake_read_place.1.stable(tables), + Statement { kind: self.kind.stable(tables), span: self.source_info.span.stable(tables) } + } +} + +impl<'tcx> Stable<'tcx> for mir::StatementKind<'tcx> { + type T = stable_mir::mir::StatementKind; + fn stable(&self, tables: &mut Tables<'tcx>) -> Self::T { + match self { + mir::StatementKind::Assign(assign) => stable_mir::mir::StatementKind::Assign( + assign.0.stable(tables), + assign.1.stable(tables), ), - SetDiscriminant { place: plc, variant_index: idx } => { - stable_mir::mir::Statement::SetDiscriminant { - place: plc.as_ref().stable(tables), - variant_index: idx.stable(tables), + mir::StatementKind::FakeRead(fake_read_place) => { + stable_mir::mir::StatementKind::FakeRead( + fake_read_place.0.stable(tables), + fake_read_place.1.stable(tables), + ) + } + mir::StatementKind::SetDiscriminant { place, variant_index } => { + stable_mir::mir::StatementKind::SetDiscriminant { + place: place.as_ref().stable(tables), + variant_index: variant_index.stable(tables), } } - Deinit(place) => stable_mir::mir::Statement::Deinit(place.stable(tables)), - StorageLive(place) => stable_mir::mir::Statement::StorageLive(place.stable(tables)), - StorageDead(place) => stable_mir::mir::Statement::StorageDead(place.stable(tables)), - Retag(retag, place) => { - stable_mir::mir::Statement::Retag(retag.stable(tables), place.stable(tables)) + mir::StatementKind::Deinit(place) => { + stable_mir::mir::StatementKind::Deinit(place.stable(tables)) + } + + mir::StatementKind::StorageLive(place) => { + stable_mir::mir::StatementKind::StorageLive(place.stable(tables)) + } + + mir::StatementKind::StorageDead(place) => { + stable_mir::mir::StatementKind::StorageDead(place.stable(tables)) + } + mir::StatementKind::Retag(retag, place) => { + stable_mir::mir::StatementKind::Retag(retag.stable(tables), place.stable(tables)) + } + mir::StatementKind::PlaceMention(place) => { + stable_mir::mir::StatementKind::PlaceMention(place.stable(tables)) } - PlaceMention(place) => stable_mir::mir::Statement::PlaceMention(place.stable(tables)), - AscribeUserType(place_projection, variance) => { - stable_mir::mir::Statement::AscribeUserType { + mir::StatementKind::AscribeUserType(place_projection, variance) => { + stable_mir::mir::StatementKind::AscribeUserType { place: place_projection.as_ref().0.stable(tables), projections: place_projection.as_ref().1.stable(tables), variance: variance.stable(tables), } } - Coverage(coverage) => stable_mir::mir::Statement::Coverage(opaque(coverage)), - Intrinsic(intrinstic) => { - stable_mir::mir::Statement::Intrinsic(intrinstic.stable(tables)) + mir::StatementKind::Coverage(coverage) => { + stable_mir::mir::StatementKind::Coverage(opaque(coverage)) + } + mir::StatementKind::Intrinsic(intrinstic) => { + stable_mir::mir::StatementKind::Intrinsic(intrinstic.stable(tables)) + } + mir::StatementKind::ConstEvalCounter => { + stable_mir::mir::StatementKind::ConstEvalCounter } - ConstEvalCounter => stable_mir::mir::Statement::ConstEvalCounter, - Nop => stable_mir::mir::Statement::Nop, + mir::StatementKind::Nop => stable_mir::mir::StatementKind::Nop, } } } @@ -806,11 +836,20 @@ impl<'tcx> Stable<'tcx> for mir::InlineAsmOperand<'tcx> { impl<'tcx> Stable<'tcx> for mir::Terminator<'tcx> { type T = stable_mir::mir::Terminator; fn stable(&self, tables: &mut Tables<'tcx>) -> Self::T { - use rustc_middle::mir::TerminatorKind::*; use stable_mir::mir::Terminator; - match &self.kind { - Goto { target } => Terminator::Goto { target: target.as_usize() }, - SwitchInt { discr, targets } => Terminator::SwitchInt { + Terminator { kind: self.kind.stable(tables), span: self.source_info.span.stable(tables) } + } +} + +impl<'tcx> Stable<'tcx> for mir::TerminatorKind<'tcx> { + type T = stable_mir::mir::TerminatorKind; + fn stable(&self, tables: &mut Tables<'tcx>) -> Self::T { + use stable_mir::mir::TerminatorKind; + match self { + mir::TerminatorKind::Goto { target } => { + TerminatorKind::Goto { target: target.as_usize() } + } + mir::TerminatorKind::SwitchInt { discr, targets } => TerminatorKind::SwitchInt { discr: discr.stable(tables), targets: targets .iter() @@ -821,42 +860,60 @@ impl<'tcx> Stable<'tcx> for mir::Terminator<'tcx> { .collect(), otherwise: targets.otherwise().as_usize(), }, - UnwindResume => Terminator::Resume, - UnwindTerminate(_) => Terminator::Abort, - Return => Terminator::Return, - Unreachable => Terminator::Unreachable, - Drop { place, target, unwind, replace: _ } => Terminator::Drop { - place: place.stable(tables), - target: target.as_usize(), - unwind: unwind.stable(tables), - }, - Call { func, args, destination, target, unwind, call_source: _, fn_span: _ } => { - Terminator::Call { - func: func.stable(tables), - args: args.iter().map(|arg| arg.stable(tables)).collect(), - destination: destination.stable(tables), - target: target.map(|t| t.as_usize()), + mir::TerminatorKind::UnwindResume => TerminatorKind::Resume, + mir::TerminatorKind::UnwindTerminate(_) => TerminatorKind::Abort, + mir::TerminatorKind::Return => TerminatorKind::Return, + mir::TerminatorKind::Unreachable => TerminatorKind::Unreachable, + mir::TerminatorKind::Drop { place, target, unwind, replace: _ } => { + TerminatorKind::Drop { + place: place.stable(tables), + target: target.as_usize(), unwind: unwind.stable(tables), } } - Assert { cond, expected, msg, target, unwind } => Terminator::Assert { - cond: cond.stable(tables), - expected: *expected, - msg: msg.stable(tables), - target: target.as_usize(), + mir::TerminatorKind::Call { + func, + args, + destination, + target, + unwind, + call_source: _, + fn_span: _, + } => TerminatorKind::Call { + func: func.stable(tables), + args: args.iter().map(|arg| arg.stable(tables)).collect(), + destination: destination.stable(tables), + target: target.map(|t| t.as_usize()), unwind: unwind.stable(tables), }, - InlineAsm { template, operands, options, line_spans, destination, unwind } => { - Terminator::InlineAsm { - template: format!("{template:?}"), - operands: operands.iter().map(|operand| operand.stable(tables)).collect(), - options: format!("{options:?}"), - line_spans: format!("{line_spans:?}"), - destination: destination.map(|d| d.as_usize()), + mir::TerminatorKind::Assert { cond, expected, msg, target, unwind } => { + TerminatorKind::Assert { + cond: cond.stable(tables), + expected: *expected, + msg: msg.stable(tables), + target: target.as_usize(), unwind: unwind.stable(tables), } } - Yield { .. } | GeneratorDrop | FalseEdge { .. } | FalseUnwind { .. } => unreachable!(), + mir::TerminatorKind::InlineAsm { + template, + operands, + options, + line_spans, + destination, + unwind, + } => TerminatorKind::InlineAsm { + template: format!("{template:?}"), + operands: operands.iter().map(|operand| operand.stable(tables)).collect(), + options: format!("{options:?}"), + line_spans: format!("{line_spans:?}"), + destination: destination.map(|d| d.as_usize()), + unwind: unwind.stable(tables), + }, + mir::TerminatorKind::Yield { .. } + | mir::TerminatorKind::GeneratorDrop + | mir::TerminatorKind::FalseEdge { .. } + | mir::TerminatorKind::FalseUnwind { .. } => unreachable!(), } } } diff --git a/compiler/rustc_trait_selection/src/traits/error_reporting/suggestions.rs b/compiler/rustc_trait_selection/src/traits/error_reporting/suggestions.rs index 15f2ba809a4..b7c73501280 100644 --- a/compiler/rustc_trait_selection/src/traits/error_reporting/suggestions.rs +++ b/compiler/rustc_trait_selection/src/traits/error_reporting/suggestions.rs @@ -4000,14 +4000,6 @@ impl<'tcx> TypeErrCtxtExt<'tcx> for TypeErrCtxt<'_, 'tcx> { // ... whose signature is `async` (i.e. this is an AFIT) let (sig, body) = item.expect_fn(); - let hir::IsAsync::Async(async_span) = sig.header.asyncness else { - return; - }; - let Ok(async_span) = - self.tcx.sess.source_map().span_extend_while(async_span, |c| c.is_whitespace()) - else { - return; - }; let hir::FnRetTy::Return(hir::Ty { kind: hir::TyKind::OpaqueDef(def, ..), .. }) = sig.decl.output else { @@ -4021,55 +4013,17 @@ impl<'tcx> TypeErrCtxtExt<'tcx> for TypeErrCtxt<'_, 'tcx> { return; } - let future = self.tcx.hir().item(*def).expect_opaque_ty(); - let Some(hir::GenericBound::LangItemTrait(_, _, _, generics)) = future.bounds.get(0) else { - // `async fn` should always lower to a lang item bound... but don't ICE. - return; - }; - let Some(hir::TypeBindingKind::Equality { term: hir::Term::Ty(future_output_ty) }) = - generics.bindings.get(0).map(|binding| binding.kind) - else { - // Also should never happen. + let Some(sugg) = suggest_desugaring_async_fn_to_impl_future_in_trait( + self.tcx, + *sig, + *body, + opaque_def_id.expect_local(), + &format!(" + {auto_trait}"), + ) else { return; }; let function_name = self.tcx.def_path_str(fn_def_id); - - let mut sugg = if future_output_ty.span.is_empty() { - vec![ - (async_span, String::new()), - ( - future_output_ty.span, - format!(" -> impl std::future::Future<Output = ()> + {auto_trait}"), - ), - ] - } else { - vec![ - ( - future_output_ty.span.shrink_to_lo(), - "impl std::future::Future<Output = ".to_owned(), - ), - (future_output_ty.span.shrink_to_hi(), format!("> + {auto_trait}")), - (async_span, String::new()), - ] - }; - - // If there's a body, we also need to wrap it in `async {}` - if let hir::TraitFn::Provided(body) = body { - let body = self.tcx.hir().body(*body); - let body_span = body.value.span; - let body_span_without_braces = - body_span.with_lo(body_span.lo() + BytePos(1)).with_hi(body_span.hi() - BytePos(1)); - if body_span_without_braces.is_empty() { - sugg.push((body_span_without_braces, " async {} ".to_owned())); - } else { - sugg.extend([ - (body_span_without_braces.shrink_to_lo(), "async {".to_owned()), - (body_span_without_braces.shrink_to_hi(), "} ".to_owned()), - ]); - } - } - err.multipart_suggestion( format!( "`{auto_trait}` can be made part of the associated future's \ @@ -4321,3 +4275,65 @@ impl<'tcx> TypeFolder<TyCtxt<'tcx>> for ReplaceImplTraitFolder<'tcx> { self.tcx } } + +pub fn suggest_desugaring_async_fn_to_impl_future_in_trait<'tcx>( + tcx: TyCtxt<'tcx>, + sig: hir::FnSig<'tcx>, + body: hir::TraitFn<'tcx>, + opaque_def_id: LocalDefId, + add_bounds: &str, +) -> Option<Vec<(Span, String)>> { + let hir::IsAsync::Async(async_span) = sig.header.asyncness else { + return None; + }; + let Ok(async_span) = tcx.sess.source_map().span_extend_while(async_span, |c| c.is_whitespace()) + else { + return None; + }; + + let future = tcx.hir().get_by_def_id(opaque_def_id).expect_item().expect_opaque_ty(); + let Some(hir::GenericBound::LangItemTrait(_, _, _, generics)) = future.bounds.get(0) else { + // `async fn` should always lower to a lang item bound... but don't ICE. + return None; + }; + let Some(hir::TypeBindingKind::Equality { term: hir::Term::Ty(future_output_ty) }) = + generics.bindings.get(0).map(|binding| binding.kind) + else { + // Also should never happen. + return None; + }; + + let mut sugg = if future_output_ty.span.is_empty() { + vec![ + (async_span, String::new()), + ( + future_output_ty.span, + format!(" -> impl std::future::Future<Output = ()>{add_bounds}"), + ), + ] + } else { + vec![ + (future_output_ty.span.shrink_to_lo(), "impl std::future::Future<Output = ".to_owned()), + (future_output_ty.span.shrink_to_hi(), format!(">{add_bounds}")), + (async_span, String::new()), + ] + }; + + // If there's a body, we also need to wrap it in `async {}` + if let hir::TraitFn::Provided(body) = body { + let body = tcx.hir().body(body); + let body_span = body.value.span; + let body_span_without_braces = + body_span.with_lo(body_span.lo() + BytePos(1)).with_hi(body_span.hi() - BytePos(1)); + if body_span_without_braces.is_empty() { + sugg.push((body_span_without_braces, " async {} ".to_owned())); + } else { + sugg.extend([ + (body_span_without_braces.shrink_to_lo(), "async {".to_owned()), + (body_span_without_braces.shrink_to_hi(), "} ".to_owned()), + ]); + } + } + + Some(sugg) +} diff --git a/compiler/rustc_trait_selection/src/traits/vtable.rs b/compiler/rustc_trait_selection/src/traits/vtable.rs index e41073937be..f23c100a686 100644 --- a/compiler/rustc_trait_selection/src/traits/vtable.rs +++ b/compiler/rustc_trait_selection/src/traits/vtable.rs @@ -316,7 +316,7 @@ fn vtable_entries<'tcx>( dump_vtable_entries(tcx, sp, trait_ref, &entries); } - tcx.arena.alloc_from_iter(entries.into_iter()) + tcx.arena.alloc_from_iter(entries) } /// Find slot base for trait methods within vtable entries of another trait diff --git a/compiler/rustc_ty_utils/src/abi.rs b/compiler/rustc_ty_utils/src/abi.rs index 16183403d67..b118ddaab2b 100644 --- a/compiler/rustc_ty_utils/src/abi.rs +++ b/compiler/rustc_ty_utils/src/abi.rs @@ -528,7 +528,7 @@ fn fn_abi_adjust_for_abi<'tcx>( arg.make_indirect(); } else { // We want to pass small aggregates as immediates, but using - // a LLVM aggregate type for this leads to bad optimizations, + // an LLVM aggregate type for this leads to bad optimizations, // so we pick an appropriately sized integer type instead. arg.cast_to(Reg { kind: RegKind::Integer, size }); } diff --git a/compiler/rustc_ty_utils/src/consts.rs b/compiler/rustc_ty_utils/src/consts.rs index 383cc996b9e..35487d3b698 100644 --- a/compiler/rustc_ty_utils/src/consts.rs +++ b/compiler/rustc_ty_utils/src/consts.rs @@ -71,7 +71,7 @@ pub(crate) fn destructure_const<'tcx>( _ => bug!("cannot destructure constant {:?}", const_), }; - let fields = tcx.arena.alloc_from_iter(fields.into_iter()); + let fields = tcx.arena.alloc_from_iter(fields); ty::DestructuredConst { variant, fields } } diff --git a/compiler/stable_mir/src/mir/body.rs b/compiler/stable_mir/src/mir/body.rs index 6f8f7b06fa3..72f026ee8de 100644 --- a/compiler/stable_mir/src/mir/body.rs +++ b/compiler/stable_mir/src/mir/body.rs @@ -5,7 +5,13 @@ use crate::{ty::Ty, Span}; #[derive(Clone, Debug)] pub struct Body { pub blocks: Vec<BasicBlock>, - pub locals: Vec<Ty>, + pub locals: Vec<LocalDecl>, +} + +#[derive(Clone, Debug)] +pub struct LocalDecl { + pub ty: Ty, + pub span: Span, } #[derive(Clone, Debug)] @@ -15,7 +21,13 @@ pub struct BasicBlock { } #[derive(Clone, Debug)] -pub enum Terminator { +pub struct Terminator { + pub kind: TerminatorKind, + pub span: Span, +} + +#[derive(Clone, Debug)] +pub enum TerminatorKind { Goto { target: usize, }, @@ -179,7 +191,13 @@ pub enum NonDivergingIntrinsic { } #[derive(Clone, Debug)] -pub enum Statement { +pub struct Statement { + pub kind: StatementKind, + pub span: Span, +} + +#[derive(Clone, Debug)] +pub enum StatementKind { Assign(Place, Rvalue), FakeRead(FakeReadCause, Place), SetDiscriminant { place: Place, variant_index: VariantIdx }, |
