diff options
| author | bors <bors@rust-lang.org> | 2022-07-16 20:31:42 +0000 |
|---|---|---|
| committer | bors <bors@rust-lang.org> | 2022-07-16 20:31:42 +0000 |
| commit | d5e7f4782e4b699728d0a08200ecd1a54d56a85d (patch) | |
| tree | 2ecfa500407be289cf19a91c39d2ce7bdd511731 /compiler | |
| parent | 7210e46dc69a4b197a313d093fe145722c248b7d (diff) | |
| parent | 6277ac2fb8bf97cd910a0a841c6924b246d32c44 (diff) | |
| download | rust-d5e7f4782e4b699728d0a08200ecd1a54d56a85d.tar.gz rust-d5e7f4782e4b699728d0a08200ecd1a54d56a85d.zip | |
Auto merge of #99346 - matthiaskrgr:rollup-p4dl1qt, r=matthiaskrgr
Rollup of 10 pull requests Successful merges: - #98582 (Allow destructuring opaque types in their defining scopes) - #99213 (migrate some of `rustc_passes::check_attr`'s diagnostics and derive improvements) - #99258 (Provide structured suggestion for dropped temp value) - #99259 (interpret/visitor: support visiting with a PlaceTy) - #99287 ([rustdoc-json] JSON no longer inlines) - #99290 (Revert "Highlight conflicting param-env candidates") - #99316 (docs: add missing word) - #99317 (Borrow Vec<T, A> as [T]) - #99323 (Fix flakyness of GUI tests) - #99342 (Avoid some `Symbol` to `String` conversions) Failed merges: r? `@ghost` `@rustbot` modify labels: rollup
Diffstat (limited to 'compiler')
73 files changed, 1635 insertions, 997 deletions
diff --git a/compiler/rustc_borrowck/src/diagnostics/conflict_errors.rs b/compiler/rustc_borrowck/src/diagnostics/conflict_errors.rs index 0ceb63477c8..ee96dbc2f60 100644 --- a/compiler/rustc_borrowck/src/diagnostics/conflict_errors.rs +++ b/compiler/rustc_borrowck/src/diagnostics/conflict_errors.rs @@ -7,7 +7,7 @@ use rustc_errors::{ }; use rustc_hir as hir; use rustc_hir::def_id::DefId; -use rustc_hir::intravisit::{walk_expr, Visitor}; +use rustc_hir::intravisit::{walk_block, walk_expr, Visitor}; use rustc_hir::{AsyncGeneratorKind, GeneratorKind}; use rustc_infer::infer::TyCtxtInferExt; use rustc_infer::traits::ObligationCause; @@ -23,7 +23,7 @@ use rustc_middle::ty::{ use rustc_mir_dataflow::move_paths::{InitKind, MoveOutIndex, MovePathIndex}; use rustc_span::hygiene::DesugaringKind; use rustc_span::symbol::sym; -use rustc_span::{BytePos, Span}; +use rustc_span::{BytePos, Span, Symbol}; use rustc_trait_selection::infer::InferCtxtExt; use rustc_trait_selection::traits::TraitEngineExt as _; @@ -1227,8 +1227,7 @@ impl<'cx, 'tcx> MirBorrowckCtxt<'cx, 'tcx> { from_closure: false, region_name: RegionName { - source: - RegionNameSource::AnonRegionFromUpvar(upvar_span, ref upvar_name), + source: RegionNameSource::AnonRegionFromUpvar(upvar_span, upvar_name), .. }, span, @@ -1500,7 +1499,70 @@ impl<'cx, 'tcx> MirBorrowckCtxt<'cx, 'tcx> { | BorrowExplanation::UsedLaterInLoop(..) | BorrowExplanation::UsedLaterWhenDropped { .. } => { // Only give this note and suggestion if it could be relevant. - err.note("consider using a `let` binding to create a longer lived value"); + let sm = self.infcx.tcx.sess.source_map(); + let mut suggested = false; + let msg = "consider using a `let` binding to create a longer lived value"; + + /// We check that there's a single level of block nesting to ensure always correct + /// suggestions. If we don't, then we only provide a free-form message to avoid + /// misleading users in cases like `src/test/ui/nll/borrowed-temporary-error.rs`. + /// We could expand the analysis to suggest hoising all of the relevant parts of + /// the users' code to make the code compile, but that could be too much. + struct NestedStatementVisitor { + span: Span, + current: usize, + found: usize, + } + + impl<'tcx> Visitor<'tcx> for NestedStatementVisitor { + fn visit_block(&mut self, block: &hir::Block<'tcx>) { + self.current += 1; + walk_block(self, block); + self.current -= 1; + } + fn visit_expr(&mut self, expr: &hir::Expr<'tcx>) { + if self.span == expr.span { + self.found = self.current; + } + walk_expr(self, expr); + } + } + let source_info = self.body.source_info(location); + if let Some(scope) = self.body.source_scopes.get(source_info.scope) + && let ClearCrossCrate::Set(scope_data) = &scope.local_data + && let Some(node) = self.infcx.tcx.hir().find(scope_data.lint_root) + && let Some(id) = node.body_id() + && let hir::ExprKind::Block(block, _) = self.infcx.tcx.hir().body(id).value.kind + { + for stmt in block.stmts { + let mut visitor = NestedStatementVisitor { + span: proper_span, + current: 0, + found: 0, + }; + visitor.visit_stmt(stmt); + if visitor.found == 0 + && stmt.span.contains(proper_span) + && let Some(p) = sm.span_to_margin(stmt.span) + && let Ok(s) = sm.span_to_snippet(proper_span) + { + let addition = format!("let binding = {};\n{}", s, " ".repeat(p)); + err.multipart_suggestion_verbose( + msg, + vec![ + (stmt.span.shrink_to_lo(), addition), + (proper_span, "binding".to_string()), + ], + Applicability::MaybeIncorrect, + ); + suggested = true; + break; + } + } + } + if !suggested { + err.note(msg); + } } _ => {} } @@ -1699,7 +1761,7 @@ impl<'cx, 'tcx> MirBorrowckCtxt<'cx, 'tcx> { borrow_span: Span, name: &Option<String>, upvar_span: Span, - upvar_name: &str, + upvar_name: Symbol, escape_span: Span, ) -> DiagnosticBuilder<'cx, ErrorGuaranteed> { let tcx = self.infcx.tcx; @@ -2093,7 +2155,9 @@ impl<'cx, 'tcx> MirBorrowckCtxt<'cx, 'tcx> { } StorageDeadOrDrop::Destructor(_) => kind, }, - ProjectionElem::Field(..) | ProjectionElem::Downcast(..) => { + ProjectionElem::OpaqueCast { .. } + | ProjectionElem::Field(..) + | ProjectionElem::Downcast(..) => { match place_ty.ty.kind() { ty::Adt(def, _) if def.has_dtor(tcx) => { // Report the outermost adt with a destructor diff --git a/compiler/rustc_borrowck/src/diagnostics/explain_borrow.rs b/compiler/rustc_borrowck/src/diagnostics/explain_borrow.rs index 230ccf51990..72aee0267ac 100644 --- a/compiler/rustc_borrowck/src/diagnostics/explain_borrow.rs +++ b/compiler/rustc_borrowck/src/diagnostics/explain_borrow.rs @@ -12,7 +12,7 @@ use rustc_middle::mir::{ }; use rustc_middle::ty::adjustment::PointerCast; use rustc_middle::ty::{self, RegionVid, TyCtxt}; -use rustc_span::symbol::Symbol; +use rustc_span::symbol::{kw, Symbol}; use rustc_span::{sym, DesugaringKind, Span}; use crate::region_infer::BlameConstraint; @@ -282,7 +282,7 @@ impl<'tcx> BorrowExplanation<'tcx> { ) { if let ConstraintCategory::OpaqueType = category { let suggestable_name = - if region_name.was_named() { region_name.to_string() } else { "'_".to_string() }; + if region_name.was_named() { region_name.name } else { kw::UnderscoreLifetime }; let msg = format!( "you can add a bound to the {}to make it last less than `'static` and match `{}`", diff --git a/compiler/rustc_borrowck/src/diagnostics/mod.rs b/compiler/rustc_borrowck/src/diagnostics/mod.rs index 53c07a3d481..fada3d45fbe 100644 --- a/compiler/rustc_borrowck/src/diagnostics/mod.rs +++ b/compiler/rustc_borrowck/src/diagnostics/mod.rs @@ -226,6 +226,7 @@ impl<'cx, 'tcx> MirBorrowckCtxt<'cx, 'tcx> { } ProjectionElem::Downcast(..) if including_downcast.0 => return None, ProjectionElem::Downcast(..) => (), + ProjectionElem::OpaqueCast(..) => (), ProjectionElem::Field(field, _ty) => { // FIXME(project-rfc_2229#36): print capture precisely here. if let Some(field) = self.is_upvar_field_projection(PlaceRef { @@ -286,6 +287,7 @@ impl<'cx, 'tcx> MirBorrowckCtxt<'cx, 'tcx> { PlaceRef { local, projection: proj_base }.ty(self.body, self.infcx.tcx) } ProjectionElem::Downcast(..) => place.ty(self.body, self.infcx.tcx), + ProjectionElem::OpaqueCast(ty) => PlaceTy::from_ty(*ty), ProjectionElem::Field(_, field_type) => PlaceTy::from_ty(*field_type), }, }; diff --git a/compiler/rustc_borrowck/src/diagnostics/mutability_errors.rs b/compiler/rustc_borrowck/src/diagnostics/mutability_errors.rs index 8134e122662..cb7077fe621 100644 --- a/compiler/rustc_borrowck/src/diagnostics/mutability_errors.rs +++ b/compiler/rustc_borrowck/src/diagnostics/mutability_errors.rs @@ -169,6 +169,7 @@ impl<'a, 'tcx> MirBorrowckCtxt<'a, 'tcx> { .., ProjectionElem::Index(_) | ProjectionElem::ConstantIndex { .. } + | ProjectionElem::OpaqueCast { .. } | ProjectionElem::Subslice { .. } | ProjectionElem::Downcast(..), ], diff --git a/compiler/rustc_borrowck/src/diagnostics/region_errors.rs b/compiler/rustc_borrowck/src/diagnostics/region_errors.rs index 6508c0da75f..0e6a05478a0 100644 --- a/compiler/rustc_borrowck/src/diagnostics/region_errors.rs +++ b/compiler/rustc_borrowck/src/diagnostics/region_errors.rs @@ -19,8 +19,7 @@ use rustc_middle::ty::subst::InternalSubsts; use rustc_middle::ty::Region; use rustc_middle::ty::TypeVisitor; use rustc_middle::ty::{self, RegionVid, Ty}; -use rustc_span::symbol::sym; -use rustc_span::symbol::Ident; +use rustc_span::symbol::{kw, sym, Ident}; use rustc_span::Span; use crate::borrowck_errors; @@ -758,7 +757,7 @@ impl<'a, 'tcx> MirBorrowckCtxt<'a, 'tcx> { return; }; - let lifetime = if f.has_name() { fr_name.to_string() } else { "'_".to_string() }; + let lifetime = if f.has_name() { fr_name.name } else { kw::UnderscoreLifetime }; let arg = match param.param.pat.simple_ident() { Some(simple_ident) => format!("argument `{}`", simple_ident), @@ -770,7 +769,7 @@ impl<'a, 'tcx> MirBorrowckCtxt<'a, 'tcx> { self.infcx.tcx, diag, fn_returns, - lifetime, + lifetime.to_string(), Some(arg), captures, Some((param.param_ty_span, param.param_ty.to_string())), diff --git a/compiler/rustc_borrowck/src/diagnostics/region_name.rs b/compiler/rustc_borrowck/src/diagnostics/region_name.rs index e41af17fbf9..4cf1ac4d7ab 100644 --- a/compiler/rustc_borrowck/src/diagnostics/region_name.rs +++ b/compiler/rustc_borrowck/src/diagnostics/region_name.rs @@ -34,13 +34,13 @@ pub(crate) enum RegionNameSource { /// The `'static` region. Static, /// The free region corresponding to the environment of a closure. - SynthesizedFreeEnvRegion(Span, String), + SynthesizedFreeEnvRegion(Span, &'static str), /// The region corresponding to an argument. AnonRegionFromArgument(RegionNameHighlight), /// The region corresponding to a closure upvar. - AnonRegionFromUpvar(Span, String), + AnonRegionFromUpvar(Span, Symbol), /// The region corresponding to the return type of a closure. - AnonRegionFromOutput(RegionNameHighlight, String), + AnonRegionFromOutput(RegionNameHighlight, &'static str), /// The region from a type yielded by a generator. AnonRegionFromYieldTy(Span, String), /// An anonymous region from an async fn. @@ -110,7 +110,7 @@ impl RegionName { } RegionNameSource::SynthesizedFreeEnvRegion(span, note) => { diag.span_label(*span, format!("lifetime `{self}` represents this closure's body")); - diag.note(note); + diag.note(*note); } RegionNameSource::AnonRegionFromArgument(RegionNameHighlight::CannotMatchHirTy( span, @@ -350,10 +350,7 @@ impl<'tcx> MirBorrowckCtxt<'_, 'tcx> { Some(RegionName { name: region_name, - source: RegionNameSource::SynthesizedFreeEnvRegion( - fn_decl_span, - note.to_string(), - ), + source: RegionNameSource::SynthesizedFreeEnvRegion(fn_decl_span, note), }) } @@ -678,7 +675,7 @@ impl<'tcx> MirBorrowckCtxt<'_, 'tcx> { Some(RegionName { name: region_name, - source: RegionNameSource::AnonRegionFromUpvar(upvar_span, upvar_name.to_string()), + source: RegionNameSource::AnonRegionFromUpvar(upvar_span, upvar_name), }) } @@ -756,7 +753,7 @@ impl<'tcx> MirBorrowckCtxt<'_, 'tcx> { Some(RegionName { name: self.synthesize_region_name(), - source: RegionNameSource::AnonRegionFromOutput(highlight, mir_description.to_string()), + source: RegionNameSource::AnonRegionFromOutput(highlight, mir_description), }) } diff --git a/compiler/rustc_borrowck/src/lib.rs b/compiler/rustc_borrowck/src/lib.rs index e8673ecd3a0..74321ddcd99 100644 --- a/compiler/rustc_borrowck/src/lib.rs +++ b/compiler/rustc_borrowck/src/lib.rs @@ -1788,6 +1788,7 @@ impl<'cx, 'tcx> MirBorrowckCtxt<'cx, 'tcx> { for (place_base, elem) in place.iter_projections().rev() { match elem { ProjectionElem::Index(_/*operand*/) | + ProjectionElem::OpaqueCast(_) | ProjectionElem::ConstantIndex { .. } | // assigning to P[i] requires P to be valid. ProjectionElem::Downcast(_/*adt_def*/, _/*variant_idx*/) => @@ -2179,6 +2180,7 @@ impl<'cx, 'tcx> MirBorrowckCtxt<'cx, 'tcx> { | ProjectionElem::Index(..) | ProjectionElem::ConstantIndex { .. } | ProjectionElem::Subslice { .. } + | ProjectionElem::OpaqueCast { .. } | ProjectionElem::Downcast(..) => { let upvar_field_projection = self.is_upvar_field_projection(place); if let Some(field) = upvar_field_projection { diff --git a/compiler/rustc_borrowck/src/places_conflict.rs b/compiler/rustc_borrowck/src/places_conflict.rs index 97335fd0dff..5b67e6aa1cf 100644 --- a/compiler/rustc_borrowck/src/places_conflict.rs +++ b/compiler/rustc_borrowck/src/places_conflict.rs @@ -255,6 +255,7 @@ fn place_components_conflict<'tcx>( | (ProjectionElem::Index { .. }, _, _) | (ProjectionElem::ConstantIndex { .. }, _, _) | (ProjectionElem::Subslice { .. }, _, _) + | (ProjectionElem::OpaqueCast { .. }, _, _) | (ProjectionElem::Downcast { .. }, _, _) => { // Recursive case. This can still be disjoint on a // further iteration if this a shallow access and @@ -322,6 +323,17 @@ fn place_projection_conflict<'tcx>( debug!("place_element_conflict: DISJOINT-OR-EQ-DEREF"); Overlap::EqualOrDisjoint } + (ProjectionElem::OpaqueCast(v1), ProjectionElem::OpaqueCast(v2)) => { + if v1 == v2 { + // same type - recur. + debug!("place_element_conflict: DISJOINT-OR-EQ-OPAQUE"); + Overlap::EqualOrDisjoint + } else { + // Different types. Disjoint! + debug!("place_element_conflict: DISJOINT-OPAQUE"); + Overlap::Disjoint + } + } (ProjectionElem::Field(f1, _), ProjectionElem::Field(f2, _)) => { if f1 == f2 { // same field (e.g., `a.y` vs. `a.y`) - recur. @@ -525,6 +537,7 @@ fn place_projection_conflict<'tcx>( | ProjectionElem::Field(..) | ProjectionElem::Index(..) | ProjectionElem::ConstantIndex { .. } + | ProjectionElem::OpaqueCast { .. } | ProjectionElem::Subslice { .. } | ProjectionElem::Downcast(..), _, diff --git a/compiler/rustc_borrowck/src/prefixes.rs b/compiler/rustc_borrowck/src/prefixes.rs index bdf2becb711..2b50cbac9a0 100644 --- a/compiler/rustc_borrowck/src/prefixes.rs +++ b/compiler/rustc_borrowck/src/prefixes.rs @@ -81,6 +81,7 @@ impl<'cx, 'tcx> Iterator for Prefixes<'cx, 'tcx> { } ProjectionElem::Downcast(..) | ProjectionElem::Subslice { .. } + | ProjectionElem::OpaqueCast { .. } | ProjectionElem::ConstantIndex { .. } | ProjectionElem::Index(_) => { cursor = cursor_base; diff --git a/compiler/rustc_borrowck/src/type_check/mod.rs b/compiler/rustc_borrowck/src/type_check/mod.rs index cf2140097e6..8e763a02af3 100644 --- a/compiler/rustc_borrowck/src/type_check/mod.rs +++ b/compiler/rustc_borrowck/src/type_check/mod.rs @@ -790,6 +790,19 @@ impl<'a, 'b, 'tcx> TypeVerifier<'a, 'b, 'tcx> { } PlaceTy::from_ty(fty) } + ProjectionElem::OpaqueCast(ty) => { + let ty = self.sanitize_type(place, ty); + let ty = self.cx.normalize(ty, location); + self.cx + .eq_types( + base.ty, + ty, + location.to_locations(), + ConstraintCategory::TypeAnnotation, + ) + .unwrap(); + PlaceTy::from_ty(ty) + } } } @@ -1195,10 +1208,11 @@ impl<'a, 'tcx> TypeChecker<'a, 'tcx> { tcx, self.param_env, proj, - |this, field, ()| { + |this, field, _| { let ty = this.field_ty(tcx, field); self.normalize(ty, locations) }, + |_, _| unreachable!(), ); curr_projected_ty = projected_ty; } @@ -2493,6 +2507,7 @@ impl<'a, 'tcx> TypeChecker<'a, 'tcx> { } ProjectionElem::Field(..) | ProjectionElem::Downcast(..) + | ProjectionElem::OpaqueCast(..) | ProjectionElem::Index(..) | ProjectionElem::ConstantIndex { .. } | ProjectionElem::Subslice { .. } => { diff --git a/compiler/rustc_codegen_cranelift/src/base.rs b/compiler/rustc_codegen_cranelift/src/base.rs index 63cd4d6de4c..54652623d94 100644 --- a/compiler/rustc_codegen_cranelift/src/base.rs +++ b/compiler/rustc_codegen_cranelift/src/base.rs @@ -825,6 +825,7 @@ pub(crate) fn codegen_place<'tcx>( cplace = cplace.place_deref(fx); } } + PlaceElem::OpaqueCast(ty) => cplace = cplace.place_opaque_cast(fx, ty), PlaceElem::Field(field, _ty) => { cplace = cplace.place_field(fx, field); } diff --git a/compiler/rustc_codegen_cranelift/src/value_and_place.rs b/compiler/rustc_codegen_cranelift/src/value_and_place.rs index a68225de58b..8ff35d2f76d 100644 --- a/compiler/rustc_codegen_cranelift/src/value_and_place.rs +++ b/compiler/rustc_codegen_cranelift/src/value_and_place.rs @@ -615,6 +615,14 @@ impl<'tcx> CPlace<'tcx> { } } + pub(crate) fn place_opaque_cast( + self, + fx: &mut FunctionCx<'_, '_, 'tcx>, + ty: Ty<'tcx>, + ) -> CPlace<'tcx> { + CPlace { inner: self.inner, layout: fx.layout_of(ty) } + } + pub(crate) fn place_field( self, fx: &mut FunctionCx<'_, '_, 'tcx>, diff --git a/compiler/rustc_codegen_ssa/src/mir/place.rs b/compiler/rustc_codegen_ssa/src/mir/place.rs index 58cee0c8bb0..421d6f807ae 100644 --- a/compiler/rustc_codegen_ssa/src/mir/place.rs +++ b/compiler/rustc_codegen_ssa/src/mir/place.rs @@ -411,6 +411,21 @@ impl<'a, 'tcx, V: CodegenObject> PlaceRef<'tcx, V> { downcast } + pub fn project_type<Bx: BuilderMethods<'a, 'tcx, Value = V>>( + &self, + bx: &mut Bx, + ty: Ty<'tcx>, + ) -> Self { + let mut downcast = *self; + downcast.layout = bx.cx().layout_of(ty); + + // Cast to the appropriate type. + let variant_ty = bx.cx().backend_type(downcast.layout); + downcast.llval = bx.pointercast(downcast.llval, bx.cx().type_ptr_to(variant_ty)); + + downcast + } + pub fn storage_live<Bx: BuilderMethods<'a, 'tcx, Value = V>>(&self, bx: &mut Bx) { bx.lifetime_start(self.llval, self.layout.size); } @@ -459,6 +474,7 @@ impl<'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>> FunctionCx<'a, 'tcx, Bx> { mir::ProjectionElem::Field(ref field, _) => { cg_base.project_field(bx, field.index()) } + mir::ProjectionElem::OpaqueCast(ty) => cg_base.project_type(bx, ty), mir::ProjectionElem::Index(index) => { let index = &mir::Operand::Copy(mir::Place::from(index)); let index = self.codegen_operand(bx, index); diff --git a/compiler/rustc_const_eval/src/const_eval/valtrees.rs b/compiler/rustc_const_eval/src/const_eval/valtrees.rs index 2288a4e7b6c..8fff4571d12 100644 --- a/compiler/rustc_const_eval/src/const_eval/valtrees.rs +++ b/compiler/rustc_const_eval/src/const_eval/valtrees.rs @@ -436,7 +436,7 @@ fn valtree_into_mplace<'tcx>( let offset = place_adjusted.layout.fields.offset(i); place - .offset( + .offset_with_meta( offset, MemPlaceMeta::Meta(Scalar::from_machine_usize( num_elems as u64, diff --git a/compiler/rustc_const_eval/src/interpret/operand.rs b/compiler/rustc_const_eval/src/interpret/operand.rs index 1465b986293..22dc1e80f13 100644 --- a/compiler/rustc_const_eval/src/interpret/operand.rs +++ b/compiler/rustc_const_eval/src/interpret/operand.rs @@ -297,7 +297,7 @@ impl<'tcx, Tag: Provenance> OpTy<'tcx, Tag> { } } - pub fn offset( + pub fn offset_with_meta( &self, offset: Size, meta: MemPlaceMeta<Tag>, @@ -305,7 +305,7 @@ impl<'tcx, Tag: Provenance> OpTy<'tcx, Tag> { cx: &impl HasDataLayout, ) -> InterpResult<'tcx, Self> { match self.try_as_mplace() { - Ok(mplace) => Ok(mplace.offset(offset, meta, layout, cx)?.into()), + Ok(mplace) => Ok(mplace.offset_with_meta(offset, meta, layout, cx)?.into()), Err(imm) => { assert!( matches!(*imm, Immediate::Uninit), @@ -317,6 +317,16 @@ impl<'tcx, Tag: Provenance> OpTy<'tcx, Tag> { } } } + + pub fn offset( + &self, + offset: Size, + layout: TyAndLayout<'tcx>, + cx: &impl HasDataLayout, + ) -> InterpResult<'tcx, Self> { + assert!(!layout.is_unsized()); + self.offset_with_meta(offset, MemPlaceMeta::None, layout, cx) + } } impl<'mir, 'tcx: 'mir, M: Machine<'mir, 'tcx>> InterpCx<'mir, 'tcx, M> { diff --git a/compiler/rustc_const_eval/src/interpret/place.rs b/compiler/rustc_const_eval/src/interpret/place.rs index f4b11ea1967..a29a1492c8e 100644 --- a/compiler/rustc_const_eval/src/interpret/place.rs +++ b/compiler/rustc_const_eval/src/interpret/place.rs @@ -163,7 +163,7 @@ impl<Tag: Provenance> MemPlace<Tag> { } #[inline] - pub fn offset<'tcx>( + pub fn offset_with_meta<'tcx>( self, offset: Size, meta: MemPlaceMeta<Tag>, @@ -199,7 +199,7 @@ impl<'tcx, Tag: Provenance> MPlaceTy<'tcx, Tag> { } #[inline] - pub fn offset( + pub fn offset_with_meta( &self, offset: Size, meta: MemPlaceMeta<Tag>, @@ -207,12 +207,22 @@ impl<'tcx, Tag: Provenance> MPlaceTy<'tcx, Tag> { cx: &impl HasDataLayout, ) -> InterpResult<'tcx, Self> { Ok(MPlaceTy { - mplace: self.mplace.offset(offset, meta, cx)?, + mplace: self.mplace.offset_with_meta(offset, meta, cx)?, align: self.align.restrict_for_offset(offset), layout, }) } + pub fn offset( + &self, + offset: Size, + layout: TyAndLayout<'tcx>, + cx: &impl HasDataLayout, + ) -> InterpResult<'tcx, Self> { + assert!(!layout.is_unsized()); + self.offset_with_meta(offset, MemPlaceMeta::None, layout, cx) + } + #[inline] pub fn from_aligned_ptr(ptr: Pointer<Option<Tag>>, layout: TyAndLayout<'tcx>) -> Self { MPlaceTy { mplace: MemPlace::from_ptr(ptr), layout, align: layout.align.abi } diff --git a/compiler/rustc_const_eval/src/interpret/projection.rs b/compiler/rustc_const_eval/src/interpret/projection.rs index 31fb6a8944d..704dc6db060 100644 --- a/compiler/rustc_const_eval/src/interpret/projection.rs +++ b/compiler/rustc_const_eval/src/interpret/projection.rs @@ -63,7 +63,7 @@ where // We do not look at `base.layout.align` nor `field_layout.align`, unlike // codegen -- mostly to see if we can get away with that - base.offset(offset, meta, field_layout, self) + base.offset_with_meta(offset, meta, field_layout, self) } /// Gets the place of a field inside the place, and also the field's type. @@ -193,9 +193,7 @@ where let offset = stride * index; // `Size` multiplication // All fields have the same layout. let field_layout = base.layout.field(self, 0); - assert!(!field_layout.is_unsized()); - - base.offset(offset, MemPlaceMeta::None, field_layout, self) + base.offset(offset, field_layout, self) } _ => span_bug!( self.cur_span(), @@ -215,10 +213,10 @@ where let abi::FieldsShape::Array { stride, .. } = base.layout.fields else { span_bug!(self.cur_span(), "operand_array_fields: expected an array layout"); }; - let layout = base.layout.field(self, 0); + let field_layout = base.layout.field(self, 0); let dl = &self.tcx.data_layout; // `Size` multiplication - Ok((0..len).map(move |i| base.offset(stride * i, MemPlaceMeta::None, layout, dl))) + Ok((0..len).map(move |i| base.offset(stride * i, field_layout, dl))) } /// Index into an array. @@ -326,7 +324,7 @@ where } }; let layout = self.layout_of(ty)?; - base.offset(from_offset, meta, layout, self) + base.offset_with_meta(from_offset, meta, layout, self) } pub fn place_subslice( @@ -351,6 +349,11 @@ where ) -> InterpResult<'tcx, PlaceTy<'tcx, M::PointerTag>> { use rustc_middle::mir::ProjectionElem::*; Ok(match proj_elem { + OpaqueCast(ty) => { + let mut place = *base; + place.layout = self.layout_of(ty)?; + place + } Field(field, _) => self.place_field(base, field.index())?, Downcast(_, variant) => self.place_downcast(base, variant)?, Deref => self.deref_operand(&self.place_to_op(base)?)?.into(), @@ -375,6 +378,11 @@ where ) -> InterpResult<'tcx, OpTy<'tcx, M::PointerTag>> { use rustc_middle::mir::ProjectionElem::*; Ok(match proj_elem { + OpaqueCast(ty) => { + let mut op = *base; + op.layout = self.layout_of(ty)?; + op + } Field(field, _) => self.operand_field(base, field.index())?, Downcast(_, variant) => self.operand_downcast(base, variant)?, Deref => self.deref_operand(base)?.into(), diff --git a/compiler/rustc_const_eval/src/interpret/validity.rs b/compiler/rustc_const_eval/src/interpret/validity.rs index 53bc2cc8a69..2e5492ecf56 100644 --- a/compiler/rustc_const_eval/src/interpret/validity.rs +++ b/compiler/rustc_const_eval/src/interpret/validity.rs @@ -853,7 +853,8 @@ impl<'rt, 'mir, 'tcx: 'mir, M: Machine<'mir, 'tcx>> ValueVisitor<'mir, 'tcx, M> self.visit_scalar(scalar, scalar_layout)?; } Abi::ScalarPair(a_layout, b_layout) => { - // We would validate these things as we descend into the fields, + // There is no `rustc_layout_scalar_valid_range_start` for pairs, so + // we would validate these things as we descend into the fields, // but that can miss bugs in layout computation. Layout computation // is subtle due to enums having ScalarPair layout, where one field // is the discriminant. @@ -867,7 +868,8 @@ impl<'rt, 'mir, 'tcx: 'mir, M: Machine<'mir, 'tcx>> ValueVisitor<'mir, 'tcx, M> } Abi::Vector { .. } => { // No checks here, we assume layout computation gets this right. - // (This is harder to check since Miri does not represent these as `Immediate`.) + // (This is harder to check since Miri does not represent these as `Immediate`. We + // also cannot use field projections since this might be a newtype around a vector.) } Abi::Aggregate { .. } => { // Nothing to do. diff --git a/compiler/rustc_const_eval/src/interpret/visitor.rs b/compiler/rustc_const_eval/src/interpret/visitor.rs index c262bca9bb4..f6a0c19d259 100644 --- a/compiler/rustc_const_eval/src/interpret/visitor.rs +++ b/compiler/rustc_const_eval/src/interpret/visitor.rs @@ -8,23 +8,33 @@ use rustc_target::abi::{FieldsShape, VariantIdx, Variants}; use std::num::NonZeroUsize; -use super::{InterpCx, MPlaceTy, Machine, OpTy}; +use super::{InterpCx, MPlaceTy, Machine, OpTy, PlaceTy}; -// A thing that we can project into, and that has a layout. -// This wouldn't have to depend on `Machine` but with the current type inference, -// that's just more convenient to work with (avoids repeating all the `Machine` bounds). +/// A thing that we can project into, and that has a layout. +/// This wouldn't have to depend on `Machine` but with the current type inference, +/// that's just more convenient to work with (avoids repeating all the `Machine` bounds). pub trait Value<'mir, 'tcx, M: Machine<'mir, 'tcx>>: Copy { /// Gets this value's layout. fn layout(&self) -> TyAndLayout<'tcx>; - /// Makes this into an `OpTy`. - fn to_op(&self, ecx: &InterpCx<'mir, 'tcx, M>) - -> InterpResult<'tcx, OpTy<'tcx, M::PointerTag>>; + /// Makes this into an `OpTy`, in a cheap way that is good for reading. + fn to_op_for_read( + &self, + ecx: &InterpCx<'mir, 'tcx, M>, + ) -> InterpResult<'tcx, OpTy<'tcx, M::PointerTag>>; + + /// Makes this into an `OpTy`, in a potentially more expensive way that is good for projections. + fn to_op_for_proj( + &self, + ecx: &InterpCx<'mir, 'tcx, M>, + ) -> InterpResult<'tcx, OpTy<'tcx, M::PointerTag>> { + self.to_op_for_read(ecx) + } /// Creates this from an `OpTy`. /// - /// If `to_op` only ever produces `Indirect` operands, then this one is definitely `Indirect`. - fn from_op(mplace: OpTy<'tcx, M::PointerTag>) -> Self; + /// If `to_op_for_proj` only ever produces `Indirect` operands, then this one is definitely `Indirect`. + fn from_op(op: &OpTy<'tcx, M::PointerTag>) -> Self; /// Projects to the given enum variant. fn project_downcast( @@ -41,8 +51,50 @@ pub trait Value<'mir, 'tcx, M: Machine<'mir, 'tcx>>: Copy { ) -> InterpResult<'tcx, Self>; } -// Operands and memory-places are both values. -// Places in general are not due to `place_field` having to do `force_allocation`. +/// A thing that we can project into given *mutable* access to `ecx`, and that has a layout. +/// This wouldn't have to depend on `Machine` but with the current type inference, +/// that's just more convenient to work with (avoids repeating all the `Machine` bounds). +pub trait ValueMut<'mir, 'tcx, M: Machine<'mir, 'tcx>>: Copy { + /// Gets this value's layout. + fn layout(&self) -> TyAndLayout<'tcx>; + + /// Makes this into an `OpTy`, in a cheap way that is good for reading. + fn to_op_for_read( + &self, + ecx: &InterpCx<'mir, 'tcx, M>, + ) -> InterpResult<'tcx, OpTy<'tcx, M::PointerTag>>; + + /// Makes this into an `OpTy`, in a potentially more expensive way that is good for projections. + fn to_op_for_proj( + &self, + ecx: &mut InterpCx<'mir, 'tcx, M>, + ) -> InterpResult<'tcx, OpTy<'tcx, M::PointerTag>>; + + /// Creates this from an `OpTy`. + /// + /// If `to_op_for_proj` only ever produces `Indirect` operands, then this one is definitely `Indirect`. + fn from_op(op: &OpTy<'tcx, M::PointerTag>) -> Self; + + /// Projects to the given enum variant. + fn project_downcast( + &self, + ecx: &mut InterpCx<'mir, 'tcx, M>, + variant: VariantIdx, + ) -> InterpResult<'tcx, Self>; + + /// Projects to the n-th field. + fn project_field( + &self, + ecx: &mut InterpCx<'mir, 'tcx, M>, + field: usize, + ) -> InterpResult<'tcx, Self>; +} + +// We cannot have a general impl which shows that Value implies ValueMut. (When we do, it says we +// cannot `impl ValueMut for PlaceTy` because some downstream crate could `impl Value for PlaceTy`.) +// So we have some copy-paste here. (We could have a macro but since we only have 2 types with this +// double-impl, that would barely make the code shorter, if at all.) + impl<'mir, 'tcx: 'mir, M: Machine<'mir, 'tcx>> Value<'mir, 'tcx, M> for OpTy<'tcx, M::PointerTag> { #[inline(always)] fn layout(&self) -> TyAndLayout<'tcx> { @@ -50,7 +102,7 @@ impl<'mir, 'tcx: 'mir, M: Machine<'mir, 'tcx>> Value<'mir, 'tcx, M> for OpTy<'tc } #[inline(always)] - fn to_op( + fn to_op_for_read( &self, _ecx: &InterpCx<'mir, 'tcx, M>, ) -> InterpResult<'tcx, OpTy<'tcx, M::PointerTag>> { @@ -58,8 +110,8 @@ impl<'mir, 'tcx: 'mir, M: Machine<'mir, 'tcx>> Value<'mir, 'tcx, M> for OpTy<'tc } #[inline(always)] - fn from_op(op: OpTy<'tcx, M::PointerTag>) -> Self { - op + fn from_op(op: &OpTy<'tcx, M::PointerTag>) -> Self { + *op } #[inline(always)] @@ -81,6 +133,54 @@ impl<'mir, 'tcx: 'mir, M: Machine<'mir, 'tcx>> Value<'mir, 'tcx, M> for OpTy<'tc } } +impl<'mir, 'tcx: 'mir, M: Machine<'mir, 'tcx>> ValueMut<'mir, 'tcx, M> + for OpTy<'tcx, M::PointerTag> +{ + #[inline(always)] + fn layout(&self) -> TyAndLayout<'tcx> { + self.layout + } + + #[inline(always)] + fn to_op_for_read( + &self, + _ecx: &InterpCx<'mir, 'tcx, M>, + ) -> InterpResult<'tcx, OpTy<'tcx, M::PointerTag>> { + Ok(*self) + } + + #[inline(always)] + fn to_op_for_proj( + &self, + _ecx: &mut InterpCx<'mir, 'tcx, M>, + ) -> InterpResult<'tcx, OpTy<'tcx, M::PointerTag>> { + Ok(*self) + } + + #[inline(always)] + fn from_op(op: &OpTy<'tcx, M::PointerTag>) -> Self { + *op + } + + #[inline(always)] + fn project_downcast( + &self, + ecx: &mut InterpCx<'mir, 'tcx, M>, + variant: VariantIdx, + ) -> InterpResult<'tcx, Self> { + ecx.operand_downcast(self, variant) + } + + #[inline(always)] + fn project_field( + &self, + ecx: &mut InterpCx<'mir, 'tcx, M>, + field: usize, + ) -> InterpResult<'tcx, Self> { + ecx.operand_field(self, field) + } +} + impl<'mir, 'tcx: 'mir, M: Machine<'mir, 'tcx>> Value<'mir, 'tcx, M> for MPlaceTy<'tcx, M::PointerTag> { @@ -90,7 +190,7 @@ impl<'mir, 'tcx: 'mir, M: Machine<'mir, 'tcx>> Value<'mir, 'tcx, M> } #[inline(always)] - fn to_op( + fn to_op_for_read( &self, _ecx: &InterpCx<'mir, 'tcx, M>, ) -> InterpResult<'tcx, OpTy<'tcx, M::PointerTag>> { @@ -98,8 +198,8 @@ impl<'mir, 'tcx: 'mir, M: Machine<'mir, 'tcx>> Value<'mir, 'tcx, M> } #[inline(always)] - fn from_op(op: OpTy<'tcx, M::PointerTag>) -> Self { - // assert is justified because our `to_op` only ever produces `Indirect` operands. + fn from_op(op: &OpTy<'tcx, M::PointerTag>) -> Self { + // assert is justified because our `to_op_for_read` only ever produces `Indirect` operands. op.assert_mem_place() } @@ -122,11 +222,111 @@ impl<'mir, 'tcx: 'mir, M: Machine<'mir, 'tcx>> Value<'mir, 'tcx, M> } } +impl<'mir, 'tcx: 'mir, M: Machine<'mir, 'tcx>> ValueMut<'mir, 'tcx, M> + for MPlaceTy<'tcx, M::PointerTag> +{ + #[inline(always)] + fn layout(&self) -> TyAndLayout<'tcx> { + self.layout + } + + #[inline(always)] + fn to_op_for_read( + &self, + _ecx: &InterpCx<'mir, 'tcx, M>, + ) -> InterpResult<'tcx, OpTy<'tcx, M::PointerTag>> { + Ok(self.into()) + } + + #[inline(always)] + fn to_op_for_proj( + &self, + _ecx: &mut InterpCx<'mir, 'tcx, M>, + ) -> InterpResult<'tcx, OpTy<'tcx, M::PointerTag>> { + Ok(self.into()) + } + + #[inline(always)] + fn from_op(op: &OpTy<'tcx, M::PointerTag>) -> Self { + // assert is justified because our `to_op_for_proj` only ever produces `Indirect` operands. + op.assert_mem_place() + } + + #[inline(always)] + fn project_downcast( + &self, + ecx: &mut InterpCx<'mir, 'tcx, M>, + variant: VariantIdx, + ) -> InterpResult<'tcx, Self> { + ecx.mplace_downcast(self, variant) + } + + #[inline(always)] + fn project_field( + &self, + ecx: &mut InterpCx<'mir, 'tcx, M>, + field: usize, + ) -> InterpResult<'tcx, Self> { + ecx.mplace_field(self, field) + } +} + +impl<'mir, 'tcx: 'mir, M: Machine<'mir, 'tcx>> ValueMut<'mir, 'tcx, M> + for PlaceTy<'tcx, M::PointerTag> +{ + #[inline(always)] + fn layout(&self) -> TyAndLayout<'tcx> { + self.layout + } + + #[inline(always)] + fn to_op_for_read( + &self, + ecx: &InterpCx<'mir, 'tcx, M>, + ) -> InterpResult<'tcx, OpTy<'tcx, M::PointerTag>> { + // We `force_allocation` here so that `from_op` below can work. + ecx.place_to_op(self) + } + + #[inline(always)] + fn to_op_for_proj( + &self, + ecx: &mut InterpCx<'mir, 'tcx, M>, + ) -> InterpResult<'tcx, OpTy<'tcx, M::PointerTag>> { + // We `force_allocation` here so that `from_op` below can work. + Ok(ecx.force_allocation(self)?.into()) + } + + #[inline(always)] + fn from_op(op: &OpTy<'tcx, M::PointerTag>) -> Self { + // assert is justified because our `to_op` only ever produces `Indirect` operands. + op.assert_mem_place().into() + } + + #[inline(always)] + fn project_downcast( + &self, + ecx: &mut InterpCx<'mir, 'tcx, M>, + variant: VariantIdx, + ) -> InterpResult<'tcx, Self> { + ecx.place_downcast(self, variant) + } + + #[inline(always)] + fn project_field( + &self, + ecx: &mut InterpCx<'mir, 'tcx, M>, + field: usize, + ) -> InterpResult<'tcx, Self> { + ecx.place_field(self, field) + } +} + macro_rules! make_value_visitor { - ($visitor_trait_name:ident, $($mutability:ident)?) => { + ($visitor_trait:ident, $value_trait:ident, $($mutability:ident)?) => { // How to traverse a value and what to do when we are at the leaves. - pub trait $visitor_trait_name<'mir, 'tcx: 'mir, M: Machine<'mir, 'tcx>>: Sized { - type V: Value<'mir, 'tcx, M>; + pub trait $visitor_trait<'mir, 'tcx: 'mir, M: Machine<'mir, 'tcx>>: Sized { + type V: $value_trait<'mir, 'tcx, M>; /// The visitor must have an `InterpCx` in it. fn ecx(&$($mutability)? self) @@ -215,19 +415,20 @@ macro_rules! make_value_visitor { } fn walk_value(&mut self, v: &Self::V) -> InterpResult<'tcx> { - trace!("walk_value: type: {}", v.layout().ty); + let ty = v.layout().ty; + trace!("walk_value: type: {ty}"); // Special treatment for special types, where the (static) layout is not sufficient. - match *v.layout().ty.kind() { + match *ty.kind() { // If it is a trait object, switch to the real type that was used to create it. ty::Dynamic(..) => { // unsized values are never immediate, so we can assert_mem_place - let op = v.to_op(self.ecx())?; + let op = v.to_op_for_read(self.ecx())?; let dest = op.assert_mem_place(); - let inner = self.ecx().unpack_dyn_trait(&dest)?.1; - trace!("walk_value: dyn object layout: {:#?}", inner.layout); + let inner_mplace = self.ecx().unpack_dyn_trait(&dest)?.1; + trace!("walk_value: dyn object layout: {:#?}", inner_mplace.layout); // recurse with the inner type - return self.visit_field(&v, 0, &Value::from_op(inner.into())); + return self.visit_field(&v, 0, &$value_trait::from_op(&inner_mplace.into())); }, // Slices do not need special handling here: they have `Array` field // placement with length 0, so we enter the `Array` case below which @@ -278,10 +479,10 @@ macro_rules! make_value_visitor { // Visit the fields of this value. match v.layout().fields { - FieldsShape::Primitive => {}, + FieldsShape::Primitive => {} FieldsShape::Union(fields) => { self.visit_union(v, fields)?; - }, + } FieldsShape::Arbitrary { ref offsets, .. } => { // FIXME: We collect in a vec because otherwise there are lifetime // errors: Projecting to a field needs access to `ecx`. @@ -291,16 +492,17 @@ macro_rules! make_value_visitor { }) .collect(); self.visit_aggregate(v, fields.into_iter())?; - }, + } FieldsShape::Array { .. } => { - // Let's get an mplace first. - let op = v.to_op(self.ecx())?; + // Let's get an mplace (or immediate) first. + // This might `force_allocate` if `v` is a `PlaceTy`, but `place_index` does that anyway. + let op = v.to_op_for_proj(self.ecx())?; // Now we can go over all the fields. // This uses the *run-time length*, i.e., if we are a slice, // the dynamic info from the metadata is used. let iter = self.ecx().operand_array_fields(&op)? .map(|f| f.and_then(|f| { - Ok(Value::from_op(f)) + Ok($value_trait::from_op(&f)) })); self.visit_aggregate(v, iter)?; } @@ -310,7 +512,7 @@ macro_rules! make_value_visitor { // If this is a multi-variant layout, find the right variant and proceed // with *its* fields. Variants::Multiple { .. } => { - let op = v.to_op(self.ecx())?; + let op = v.to_op_for_read(self.ecx())?; let idx = self.read_discriminant(&op)?; let inner = v.project_downcast(self.ecx(), idx)?; trace!("walk_value: variant layout: {:#?}", inner.layout()); @@ -325,5 +527,5 @@ macro_rules! make_value_visitor { } } -make_value_visitor!(ValueVisitor,); -make_value_visitor!(MutValueVisitor, mut); +make_value_visitor!(ValueVisitor, Value,); +make_value_visitor!(MutValueVisitor, ValueMut, mut); 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 628298df473..0581f491978 100644 --- a/compiler/rustc_const_eval/src/transform/check_consts/check.rs +++ b/compiler/rustc_const_eval/src/transform/check_consts/check.rs @@ -652,6 +652,7 @@ impl<'tcx> Visitor<'tcx> for Checker<'_, 'tcx> { ProjectionElem::ConstantIndex { .. } | ProjectionElem::Downcast(..) + | ProjectionElem::OpaqueCast(..) | ProjectionElem::Subslice { .. } | ProjectionElem::Field(..) | ProjectionElem::Index(_) => {} diff --git a/compiler/rustc_const_eval/src/transform/check_consts/qualifs.rs b/compiler/rustc_const_eval/src/transform/check_consts/qualifs.rs index 29464cf8c4e..c2b4f6eca5c 100644 --- a/compiler/rustc_const_eval/src/transform/check_consts/qualifs.rs +++ b/compiler/rustc_const_eval/src/transform/check_consts/qualifs.rs @@ -316,6 +316,7 @@ where ProjectionElem::Deref | ProjectionElem::Field(_, _) + | ProjectionElem::OpaqueCast(_) | ProjectionElem::ConstantIndex { .. } | ProjectionElem::Subslice { .. } | ProjectionElem::Downcast(_, _) diff --git a/compiler/rustc_const_eval/src/transform/promote_consts.rs b/compiler/rustc_const_eval/src/transform/promote_consts.rs index ed4d8c95d1e..daa154576ae 100644 --- a/compiler/rustc_const_eval/src/transform/promote_consts.rs +++ b/compiler/rustc_const_eval/src/transform/promote_consts.rs @@ -361,7 +361,7 @@ impl<'tcx> Validator<'_, 'tcx> { return Err(Unpromotable); } } - ProjectionElem::Downcast(..) => { + ProjectionElem::OpaqueCast(..) | ProjectionElem::Downcast(..) => { return Err(Unpromotable); } diff --git a/compiler/rustc_error_messages/locales/en-US/passes.ftl b/compiler/rustc_error_messages/locales/en-US/passes.ftl new file mode 100644 index 00000000000..e4c9a4dad7b --- /dev/null +++ b/compiler/rustc_error_messages/locales/en-US/passes.ftl @@ -0,0 +1,151 @@ +-passes-previously-accepted = + this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release! + +-passes-see-issue = + see issue #{$issue} <https://github.com/rust-lang/rust/issues/{$issue}> for more information + +passes-outer-crate-level-attr = + crate-level attribute should be an inner attribute: add an exclamation mark: `#![foo]` + +passes-inner-crate-level-attr = + crate-level attribute should be in the root module + +passes-ignored-attr-with-macro = `#[{$sym}]` is ignored on struct fields, match arms and macro defs + .warn = {-passes-previously-accepted} + .note = {-passes-see-issue(issue: "80564")} + +passes-ignored-attr = `#[{$sym}]` is ignored on struct fields and match arms + .warn = {-passes-previously-accepted} + .note = {-passes-see-issue(issue: "80564")} + +passes-inline-ignored-function-prototype = `#[inline]` is ignored on function prototypes + +passes-inline-ignored-constants = `#[inline]` is ignored on constants + .warn = {-passes-previously-accepted} + .note = {-passes-see-issue(issue: "65833")} + +passes-inline-not-fn-or-closure = attribute should be applied to function or closure + .label = not a function or closure + +passes-no-coverage-ignored-function-prototype = `#[no_coverage]` is ignored on function prototypes + +passes-no-coverage-propagate = + `#[no_coverage]` does not propagate into items and must be applied to the contained functions directly + +passes-no-coverage-fn-defn = `#[no_coverage]` may only be applied to function definitions + +passes-no-coverage-not-coverable = `#[no_coverage]` must be applied to coverable code + .label = not coverable code + +passes-should-be-applied-to-fn = attribute should be applied to a function definition + .label = not a function definition + +passes-naked-tracked-caller = cannot use `#[track_caller]` with `#[naked]` + +passes-should-be-applied-to-struct-enum = attribute should be applied to a struct or enum + .label = not a struct or enum + +passes-should-be-applied-to-trait = attribute should be applied to a trait + .label = not a trait + +passes-target-feature-on-statement = {passes-should-be-applied-to-fn} + .warn = {-passes-previously-accepted} + .label = {passes-should-be-applied-to-fn.label} + +passes-should-be-applied-to-static = attribute should be applied to a static + .label = not a static + +passes-doc-expect-str = doc {$attr_name} attribute expects a string: #[doc({$attr_name} = "a")] + +passes-doc-alias-empty = {$attr_str} attribute cannot have empty value + +passes-doc-alias-bad-char = {$char_} character isn't allowed in {$attr_str} + +passes-doc-alias-start-end = {$attr_str} cannot start or end with ' ' + +passes-doc-alias-bad-location = {$attr_str} isn't allowed on {$location} + +passes-doc-alias-not-an-alias = {$attr_str} is the same as the item's name + +passes-doc-alias-duplicated = doc alias is duplicated + .label = first defined here + +passes-doc-alias-not-string-literal = `#[doc(alias("a"))]` expects string literals + +passes-doc-alias-malformed = + doc alias attribute expects a string `#[doc(alias = "a")]` or a list of strings `#[doc(alias("a", "b"))]` + +passes-doc-keyword-empty-mod = `#[doc(keyword = "...")]` should be used on empty modules + +passes-doc-keyword-not-mod = `#[doc(keyword = "...")]` should be used on modules + +passes-doc-keyword-invalid-ident = `{$doc_keyword}` is not a valid identifier + +passes-doc-tuple-variadic-not-first = + `#[doc(tuple_variadic)]` must be used on the first of a set of tuple trait impls with varying arity + +passes-doc-keyword-only-impl = `#[doc(keyword = "...")]` should be used on impl blocks + +passes-doc-inline-conflict-first = this attribute... +passes-doc-inline-conflict-second = ...conflicts with this attribute +passes-doc-inline-conflict = conflicting doc inlining attributes + .help = remove one of the conflicting attributes + +passes-doc-inline-only-use = this attribute can only be applied to a `use` item + .label = only applicable on `use` items + .not-a-use-item-label = not a `use` item + .note = read <https://doc.rust-lang.org/nightly/rustdoc/the-doc-attribute.html#inline-and-no_inline> for more information + +passes-doc-attr-not-crate-level = + `#![doc({$attr_name} = "...")]` isn't allowed as a crate-level attribute + +passes-attr-crate-level = this attribute can only be applied at the crate level + .suggestion = to apply to the crate, use an inner attribute + .help = to apply to the crate, use an inner attribute + .note = read <https://doc.rust-lang.org/nightly/rustdoc/the-doc-attribute.html#at-the-crate-level> for more information + +passes-doc-test-unknown = unknown `doc(test)` attribute `{$path}` + +passes-doc-test-takes-list = `#[doc(test(...)]` takes a list of attributes + +passes-doc-primitive = `doc(primitive)` should never have been stable + +passes-doc-test-unknown-any = unknown `doc` attribute `{$path}` + +passes-doc-test-unknown-spotlight = unknown `doc` attribute `{$path}` + .note = `doc(spotlight)` was renamed to `doc(notable_trait)` + .suggestion = use `notable_trait` instead + .no-op-note = `doc(spotlight)` is now a no-op + +passes-doc-test-unknown-include = unknown `doc` attribute `{$path}` + .suggestion = use `doc = include_str!` instead + +passes-doc-invalid = invalid `doc` attribute + +passes-pass-by-value = `pass_by_value` attribute should be applied to a struct, enum or type alias + .label = is not a struct, enum or type alias + +passes-allow-incoherent-impl = + `rustc_allow_incoherent_impl` attribute should be applied to impl items. + .label = the only currently supported targets are inherent methods + +passes-has-incoherent-inherent-impl = + `rustc_has_incoherent_inherent_impls` attribute should be applied to types or traits. + .label = only adts, extern types and traits are supported + +passes-must-use-async = + `must_use` attribute on `async` functions applies to the anonymous `Future` returned by the function, not the value within + .label = this attribute does nothing, the `Future`s returned by async functions are already `must_use` + +passes-must-use-no-effect = `#[must_use]` has no effect when applied to {$article} {$target} + +passes-must-not-suspend = `must_not_suspend` attribute should be applied to a struct, enum, or trait + .label = is not a struct, enum, or trait + +passes-cold = {passes-should-be-applied-to-fn} + .warn = {-passes-previously-accepted} + .label = {passes-should-be-applied-to-fn.label} + +passes-link = attribute should be applied to an `extern` block with non-Rust ABI + .warn = {-passes-previously-accepted} + .label = not an `extern` block diff --git a/compiler/rustc_error_messages/locales/en-US/privacy.ftl b/compiler/rustc_error_messages/locales/en-US/privacy.ftl index 2b0778f48ca..f8a750da93f 100644 --- a/compiler/rustc_error_messages/locales/en-US/privacy.ftl +++ b/compiler/rustc_error_messages/locales/en-US/privacy.ftl @@ -10,3 +10,12 @@ privacy-unnamed-item-is-private = {$kind} is private privacy-in-public-interface = {$vis_descr} {$kind} `{$descr}` in public interface .label = can't leak {$vis_descr} {$kind} .visibility-label = `{$descr}` declared as {$vis_descr} + +privacy-from-private-dep-in-public-interface = + {$kind} `{$descr}` from private dependency '{$krate}' in public interface + +private-in-public-lint = + {$vis_descr} {$kind} `{$descr}` in public interface (error {$kind -> + [trait] E0445 + *[other] E0446 + }) diff --git a/compiler/rustc_error_messages/src/lib.rs b/compiler/rustc_error_messages/src/lib.rs index d16171cb162..a3040f83fdf 100644 --- a/compiler/rustc_error_messages/src/lib.rs +++ b/compiler/rustc_error_messages/src/lib.rs @@ -37,6 +37,7 @@ fluent_messages! { expand => "../locales/en-US/expand.ftl", lint => "../locales/en-US/lint.ftl", parser => "../locales/en-US/parser.ftl", + passes => "../locales/en-US/passes.ftl", privacy => "../locales/en-US/privacy.ftl", typeck => "../locales/en-US/typeck.ftl", } diff --git a/compiler/rustc_errors/src/diagnostic.rs b/compiler/rustc_errors/src/diagnostic.rs index da321c45875..7d7f3e18335 100644 --- a/compiler/rustc_errors/src/diagnostic.rs +++ b/compiler/rustc_errors/src/diagnostic.rs @@ -40,6 +40,35 @@ pub trait IntoDiagnosticArg { fn into_diagnostic_arg(self) -> DiagnosticArgValue<'static>; } +macro_rules! into_diagnostic_arg_using_display { + ($( $ty:ty ),+ $(,)?) => { + $( + impl IntoDiagnosticArg for $ty { + fn into_diagnostic_arg(self) -> DiagnosticArgValue<'static> { + self.to_string().into_diagnostic_arg() + } + } + )+ + } +} + +into_diagnostic_arg_using_display!( + i8, + u8, + i16, + u16, + i32, + u32, + i64, + u64, + i128, + u128, + std::num::NonZeroU32, + hir::Target, + Edition, + Ident, +); + impl IntoDiagnosticArg for bool { fn into_diagnostic_arg(self) -> DiagnosticArgValue<'static> { if self { @@ -50,81 +79,9 @@ impl IntoDiagnosticArg for bool { } } -impl IntoDiagnosticArg for i8 { - fn into_diagnostic_arg(self) -> DiagnosticArgValue<'static> { - DiagnosticArgValue::Str(Cow::Owned(self.to_string())) - } -} - -impl IntoDiagnosticArg for u8 { +impl IntoDiagnosticArg for char { fn into_diagnostic_arg(self) -> DiagnosticArgValue<'static> { - DiagnosticArgValue::Str(Cow::Owned(self.to_string())) - } -} - -impl IntoDiagnosticArg for i16 { - fn into_diagnostic_arg(self) -> DiagnosticArgValue<'static> { - DiagnosticArgValue::Str(Cow::Owned(self.to_string())) - } -} - -impl IntoDiagnosticArg for u16 { - fn into_diagnostic_arg(self) -> DiagnosticArgValue<'static> { - DiagnosticArgValue::Str(Cow::Owned(self.to_string())) - } -} - -impl IntoDiagnosticArg for i32 { - fn into_diagnostic_arg(self) -> DiagnosticArgValue<'static> { - DiagnosticArgValue::Str(Cow::Owned(self.to_string())) - } -} - -impl IntoDiagnosticArg for u32 { - fn into_diagnostic_arg(self) -> DiagnosticArgValue<'static> { - DiagnosticArgValue::Str(Cow::Owned(self.to_string())) - } -} - -impl IntoDiagnosticArg for i64 { - fn into_diagnostic_arg(self) -> DiagnosticArgValue<'static> { - DiagnosticArgValue::Str(Cow::Owned(self.to_string())) - } -} - -impl IntoDiagnosticArg for u64 { - fn into_diagnostic_arg(self) -> DiagnosticArgValue<'static> { - DiagnosticArgValue::Str(Cow::Owned(self.to_string())) - } -} - -impl IntoDiagnosticArg for i128 { - fn into_diagnostic_arg(self) -> DiagnosticArgValue<'static> { - DiagnosticArgValue::Str(Cow::Owned(self.to_string())) - } -} - -impl IntoDiagnosticArg for u128 { - fn into_diagnostic_arg(self) -> DiagnosticArgValue<'static> { - DiagnosticArgValue::Str(Cow::Owned(self.to_string())) - } -} - -impl IntoDiagnosticArg for String { - fn into_diagnostic_arg(self) -> DiagnosticArgValue<'static> { - DiagnosticArgValue::Str(Cow::Owned(self)) - } -} - -impl IntoDiagnosticArg for std::num::NonZeroU32 { - fn into_diagnostic_arg(self) -> DiagnosticArgValue<'static> { - DiagnosticArgValue::Str(Cow::Owned(self.to_string())) - } -} - -impl IntoDiagnosticArg for Edition { - fn into_diagnostic_arg(self) -> DiagnosticArgValue<'static> { - DiagnosticArgValue::Str(Cow::Owned(self.to_string())) + DiagnosticArgValue::Str(Cow::Owned(format!("{:?}", self))) } } @@ -134,15 +91,15 @@ impl IntoDiagnosticArg for Symbol { } } -impl IntoDiagnosticArg for Ident { +impl<'a> IntoDiagnosticArg for &'a str { fn into_diagnostic_arg(self) -> DiagnosticArgValue<'static> { self.to_string().into_diagnostic_arg() } } -impl<'a> IntoDiagnosticArg for &'a str { +impl IntoDiagnosticArg for String { fn into_diagnostic_arg(self) -> DiagnosticArgValue<'static> { - self.to_string().into_diagnostic_arg() + DiagnosticArgValue::Str(Cow::Owned(self)) } } @@ -496,7 +453,7 @@ impl Diagnostic { self } - pub fn note_trait_signature(&mut self, name: String, signature: String) -> &mut Self { + pub fn note_trait_signature(&mut self, name: Symbol, signature: String) -> &mut Self { self.highlighted_note(vec![ (format!("`{}` from trait: `", name), Style::NoStyle), (signature, Style::Highlight), diff --git a/compiler/rustc_errors/src/diagnostic_builder.rs b/compiler/rustc_errors/src/diagnostic_builder.rs index 99ac6a3546e..9e68ee282e6 100644 --- a/compiler/rustc_errors/src/diagnostic_builder.rs +++ b/compiler/rustc_errors/src/diagnostic_builder.rs @@ -595,6 +595,7 @@ macro_rules! error_code { pub struct LintDiagnosticBuilder<'a, G: EmissionGuarantee>(DiagnosticBuilder<'a, G>); impl<'a, G: EmissionGuarantee> LintDiagnosticBuilder<'a, G> { + #[rustc_lint_diagnostics] /// Return the inner `DiagnosticBuilder`, first setting the primary message to `msg`. pub fn build(mut self, msg: impl Into<DiagnosticMessage>) -> DiagnosticBuilder<'a, G> { self.0.set_primary_message(msg); diff --git a/compiler/rustc_expand/src/module.rs b/compiler/rustc_expand/src/module.rs index 876faad33b6..0315d11634c 100644 --- a/compiler/rustc_expand/src/module.rs +++ b/compiler/rustc_expand/src/module.rs @@ -218,10 +218,9 @@ pub fn default_submod_path<'a>( "" }; - let mod_name = ident.name.to_string(); - let default_path_str = format!("{}{}.rs", relative_prefix, mod_name); + let default_path_str = format!("{}{}.rs", relative_prefix, ident.name); let secondary_path_str = - format!("{}{}{}mod.rs", relative_prefix, mod_name, path::MAIN_SEPARATOR); + format!("{}{}{}mod.rs", relative_prefix, ident.name, path::MAIN_SEPARATOR); let default_path = dir_path.join(&default_path_str); let secondary_path = dir_path.join(&secondary_path_str); let default_exists = sess.source_map().file_exists(&default_path); diff --git a/compiler/rustc_infer/src/infer/error_reporting/need_type_info.rs b/compiler/rustc_infer/src/infer/error_reporting/need_type_info.rs index 066bf9681b6..b267140daa9 100644 --- a/compiler/rustc_infer/src/infer/error_reporting/need_type_info.rs +++ b/compiler/rustc_infer/src/infer/error_reporting/need_type_info.rs @@ -138,7 +138,7 @@ fn fmt_printer<'a, 'tcx>(infcx: &'a InferCtxt<'_, 'tcx>, ns: Namespace) -> FmtPr if let TypeVariableOriginKind::TypeParameterDefinition(name, _) = infcx.inner.borrow_mut().type_variables().var_origin(ty_vid).kind { - Some(name.to_string()) + Some(name) } else { None } @@ -151,7 +151,7 @@ fn fmt_printer<'a, 'tcx>(infcx: &'a InferCtxt<'_, 'tcx>, ns: Namespace) -> FmtPr if let ConstVariableOriginKind::ConstParameterDefinition(name, _) = infcx.inner.borrow_mut().const_unification_table().probe_value(ct_vid).origin.kind { - return Some(name.to_string()); + return Some(name); } else { None } diff --git a/compiler/rustc_macros/src/diagnostics/diagnostic.rs b/compiler/rustc_macros/src/diagnostics/diagnostic.rs index 027f377b0ac..6b5b8b59320 100644 --- a/compiler/rustc_macros/src/diagnostics/diagnostic.rs +++ b/compiler/rustc_macros/src/diagnostics/diagnostic.rs @@ -59,7 +59,7 @@ impl<'a> SessionDiagnosticDerive<'a> { return DiagnosticDeriveError::ErrorHandled.to_compile_error(); } (Some(DiagnosticDeriveKind::Lint), _) => { - span_err(span, "only `#[error(..)]` and `#[warn(..)]` are supported") + span_err(span, "only `#[error(..)]` and `#[warning(..)]` are supported") .help("use the `#[error(...)]` attribute to create a error") .emit(); return DiagnosticDeriveError::ErrorHandled.to_compile_error(); diff --git a/compiler/rustc_macros/src/diagnostics/diagnostic_builder.rs b/compiler/rustc_macros/src/diagnostics/diagnostic_builder.rs index 74ce1ab08c2..5c5275b7cfb 100644 --- a/compiler/rustc_macros/src/diagnostics/diagnostic_builder.rs +++ b/compiler/rustc_macros/src/diagnostics/diagnostic_builder.rs @@ -8,12 +8,13 @@ use crate::diagnostics::utils::{ report_error_if_not_applied_to_span, report_type_error, type_is_unit, type_matches_path, Applicability, FieldInfo, FieldInnerTy, HasFieldMap, SetOnce, }; -use proc_macro2::{Ident, TokenStream}; +use proc_macro2::{Ident, Span, TokenStream}; use quote::{format_ident, quote}; use std::collections::HashMap; use std::str::FromStr; use syn::{ - parse_quote, spanned::Spanned, Attribute, Meta, MetaList, MetaNameValue, NestedMeta, Path, Type, + parse_quote, spanned::Spanned, Attribute, Field, Meta, MetaList, MetaNameValue, NestedMeta, + Path, Type, }; use synstructure::{BindingInfo, Structure}; @@ -80,8 +81,8 @@ impl DiagnosticDeriveBuilder { } pub fn body<'s>(&mut self, structure: &mut Structure<'s>) -> (TokenStream, TokenStream) { - // Keep track of which fields are subdiagnostics or have no attributes. - let mut subdiagnostics_or_empty = std::collections::HashSet::new(); + // Keep track of which fields need to be handled with a by-move binding. + let mut needs_moved = std::collections::HashSet::new(); // Generates calls to `span_label` and similar functions based on the attributes // on fields. Code for suggestions uses formatting machinery and the value of @@ -92,16 +93,11 @@ impl DiagnosticDeriveBuilder { let attrs = structure .clone() .filter(|field_binding| { - let attrs = &field_binding.ast().attrs; - - (!attrs.is_empty() - && attrs.iter().all(|attr| { - "subdiagnostic" != attr.path.segments.last().unwrap().ident.to_string() - })) - || { - subdiagnostics_or_empty.insert(field_binding.binding.clone()); - false - } + let ast = &field_binding.ast(); + !self.needs_move(ast) || { + needs_moved.insert(field_binding.binding.clone()); + false + } }) .each(|field_binding| self.generate_field_attrs_code(field_binding)); @@ -111,12 +107,41 @@ impl DiagnosticDeriveBuilder { // attributes or a `#[subdiagnostic]` attribute then it must be passed as an // argument to the diagnostic so that it can be referred to by Fluent messages. let args = structure - .filter(|field_binding| subdiagnostics_or_empty.contains(&field_binding.binding)) + .filter(|field_binding| needs_moved.contains(&field_binding.binding)) .each(|field_binding| self.generate_field_attrs_code(field_binding)); (attrs, args) } + /// Returns `true` if `field` should generate a `set_arg` call rather than any other diagnostic + /// call (like `span_label`). + fn should_generate_set_arg(&self, field: &Field) -> bool { + field.attrs.is_empty() + } + + /// Returns `true` if `field` needs to have code generated in the by-move branch of the + /// generated derive rather than the by-ref branch. + fn needs_move(&self, field: &Field) -> bool { + let generates_set_arg = self.should_generate_set_arg(field); + let is_multispan = type_matches_path(&field.ty, &["rustc_errors", "MultiSpan"]); + // FIXME(davidtwco): better support for one field needing to be in the by-move and + // by-ref branches. + let is_subdiagnostic = field + .attrs + .iter() + .map(|attr| attr.path.segments.last().unwrap().ident.to_string()) + .any(|attr| attr == "subdiagnostic"); + + // `set_arg` calls take their argument by-move.. + generates_set_arg + // If this is a `MultiSpan` field then it needs to be moved to be used by any + // attribute.. + || is_multispan + // If this a `#[subdiagnostic]` then it needs to be moved as the other diagnostic is + // unlikely to be `Copy`.. + || is_subdiagnostic + } + /// Establishes state in the `DiagnosticDeriveBuilder` resulting from the struct /// attributes like `#[error(..)`, such as the diagnostic kind and slug. Generates /// diagnostic builder calls for setting error code and creating note/help messages. @@ -131,7 +156,7 @@ impl DiagnosticDeriveBuilder { let name = name.as_str(); let meta = attr.parse_meta()?; - let is_help_or_note = matches!(name, "help" | "note"); + let is_help_note_or_warn = matches!(name, "help" | "note" | "warn_"); let nested = match meta { // Most attributes are lists, like `#[error(..)]`/`#[warning(..)]` for most cases or @@ -139,8 +164,12 @@ impl DiagnosticDeriveBuilder { Meta::List(MetaList { ref nested, .. }) => nested, // Subdiagnostics without spans can be applied to the type too, and these are just // paths: `#[help]` and `#[note]` - Meta::Path(_) if is_help_or_note => { - let fn_name = proc_macro2::Ident::new(name, attr.span()); + Meta::Path(_) if is_help_note_or_warn => { + let fn_name = if name == "warn_" { + Ident::new("warn", attr.span()) + } else { + Ident::new(name, attr.span()) + }; return Ok(quote! { #diag.#fn_name(rustc_errors::fluent::_subdiag::#fn_name); }); } _ => throw_invalid_attr!(attr, &meta), @@ -152,9 +181,11 @@ impl DiagnosticDeriveBuilder { "error" => self.kind.set_once((DiagnosticDeriveKind::Error, span)), "warning" => self.kind.set_once((DiagnosticDeriveKind::Warn, span)), "lint" => self.kind.set_once((DiagnosticDeriveKind::Lint, span)), - "help" | "note" => (), + "help" | "note" | "warn_" => (), _ => throw_invalid_attr!(attr, &meta, |diag| { - diag.help("only `error`, `warning`, `help` and `note` are valid attributes") + diag.help( + "only `error`, `warning`, `help`, `note` and `warn_` are valid attributes", + ) }), } @@ -163,14 +194,16 @@ impl DiagnosticDeriveBuilder { let mut nested_iter = nested.into_iter(); if let Some(nested_attr) = nested_iter.next() { // Report an error if there are any other list items after the path. - if is_help_or_note && nested_iter.next().is_some() { + if is_help_note_or_warn && nested_iter.next().is_some() { throw_invalid_nested_attr!(attr, &nested_attr, |diag| { - diag.help("`help` and `note` struct attributes can only have one argument") + diag.help( + "`help`, `note` and `warn_` struct attributes can only have one argument", + ) }); } match nested_attr { - NestedMeta::Meta(Meta::Path(path)) if is_help_or_note => { + NestedMeta::Meta(Meta::Path(path)) if is_help_note_or_warn => { let fn_name = proc_macro2::Ident::new(name, attr.span()); return Ok(quote! { #diag.#fn_name(rustc_errors::fluent::#path); }); } @@ -178,7 +211,7 @@ impl DiagnosticDeriveBuilder { self.slug.set_once((path.clone(), span)); } NestedMeta::Meta(meta @ Meta::NameValue(_)) - if !is_help_or_note + if !is_help_note_or_warn && meta.path().segments.last().unwrap().ident.to_string() == "code" => { // don't error for valid follow-up attributes @@ -227,57 +260,55 @@ impl DiagnosticDeriveBuilder { let field = binding_info.ast(); let field_binding = &binding_info.binding; - let inner_ty = FieldInnerTy::from_type(&field.ty); - - // When generating `set_arg` or `add_subdiagnostic` calls, move data rather than - // borrow it to avoid requiring clones - this must therefore be the last use of - // each field (for example, any formatting machinery that might refer to a field - // should be generated already). - if field.attrs.is_empty() { + if self.should_generate_set_arg(&field) { let diag = &self.diag; let ident = field.ident.as_ref().unwrap(); - quote! { + return quote! { #diag.set_arg( stringify!(#ident), #field_binding ); - } - } else { - field - .attrs - .iter() - .map(move |attr| { - let name = attr.path.segments.last().unwrap().ident.to_string(); - let (binding, needs_destructure) = match (name.as_str(), &inner_ty) { - // `primary_span` can accept a `Vec<Span>` so don't destructure that. - ("primary_span", FieldInnerTy::Vec(_)) => { - (quote! { #field_binding.clone() }, false) - } - // `subdiagnostics` are not derefed because they are bound by value. - ("subdiagnostic", _) => (quote! { #field_binding }, true), - _ => (quote! { *#field_binding }, true), - }; - - let generated_code = self - .generate_inner_field_code( - attr, - FieldInfo { - binding: binding_info, - ty: inner_ty.inner_type().unwrap_or(&field.ty), - span: &field.span(), - }, - binding, - ) - .unwrap_or_else(|v| v.to_compile_error()); - - if needs_destructure { - inner_ty.with(field_binding, generated_code) - } else { - generated_code - } - }) - .collect() + }; } + + let needs_move = self.needs_move(&field); + let inner_ty = FieldInnerTy::from_type(&field.ty); + + field + .attrs + .iter() + .map(move |attr| { + let name = attr.path.segments.last().unwrap().ident.to_string(); + let needs_clone = + name == "primary_span" && matches!(inner_ty, FieldInnerTy::Vec(_)); + let (binding, needs_destructure) = if needs_clone { + // `primary_span` can accept a `Vec<Span>` so don't destructure that. + (quote! { #field_binding.clone() }, false) + } else if needs_move { + (quote! { #field_binding }, true) + } else { + (quote! { *#field_binding }, true) + }; + + let generated_code = self + .generate_inner_field_code( + attr, + FieldInfo { + binding: binding_info, + ty: inner_ty.inner_type().unwrap_or(&field.ty), + span: &field.span(), + }, + binding, + ) + .unwrap_or_else(|v| v.to_compile_error()); + + if needs_destructure { + inner_ty.with(field_binding, generated_code) + } else { + generated_code + } + }) + .collect() } fn generate_inner_field_code( @@ -324,10 +355,12 @@ impl DiagnosticDeriveBuilder { report_error_if_not_applied_to_span(attr, &info)?; Ok(self.add_spanned_subdiagnostic(binding, ident, parse_quote! { _subdiag::label })) } - "note" | "help" => { - let path = match name { - "note" => parse_quote! { _subdiag::note }, - "help" => parse_quote! { _subdiag::help }, + "note" | "help" | "warn_" => { + let warn_ident = Ident::new("warn", Span::call_site()); + let (ident, path) = match name { + "note" => (ident, parse_quote! { _subdiag::note }), + "help" => (ident, parse_quote! { _subdiag::help }), + "warn_" => (&warn_ident, parse_quote! { _subdiag::warn }), _ => unreachable!(), }; if type_matches_path(&info.ty, &["rustc_span", "Span"]) { @@ -364,10 +397,10 @@ impl DiagnosticDeriveBuilder { "suggestion" | "suggestion_short" | "suggestion_hidden" | "suggestion_verbose" => { return self.generate_inner_field_code_suggestion(attr, info); } - "label" | "help" | "note" => (), + "label" | "help" | "note" | "warn_" => (), _ => throw_invalid_attr!(attr, &meta, |diag| { diag.help( - "only `label`, `note`, `help` or `suggestion{,_short,_hidden,_verbose}` are \ + "only `label`, `help`, `note`, `warn` or `suggestion{,_short,_hidden,_verbose}` are \ valid field attributes", ) }), @@ -396,7 +429,14 @@ impl DiagnosticDeriveBuilder { Ok(self.add_spanned_subdiagnostic(binding, ident, msg)) } "note" | "help" if type_is_unit(&info.ty) => Ok(self.add_subdiagnostic(ident, msg)), - "note" | "help" => report_type_error(attr, "`Span` or `()`")?, + // `warn_` must be special-cased because the attribute `warn` already has meaning and + // so isn't used, despite the diagnostic API being named `warn`. + "warn_" if type_matches_path(&info.ty, &["rustc_span", "Span"]) => Ok(self + .add_spanned_subdiagnostic(binding, &Ident::new("warn", Span::call_site()), msg)), + "warn_" if type_is_unit(&info.ty) => { + Ok(self.add_subdiagnostic(&Ident::new("warn", Span::call_site()), msg)) + } + "note" | "help" | "warn_" => report_type_error(attr, "`Span` or `()`")?, _ => unreachable!(), } } diff --git a/compiler/rustc_macros/src/diagnostics/fluent.rs b/compiler/rustc_macros/src/diagnostics/fluent.rs index 2758fcd1310..1170d2b3c59 100644 --- a/compiler/rustc_macros/src/diagnostics/fluent.rs +++ b/compiler/rustc_macros/src/diagnostics/fluent.rs @@ -260,10 +260,12 @@ pub(crate) fn fluent_messages(input: proc_macro::TokenStream) -> proc_macro::Tok #generated pub mod _subdiag { - pub const note: crate::SubdiagnosticMessage = - crate::SubdiagnosticMessage::FluentAttr(std::borrow::Cow::Borrowed("note")); pub const help: crate::SubdiagnosticMessage = crate::SubdiagnosticMessage::FluentAttr(std::borrow::Cow::Borrowed("help")); + pub const note: crate::SubdiagnosticMessage = + crate::SubdiagnosticMessage::FluentAttr(std::borrow::Cow::Borrowed("note")); + pub const warn: crate::SubdiagnosticMessage = + crate::SubdiagnosticMessage::FluentAttr(std::borrow::Cow::Borrowed("warn")); pub const label: crate::SubdiagnosticMessage = crate::SubdiagnosticMessage::FluentAttr(std::borrow::Cow::Borrowed("label")); pub const suggestion: crate::SubdiagnosticMessage = diff --git a/compiler/rustc_macros/src/diagnostics/subdiagnostic.rs b/compiler/rustc_macros/src/diagnostics/subdiagnostic.rs index 2a5b6beba94..edf4dbed985 100644 --- a/compiler/rustc_macros/src/diagnostics/subdiagnostic.rs +++ b/compiler/rustc_macros/src/diagnostics/subdiagnostic.rs @@ -37,6 +37,8 @@ enum SubdiagnosticKind { Note, /// `#[help(...)]` Help, + /// `#[warn_(...)]` + Warn, /// `#[suggestion{,_short,_hidden,_verbose}]` Suggestion(SubdiagnosticSuggestionKind), } @@ -49,6 +51,7 @@ impl FromStr for SubdiagnosticKind { "label" => Ok(SubdiagnosticKind::Label), "note" => Ok(SubdiagnosticKind::Note), "help" => Ok(SubdiagnosticKind::Help), + "warn_" => Ok(SubdiagnosticKind::Warn), "suggestion" => Ok(SubdiagnosticKind::Suggestion(SubdiagnosticSuggestionKind::Normal)), "suggestion_short" => { Ok(SubdiagnosticKind::Suggestion(SubdiagnosticSuggestionKind::Short)) @@ -70,6 +73,7 @@ impl quote::IdentFragment for SubdiagnosticKind { SubdiagnosticKind::Label => write!(f, "label"), SubdiagnosticKind::Note => write!(f, "note"), SubdiagnosticKind::Help => write!(f, "help"), + SubdiagnosticKind::Warn => write!(f, "warn"), SubdiagnosticKind::Suggestion(SubdiagnosticSuggestionKind::Normal) => { write!(f, "suggestion") } diff --git a/compiler/rustc_macros/src/diagnostics/utils.rs b/compiler/rustc_macros/src/diagnostics/utils.rs index 8977db4606c..002abb152f7 100644 --- a/compiler/rustc_macros/src/diagnostics/utils.rs +++ b/compiler/rustc_macros/src/diagnostics/utils.rs @@ -85,7 +85,13 @@ pub(crate) fn report_error_if_not_applied_to_span( attr: &Attribute, info: &FieldInfo<'_>, ) -> Result<(), DiagnosticDeriveError> { - report_error_if_not_applied_to_ty(attr, info, &["rustc_span", "Span"], "`Span`") + if !type_matches_path(&info.ty, &["rustc_span", "Span"]) + && !type_matches_path(&info.ty, &["rustc_errors", "MultiSpan"]) + { + report_type_error(attr, "`Span` or `MultiSpan`")?; + } + + Ok(()) } /// Inner type of a field and type of wrapper. diff --git a/compiler/rustc_macros/src/lib.rs b/compiler/rustc_macros/src/lib.rs index 168530c54b9..ab509b26f1c 100644 --- a/compiler/rustc_macros/src/lib.rs +++ b/compiler/rustc_macros/src/lib.rs @@ -130,8 +130,9 @@ decl_derive!( warning, error, lint, - note, help, + note, + warn_, // field attributes skip_arg, primary_span, @@ -148,8 +149,9 @@ decl_derive!( warning, error, lint, - note, help, + note, + warn_, // field attributes skip_arg, primary_span, @@ -166,6 +168,7 @@ decl_derive!( label, help, note, + warn_, suggestion, suggestion_short, suggestion_hidden, diff --git a/compiler/rustc_middle/src/mir/mod.rs b/compiler/rustc_middle/src/mir/mod.rs index f61cb7e8c47..0b5d23be58d 100644 --- a/compiler/rustc_middle/src/mir/mod.rs +++ b/compiler/rustc_middle/src/mir/mod.rs @@ -1397,6 +1397,7 @@ impl<V, T> ProjectionElem<V, T> { Self::Field(_, _) | Self::Index(_) + | Self::OpaqueCast(_) | Self::ConstantIndex { .. } | Self::Subslice { .. } | Self::Downcast(_, _) => false, @@ -1574,7 +1575,9 @@ impl Debug for Place<'_> { fn fmt(&self, fmt: &mut Formatter<'_>) -> fmt::Result { for elem in self.projection.iter().rev() { match elem { - ProjectionElem::Downcast(_, _) | ProjectionElem::Field(_, _) => { + ProjectionElem::OpaqueCast(_) + | ProjectionElem::Downcast(_, _) + | ProjectionElem::Field(_, _) => { write!(fmt, "(").unwrap(); } ProjectionElem::Deref => { @@ -1590,6 +1593,9 @@ impl Debug for Place<'_> { for elem in self.projection.iter() { match elem { + ProjectionElem::OpaqueCast(ty) => { + write!(fmt, " as {})", ty)?; + } ProjectionElem::Downcast(Some(name), _index) => { write!(fmt, " as {})", name)?; } diff --git a/compiler/rustc_middle/src/mir/syntax.rs b/compiler/rustc_middle/src/mir/syntax.rs index 510316c778b..263c2ca3c70 100644 --- a/compiler/rustc_middle/src/mir/syntax.rs +++ b/compiler/rustc_middle/src/mir/syntax.rs @@ -754,6 +754,9 @@ pub type AssertMessage<'tcx> = AssertKind<Operand<'tcx>>; /// generator has more than one variant, the parent place's variant index must be set, indicating /// which variant is being used. If it has just one variant, the variant index may or may not be /// included - the single possible variant is inferred if it is not included. +/// - [`OpaqueCast`](ProjectionElem::OpaqueCast): This projection changes the place's type to the +/// given one, and makes no other changes. A `OpaqueCast` projection on any type other than an +/// opaque type from the current crate is not well-formed. /// - [`ConstantIndex`](ProjectionElem::ConstantIndex): Computes an offset in units of `T` into the /// place as described in the documentation for the `ProjectionElem`. The resulting address is /// the parent's address plus that offset, and the type is `T`. This is only legal if the parent @@ -856,6 +859,10 @@ pub enum ProjectionElem<V, T> { /// /// The included Symbol is the name of the variant, used for printing MIR. Downcast(Option<Symbol>, VariantIdx), + + /// Like an explicit cast from an opaque type to a concrete type, but without + /// requiring an intermediate variable. + OpaqueCast(T), } /// Alias for projections as they appear in places, where the base is a place diff --git a/compiler/rustc_middle/src/mir/tcx.rs b/compiler/rustc_middle/src/mir/tcx.rs index fd3359ea80f..c6975df45ef 100644 --- a/compiler/rustc_middle/src/mir/tcx.rs +++ b/compiler/rustc_middle/src/mir/tcx.rs @@ -57,7 +57,7 @@ impl<'tcx> PlaceTy<'tcx> { /// `PlaceElem`, where we can just use the `Ty` that is already /// stored inline on field projection elems. pub fn projection_ty(self, tcx: TyCtxt<'tcx>, elem: PlaceElem<'tcx>) -> PlaceTy<'tcx> { - self.projection_ty_core(tcx, ty::ParamEnv::empty(), &elem, |_, _, ty| ty) + self.projection_ty_core(tcx, ty::ParamEnv::empty(), &elem, |_, _, ty| ty, |_, ty| ty) } /// `place_ty.projection_ty_core(tcx, elem, |...| { ... })` @@ -71,6 +71,7 @@ impl<'tcx> PlaceTy<'tcx> { param_env: ty::ParamEnv<'tcx>, elem: &ProjectionElem<V, T>, mut handle_field: impl FnMut(&Self, Field, T) -> Ty<'tcx>, + mut handle_opaque_cast: impl FnMut(&Self, T) -> Ty<'tcx>, ) -> PlaceTy<'tcx> where V: ::std::fmt::Debug, @@ -109,6 +110,7 @@ impl<'tcx> PlaceTy<'tcx> { PlaceTy { ty: self.ty, variant_index: Some(index) } } ProjectionElem::Field(f, fty) => PlaceTy::from_ty(handle_field(&self, f, fty)), + ProjectionElem::OpaqueCast(ty) => PlaceTy::from_ty(handle_opaque_cast(&self, ty)), }; debug!("projection_ty self: {:?} elem: {:?} yields: {:?}", self, elem, answer); answer diff --git a/compiler/rustc_middle/src/mir/type_foldable.rs b/compiler/rustc_middle/src/mir/type_foldable.rs index 82a6b0c506f..a73ef23e281 100644 --- a/compiler/rustc_middle/src/mir/type_foldable.rs +++ b/compiler/rustc_middle/src/mir/type_foldable.rs @@ -182,6 +182,7 @@ impl<'tcx> TypeFoldable<'tcx> for PlaceElem<'tcx> { Ok(match self { Deref => Deref, Field(f, ty) => Field(f, ty.try_fold_with(folder)?), + OpaqueCast(ty) => OpaqueCast(ty.try_fold_with(folder)?), Index(v) => Index(v.try_fold_with(folder)?), Downcast(symbol, variantidx) => Downcast(symbol, variantidx), ConstantIndex { offset, min_length, from_end } => { diff --git a/compiler/rustc_middle/src/mir/visit.rs b/compiler/rustc_middle/src/mir/visit.rs index d285728ec07..e5599fb15ad 100644 --- a/compiler/rustc_middle/src/mir/visit.rs +++ b/compiler/rustc_middle/src/mir/visit.rs @@ -1064,6 +1064,11 @@ macro_rules! visit_place_fns { self.visit_ty(&mut new_ty, TyContext::Location(location)); if ty != new_ty { Some(PlaceElem::Field(field, new_ty)) } else { None } } + PlaceElem::OpaqueCast(ty) => { + let mut new_ty = ty; + self.visit_ty(&mut new_ty, TyContext::Location(location)); + if ty != new_ty { Some(PlaceElem::OpaqueCast(new_ty)) } else { None } + } PlaceElem::Deref | PlaceElem::ConstantIndex { .. } | PlaceElem::Subslice { .. } @@ -1133,7 +1138,7 @@ macro_rules! visit_place_fns { location: Location, ) { match elem { - ProjectionElem::Field(_field, ty) => { + ProjectionElem::OpaqueCast(ty) | ProjectionElem::Field(_, ty) => { self.visit_ty(ty, TyContext::Location(location)); } ProjectionElem::Index(local) => { diff --git a/compiler/rustc_middle/src/traits/mod.rs b/compiler/rustc_middle/src/traits/mod.rs index 945cdfbb0e9..75559d4f8b8 100644 --- a/compiler/rustc_middle/src/traits/mod.rs +++ b/compiler/rustc_middle/src/traits/mod.rs @@ -542,17 +542,9 @@ pub enum SelectionError<'tcx> { ErrorReporting, /// Multiple applicable `impl`s where found. The `DefId`s correspond to /// all the `impl`s' Items. - Ambiguous(Vec<AmbiguousSelection>), + Ambiguous(Vec<DefId>), } -#[derive(Copy, Clone, Debug)] -pub enum AmbiguousSelection { - Impl(DefId), - ParamEnv(Span), -} - -TrivialTypeTraversalAndLiftImpls! { AmbiguousSelection, } - /// When performing resolution, it is typically the case that there /// can be one of three outcomes: /// diff --git a/compiler/rustc_middle/src/ty/layout.rs b/compiler/rustc_middle/src/ty/layout.rs index 71c93d05792..c41a8318ec5 100644 --- a/compiler/rustc_middle/src/ty/layout.rs +++ b/compiler/rustc_middle/src/ty/layout.rs @@ -1975,7 +1975,7 @@ impl<'tcx> LayoutCx<'tcx, TyCtxt<'tcx>> { min_size = field_end; } FieldInfo { - name: name.to_string(), + name, offset: offset.bytes(), size: field_layout.size.bytes(), align: field_layout.align.abi.bytes(), @@ -1984,7 +1984,7 @@ impl<'tcx> LayoutCx<'tcx, TyCtxt<'tcx>> { .collect(); VariantInfo { - name: n.map(|n| n.to_string()), + name: n, kind: if layout.is_unsized() { SizeKind::Min } else { SizeKind::Exact }, align: layout.align.abi.bytes(), size: if min_size.bytes() == 0 { layout.size.bytes() } else { min_size.bytes() }, diff --git a/compiler/rustc_middle/src/ty/print/pretty.rs b/compiler/rustc_middle/src/ty/print/pretty.rs index 81c4d2ae346..96e84bc8f0a 100644 --- a/compiler/rustc_middle/src/ty/print/pretty.rs +++ b/compiler/rustc_middle/src/ty/print/pretty.rs @@ -1030,11 +1030,11 @@ pub trait PrettyPrinter<'tcx>: } } - fn ty_infer_name(&self, _: ty::TyVid) -> Option<String> { + fn ty_infer_name(&self, _: ty::TyVid) -> Option<Symbol> { None } - fn const_infer_name(&self, _: ty::ConstVid<'tcx>) -> Option<String> { + fn const_infer_name(&self, _: ty::ConstVid<'tcx>) -> Option<Symbol> { None } @@ -1550,8 +1550,8 @@ pub struct FmtPrinterData<'a, 'tcx> { pub region_highlight_mode: RegionHighlightMode<'tcx>, - pub ty_infer_name_resolver: Option<Box<dyn Fn(ty::TyVid) -> Option<String> + 'a>>, - pub const_infer_name_resolver: Option<Box<dyn Fn(ty::ConstVid<'tcx>) -> Option<String> + 'a>>, + pub ty_infer_name_resolver: Option<Box<dyn Fn(ty::TyVid) -> Option<Symbol> + 'a>>, + pub const_infer_name_resolver: Option<Box<dyn Fn(ty::ConstVid<'tcx>) -> Option<Symbol> + 'a>>, } impl<'a, 'tcx> Deref for FmtPrinter<'a, 'tcx> { @@ -1841,11 +1841,11 @@ impl<'tcx> Printer<'tcx> for FmtPrinter<'_, 'tcx> { } impl<'tcx> PrettyPrinter<'tcx> for FmtPrinter<'_, 'tcx> { - fn ty_infer_name(&self, id: ty::TyVid) -> Option<String> { + fn ty_infer_name(&self, id: ty::TyVid) -> Option<Symbol> { self.0.ty_infer_name_resolver.as_ref().and_then(|func| func(id)) } - fn const_infer_name(&self, id: ty::ConstVid<'tcx>) -> Option<String> { + fn const_infer_name(&self, id: ty::ConstVid<'tcx>) -> Option<Symbol> { self.0.const_infer_name_resolver.as_ref().and_then(|func| func(id)) } diff --git a/compiler/rustc_mir_build/src/build/expr/as_place.rs b/compiler/rustc_mir_build/src/build/expr/as_place.rs index e88f9dc1f08..6abf419dd49 100644 --- a/compiler/rustc_mir_build/src/build/expr/as_place.rs +++ b/compiler/rustc_mir_build/src/build/expr/as_place.rs @@ -7,6 +7,7 @@ use rustc_hir::def_id::{DefId, LocalDefId}; use rustc_middle::hir::place::Projection as HirProjection; use rustc_middle::hir::place::ProjectionKind as HirProjectionKind; use rustc_middle::middle::region; +use rustc_middle::mir::tcx::PlaceTy; use rustc_middle::mir::AssertKind::BoundsCheck; use rustc_middle::mir::*; use rustc_middle::thir::*; @@ -71,7 +72,7 @@ pub(crate) enum PlaceBase { /// This is used internally when building a place for an expression like `a.b.c`. The fields `b` /// and `c` can be progressively pushed onto the place builder that is created when converting `a`. #[derive(Clone, Debug, PartialEq)] -pub(crate) struct PlaceBuilder<'tcx> { +pub(in crate::build) struct PlaceBuilder<'tcx> { base: PlaceBase, projection: Vec<PlaceElem<'tcx>>, } @@ -104,6 +105,8 @@ fn convert_to_hir_projections_and_truncate_for_capture<'tcx>( variant = Some(*idx); continue; } + // These do not affect anything, they just make sure we know the right type. + ProjectionElem::OpaqueCast(_) => continue, ProjectionElem::Index(..) | ProjectionElem::ConstantIndex { .. } | ProjectionElem::Subslice { .. } => { @@ -201,10 +204,10 @@ fn find_capture_matching_projections<'a, 'tcx>( /// `PlaceBuilder` now starts from `PlaceBase::Local`. /// /// Returns a Result with the error being the PlaceBuilder (`from_builder`) that was not found. -fn to_upvars_resolved_place_builder<'a, 'tcx>( +#[instrument(level = "trace", skip(cx))] +fn to_upvars_resolved_place_builder<'tcx>( from_builder: PlaceBuilder<'tcx>, - tcx: TyCtxt<'tcx>, - typeck_results: &'a ty::TypeckResults<'tcx>, + cx: &Builder<'_, 'tcx>, ) -> Result<PlaceBuilder<'tcx>, PlaceBuilder<'tcx>> { match from_builder.base { PlaceBase::Local(_) => Ok(from_builder), @@ -219,13 +222,13 @@ fn to_upvars_resolved_place_builder<'a, 'tcx>( let Some((capture_index, capture)) = find_capture_matching_projections( - typeck_results, + cx.typeck_results, var_hir_id, closure_def_id, &from_builder.projection, ) else { - let closure_span = tcx.def_span(closure_def_id); - if !enable_precise_capture(tcx, closure_span) { + let closure_span = cx.tcx.def_span(closure_def_id); + if !enable_precise_capture(cx.tcx, closure_span) { bug!( "No associated capture found for {:?}[{:#?}] even though \ capture_disjoint_fields isn't enabled", @@ -242,8 +245,8 @@ fn to_upvars_resolved_place_builder<'a, 'tcx>( }; // We won't be building MIR if the closure wasn't local - let closure_hir_id = tcx.hir().local_def_id_to_hir_id(closure_def_id.expect_local()); - let closure_ty = typeck_results.node_type(closure_hir_id); + let closure_hir_id = cx.tcx.hir().local_def_id_to_hir_id(closure_def_id.expect_local()); + let closure_ty = cx.typeck_results.node_type(closure_hir_id); let substs = match closure_ty.kind() { ty::Closure(_, substs) => ty::UpvarSubsts::Closure(substs), @@ -270,12 +273,14 @@ fn to_upvars_resolved_place_builder<'a, 'tcx>( // We used some of the projections to build the capture itself, // now we apply the remaining to the upvar resolved place. + trace!(?capture.place, ?from_builder.projection); let remaining_projections = strip_prefix( capture.place.base_ty, from_builder.projection, &capture.place.projections, ); upvar_resolved_place_builder.projection.extend(remaining_projections); + trace!(?upvar_resolved_place_builder); Ok(upvar_resolved_place_builder) } @@ -294,16 +299,21 @@ fn strip_prefix<'tcx>( prefix_projections: &[HirProjection<'tcx>], ) -> impl Iterator<Item = PlaceElem<'tcx>> { let mut iter = projections.into_iter(); + let mut next = || match iter.next()? { + // Filter out opaque casts, they are unnecessary in the prefix. + ProjectionElem::OpaqueCast(..) => iter.next(), + other => Some(other), + }; for projection in prefix_projections { match projection.kind { HirProjectionKind::Deref => { - assert!(matches!(iter.next(), Some(ProjectionElem::Deref))); + assert!(matches!(next(), Some(ProjectionElem::Deref))); } HirProjectionKind::Field(..) => { if base_ty.is_enum() { - assert!(matches!(iter.next(), Some(ProjectionElem::Downcast(..)))); + assert!(matches!(next(), Some(ProjectionElem::Downcast(..)))); } - assert!(matches!(iter.next(), Some(ProjectionElem::Field(..)))); + assert!(matches!(next(), Some(ProjectionElem::Field(..)))); } HirProjectionKind::Index | HirProjectionKind::Subslice => { bug!("unexpected projection kind: {:?}", projection); @@ -315,24 +325,32 @@ fn strip_prefix<'tcx>( } impl<'tcx> PlaceBuilder<'tcx> { - pub(crate) fn into_place<'a>( - self, - tcx: TyCtxt<'tcx>, - typeck_results: &'a ty::TypeckResults<'tcx>, - ) -> Place<'tcx> { + pub(crate) fn into_place(self, cx: &Builder<'_, 'tcx>) -> Place<'tcx> { if let PlaceBase::Local(local) = self.base { - Place { local, projection: tcx.intern_place_elems(&self.projection) } + let mut projections = vec![]; + let mut ty = PlaceTy::from_ty(cx.local_decls[local].ty); + for projection in self.projection { + // Only preserve those opaque casts that actually go from an opaque type + // to another type. + if let ProjectionElem::OpaqueCast(t) = projection { + if let ty::Opaque(..) = ty.ty.kind() { + if t != ty.ty { + projections.push(ProjectionElem::OpaqueCast(t)); + } + } + } else { + projections.push(projection); + } + ty = ty.projection_ty(cx.tcx, projection); + } + Place { local, projection: cx.tcx.intern_place_elems(&projections) } } else { - self.expect_upvars_resolved(tcx, typeck_results).into_place(tcx, typeck_results) + self.expect_upvars_resolved(cx).into_place(cx) } } - fn expect_upvars_resolved<'a>( - self, - tcx: TyCtxt<'tcx>, - typeck_results: &'a ty::TypeckResults<'tcx>, - ) -> PlaceBuilder<'tcx> { - to_upvars_resolved_place_builder(self, tcx, typeck_results).unwrap() + fn expect_upvars_resolved(self, cx: &Builder<'_, 'tcx>) -> PlaceBuilder<'tcx> { + to_upvars_resolved_place_builder(self, cx).unwrap() } /// Attempts to resolve the `PlaceBuilder`. @@ -346,12 +364,11 @@ impl<'tcx> PlaceBuilder<'tcx> { /// not captured. This can happen because the final mir that will be /// generated doesn't require a read for this place. Failures will only /// happen inside closures. - pub(crate) fn try_upvars_resolved<'a>( + pub(crate) fn try_upvars_resolved( self, - tcx: TyCtxt<'tcx>, - typeck_results: &'a ty::TypeckResults<'tcx>, + cx: &Builder<'_, 'tcx>, ) -> Result<PlaceBuilder<'tcx>, PlaceBuilder<'tcx>> { - to_upvars_resolved_place_builder(self, tcx, typeck_results) + to_upvars_resolved_place_builder(self, cx) } pub(crate) fn base(&self) -> PlaceBase { @@ -411,7 +428,7 @@ impl<'a, 'tcx> Builder<'a, 'tcx> { expr: &Expr<'tcx>, ) -> BlockAnd<Place<'tcx>> { let place_builder = unpack!(block = self.as_place_builder(block, expr)); - block.and(place_builder.into_place(self.tcx, self.typeck_results)) + block.and(place_builder.into_place(self)) } /// This is used when constructing a compound `Place`, so that we can avoid creating @@ -435,7 +452,7 @@ impl<'a, 'tcx> Builder<'a, 'tcx> { expr: &Expr<'tcx>, ) -> BlockAnd<Place<'tcx>> { let place_builder = unpack!(block = self.as_read_only_place_builder(block, expr)); - block.and(place_builder.into_place(self.tcx, self.typeck_results)) + block.and(place_builder.into_place(self)) } /// This is used when constructing a compound `Place`, so that we can avoid creating @@ -530,7 +547,7 @@ impl<'a, 'tcx> Builder<'a, 'tcx> { inferred_ty: expr.ty, }); - let place = place_builder.clone().into_place(this.tcx, this.typeck_results); + let place = place_builder.clone().into_place(this); this.cfg.push( block, Statement { @@ -682,7 +699,7 @@ impl<'a, 'tcx> Builder<'a, 'tcx> { if is_outermost_index { self.read_fake_borrows(block, fake_borrow_temps, source_info) } else { - base_place = base_place.expect_upvars_resolved(self.tcx, self.typeck_results); + base_place = base_place.expect_upvars_resolved(self); self.add_fake_borrows_of_base( &base_place, block, @@ -710,12 +727,7 @@ impl<'a, 'tcx> Builder<'a, 'tcx> { let lt = self.temp(bool_ty, expr_span); // len = len(slice) - self.cfg.push_assign( - block, - source_info, - len, - Rvalue::Len(slice.into_place(self.tcx, self.typeck_results)), - ); + self.cfg.push_assign(block, source_info, len, Rvalue::Len(slice.into_place(self))); // lt = idx < len self.cfg.push_assign( block, @@ -795,6 +807,7 @@ impl<'a, 'tcx> Builder<'a, 'tcx> { } ProjectionElem::Field(..) | ProjectionElem::Downcast(..) + | ProjectionElem::OpaqueCast(..) | ProjectionElem::ConstantIndex { .. } | ProjectionElem::Subslice { .. } => (), } 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 15f2d17c4e0..93f76333165 100644 --- a/compiler/rustc_mir_build/src/build/expr/as_rvalue.rs +++ b/compiler/rustc_mir_build/src/build/expr/as_rvalue.rs @@ -321,11 +321,8 @@ impl<'a, 'tcx> Builder<'a, 'tcx> { let place_builder = unpack!(block = this.as_place_builder(block, &this.thir[*thir_place])); - if let Ok(place_builder_resolved) = - place_builder.try_upvars_resolved(this.tcx, this.typeck_results) - { - let mir_place = - place_builder_resolved.into_place(this.tcx, this.typeck_results); + if let Ok(place_builder_resolved) = place_builder.try_upvars_resolved(this) { + let mir_place = place_builder_resolved.into_place(this); this.cfg.push_fake_read( block, this.source_info(this.tcx.hir().span(*hir_id)), @@ -616,8 +613,7 @@ impl<'a, 'tcx> Builder<'a, 'tcx> { // by the parent itself. The mutability of the current capture // is same as that of the capture in the parent closure. PlaceBase::Upvar { .. } => { - let enclosing_upvars_resolved = - arg_place_builder.clone().into_place(this.tcx, this.typeck_results); + let enclosing_upvars_resolved = arg_place_builder.clone().into_place(this); match enclosing_upvars_resolved.as_ref() { PlaceRef { @@ -654,7 +650,7 @@ impl<'a, 'tcx> Builder<'a, 'tcx> { Mutability::Mut => BorrowKind::Mut { allow_two_phase_borrow: false }, }; - let arg_place = arg_place_builder.into_place(this.tcx, this.typeck_results); + let arg_place = arg_place_builder.into_place(this); this.cfg.push_assign( block, 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 724b72f8769..dac8862647a 100644 --- a/compiler/rustc_mir_build/src/build/expr/as_temp.rs +++ b/compiler/rustc_mir_build/src/build/expr/as_temp.rs @@ -23,6 +23,7 @@ impl<'a, 'tcx> Builder<'a, 'tcx> { ensure_sufficient_stack(|| self.as_temp_inner(block, temp_lifetime, expr, mutability)) } + #[instrument(skip(self), level = "debug")] fn as_temp_inner( &mut self, mut block: BasicBlock, @@ -30,10 +31,6 @@ impl<'a, 'tcx> Builder<'a, 'tcx> { expr: &Expr<'tcx>, mutability: Mutability, ) -> BlockAnd<Local> { - debug!( - "as_temp(block={:?}, temp_lifetime={:?}, expr={:?}, mutability={:?})", - block, temp_lifetime, expr, mutability - ); let this = self; let expr_span = expr.span; diff --git a/compiler/rustc_mir_build/src/build/expr/into.rs b/compiler/rustc_mir_build/src/build/expr/into.rs index 017d43d10a9..d1ef515b3d2 100644 --- a/compiler/rustc_mir_build/src/build/expr/into.rs +++ b/compiler/rustc_mir_build/src/build/expr/into.rs @@ -15,14 +15,13 @@ use std::iter; impl<'a, 'tcx> Builder<'a, 'tcx> { /// Compile `expr`, storing the result into `destination`, which /// is assumed to be uninitialized. + #[instrument(level = "debug", skip(self))] pub(crate) fn expr_into_dest( &mut self, destination: Place<'tcx>, mut block: BasicBlock, expr: &Expr<'tcx>, ) -> BlockAnd<()> { - debug!("expr_into_dest(destination={:?}, block={:?}, expr={:?})", destination, block, expr); - // since we frequently have to reference `self` from within a // closure, where `self` would be shadowed, it's easier to // just use the name `this` uniformly @@ -366,9 +365,7 @@ impl<'a, 'tcx> Builder<'a, 'tcx> { None => { let place_builder = place_builder.clone(); this.consume_by_copy_or_move( - place_builder - .field(n, *ty) - .into_place(this.tcx, this.typeck_results), + place_builder.field(n, *ty).into_place(this), ) } }) diff --git a/compiler/rustc_mir_build/src/build/matches/mod.rs b/compiler/rustc_mir_build/src/build/matches/mod.rs index 7067a48b783..86ef666eac8 100644 --- a/compiler/rustc_mir_build/src/build/matches/mod.rs +++ b/compiler/rustc_mir_build/src/build/matches/mod.rs @@ -220,10 +220,8 @@ impl<'a, 'tcx> Builder<'a, 'tcx> { let cause_matched_place = FakeReadCause::ForMatchedPlace(None); let source_info = self.source_info(scrutinee_span); - if let Ok(scrutinee_builder) = - scrutinee_place_builder.clone().try_upvars_resolved(self.tcx, self.typeck_results) - { - let scrutinee_place = scrutinee_builder.into_place(self.tcx, self.typeck_results); + if let Ok(scrutinee_builder) = scrutinee_place_builder.clone().try_upvars_resolved(self) { + let scrutinee_place = scrutinee_builder.into_place(self); self.cfg.push_fake_read(block, source_info, cause_matched_place, scrutinee_place); } @@ -348,12 +346,10 @@ impl<'a, 'tcx> Builder<'a, 'tcx> { // ``` let mut opt_scrutinee_place: Option<(Option<&Place<'tcx>>, Span)> = None; let scrutinee_place: Place<'tcx>; - if let Ok(scrutinee_builder) = scrutinee_place_builder - .clone() - .try_upvars_resolved(this.tcx, this.typeck_results) + if let Ok(scrutinee_builder) = + scrutinee_place_builder.clone().try_upvars_resolved(this) { - scrutinee_place = - scrutinee_builder.into_place(this.tcx, this.typeck_results); + scrutinee_place = scrutinee_builder.into_place(this); opt_scrutinee_place = Some((Some(&scrutinee_place), scrutinee_span)); } let scope = this.declare_bindings( @@ -602,12 +598,6 @@ impl<'a, 'tcx> Builder<'a, 'tcx> { while let Some(next) = { for binding in &candidate_ref.bindings { let local = self.var_local_id(binding.var_id, OutsideGuard); - - let Some(box LocalInfo::User(ClearCrossCrate::Set(BindingForm::Var( - VarBindingForm { opt_match_place: Some((ref mut match_place, _)), .. }, - )))) = self.local_decls[local].local_info else { - bug!("Let binding to non-user variable.") - }; // `try_upvars_resolved` may fail if it is unable to resolve the given // `PlaceBuilder` inside a closure. In this case, we don't want to include // a scrutinee place. `scrutinee_place_builder` will fail for destructured @@ -622,10 +612,15 @@ impl<'a, 'tcx> Builder<'a, 'tcx> { // let (v1, v2) = foo; // }; // ``` - if let Ok(match_pair_resolved) = - initializer.clone().try_upvars_resolved(self.tcx, self.typeck_results) - { - let place = match_pair_resolved.into_place(self.tcx, self.typeck_results); + if let Ok(match_pair_resolved) = initializer.clone().try_upvars_resolved(self) { + let place = match_pair_resolved.into_place(self); + + let Some(box LocalInfo::User(ClearCrossCrate::Set(BindingForm::Var( + VarBindingForm { opt_match_place: Some((ref mut match_place, _)), .. }, + )))) = self.local_decls[local].local_info else { + bug!("Let binding to non-user variable.") + }; + *match_place = Some(place); } } @@ -654,6 +649,7 @@ impl<'a, 'tcx> Builder<'a, 'tcx> { /// scope for the bindings in these patterns, if such a scope had to be /// created. NOTE: Declaring the bindings should always be done in their /// drop scope. + #[instrument(skip(self), level = "debug")] pub(crate) fn declare_bindings( &mut self, mut visibility_scope: Option<SourceScope>, @@ -662,7 +658,6 @@ impl<'a, 'tcx> Builder<'a, 'tcx> { has_guard: ArmHasGuard, opt_match_place: Option<(Option<&Place<'tcx>>, Span)>, ) -> Option<SourceScope> { - debug!("declare_bindings: pattern={:?}", pattern); self.visit_primary_bindings( &pattern, UserTypeProjections::none(), @@ -872,7 +867,7 @@ impl<'tcx, 'pat> Candidate<'pat, 'tcx> { Candidate { span: pattern.span, has_guard, - match_pairs: smallvec![MatchPair { place, pattern }], + match_pairs: smallvec![MatchPair::new(place, pattern)], bindings: Vec::new(), ascriptions: Vec::new(), subcandidates: Vec::new(), @@ -1048,6 +1043,7 @@ impl<'a, 'tcx> Builder<'a, 'tcx> { /// if `x.0` matches `false` (for the third arm). In the (impossible at /// runtime) case when `x.0` is now `true`, we branch to /// `otherwise_block`. + #[instrument(skip(self, fake_borrows), level = "debug")] fn match_candidates<'pat>( &mut self, span: Span, @@ -1057,11 +1053,6 @@ impl<'a, 'tcx> Builder<'a, 'tcx> { candidates: &mut [&mut Candidate<'pat, 'tcx>], fake_borrows: &mut Option<FxIndexSet<Place<'tcx>>>, ) { - debug!( - "matched_candidate(span={:?}, candidates={:?}, start_block={:?}, otherwise_block={:?})", - span, candidates, start_block, otherwise_block, - ); - // Start by simplifying candidates. Once this process is complete, all // the match pairs which remain require some form of test, whether it // be a switch or pattern comparison. @@ -1380,6 +1371,10 @@ impl<'a, 'tcx> Builder<'a, 'tcx> { ) } + #[instrument( + skip(self, otherwise, or_span, place, fake_borrows, candidate, pats), + level = "debug" + )] fn test_or_pattern<'pat>( &mut self, candidate: &mut Candidate<'pat, 'tcx>, @@ -1389,7 +1384,7 @@ impl<'a, 'tcx> Builder<'a, 'tcx> { place: PlaceBuilder<'tcx>, fake_borrows: &mut Option<FxIndexSet<Place<'tcx>>>, ) { - debug!("test_or_pattern:\ncandidate={:#?}\npats={:#?}", candidate, pats); + debug!("candidate={:#?}\npats={:#?}", candidate, pats); let mut or_candidates: Vec<_> = pats .iter() .map(|pat| Candidate::new(place.clone(), pat, candidate.has_guard)) @@ -1605,9 +1600,9 @@ impl<'a, 'tcx> Builder<'a, 'tcx> { // Insert a Shallow borrow of any places that is switched on. if let Some(fb) = fake_borrows && let Ok(match_place_resolved) = - match_place.clone().try_upvars_resolved(self.tcx, self.typeck_results) + match_place.clone().try_upvars_resolved(self) { - let resolved_place = match_place_resolved.into_place(self.tcx, self.typeck_results); + let resolved_place = match_place_resolved.into_place(self); fb.insert(resolved_place); } @@ -1634,9 +1629,14 @@ impl<'a, 'tcx> Builder<'a, 'tcx> { candidates = rest; } // at least the first candidate ought to be tested - assert!(total_candidate_count > candidates.len()); - debug!("test_candidates: tested_candidates: {}", total_candidate_count - candidates.len()); - debug!("test_candidates: untested_candidates: {}", candidates.len()); + assert!( + total_candidate_count > candidates.len(), + "{}, {:#?}", + total_candidate_count, + candidates + ); + debug!("tested_candidates: {}", total_candidate_count - candidates.len()); + debug!("untested_candidates: {}", candidates.len()); // HACK(matthewjasper) This is a closure so that we can let the test // create its blocks before the rest of the match. This currently @@ -1794,10 +1794,8 @@ impl<'a, 'tcx> Builder<'a, 'tcx> { ); let mut opt_expr_place: Option<(Option<&Place<'tcx>>, Span)> = None; let expr_place: Place<'tcx>; - if let Ok(expr_builder) = - expr_place_builder.try_upvars_resolved(self.tcx, self.typeck_results) - { - expr_place = expr_builder.into_place(self.tcx, self.typeck_results); + if let Ok(expr_builder) = expr_place_builder.try_upvars_resolved(self) { + expr_place = expr_builder.into_place(self); opt_expr_place = Some((Some(&expr_place), expr_span)); } let otherwise_post_guard_block = otherwise_candidate.pre_binding_block.unwrap(); @@ -2195,6 +2193,7 @@ impl<'a, 'tcx> Builder<'a, 'tcx> { /// first local is a binding for occurrences of `var` in the guard, which /// will have type `&T`. The second local is a binding for occurrences of /// `var` in the arm body, which will have type `T`. + #[instrument(skip(self), level = "debug")] fn declare_binding( &mut self, source_info: SourceInfo, @@ -2209,19 +2208,12 @@ impl<'a, 'tcx> Builder<'a, 'tcx> { opt_match_place: Option<(Option<Place<'tcx>>, Span)>, pat_span: Span, ) { - debug!( - "declare_binding(var_id={:?}, name={:?}, mode={:?}, var_ty={:?}, \ - visibility_scope={:?}, source_info={:?})", - var_id, name, mode, var_ty, visibility_scope, source_info - ); - let tcx = self.tcx; let debug_source_info = SourceInfo { span: source_info.span, scope: visibility_scope }; let binding_mode = match mode { BindingMode::ByValue => ty::BindingMode::BindByValue(mutability), BindingMode::ByRef(_) => ty::BindingMode::BindByReference(mutability), }; - debug!("declare_binding: user_ty={:?}", user_ty); let local = LocalDecl::<'tcx> { mutability, ty: var_ty, @@ -2271,7 +2263,7 @@ impl<'a, 'tcx> Builder<'a, 'tcx> { } else { LocalsForNode::One(for_arm_body) }; - debug!("declare_binding: vars={:?}", locals); + debug!(?locals); self.var_indices.insert(var_id, locals); } diff --git a/compiler/rustc_mir_build/src/build/matches/simplify.rs b/compiler/rustc_mir_build/src/build/matches/simplify.rs index c6298904140..6fa817da28a 100644 --- a/compiler/rustc_mir_build/src/build/matches/simplify.rs +++ b/compiler/rustc_mir_build/src/build/matches/simplify.rs @@ -37,12 +37,13 @@ impl<'a, 'tcx> Builder<'a, 'tcx> { /// /// only generates a single switch. If this happens this method returns /// `true`. + #[instrument(skip(self, candidate), level = "debug")] pub(super) fn simplify_candidate<'pat>( &mut self, candidate: &mut Candidate<'pat, 'tcx>, ) -> bool { // repeatedly simplify match pairs until fixed point is reached - debug!(?candidate, "simplify_candidate"); + debug!("{:#?}", candidate); // existing_bindings and new_bindings exists to keep the semantics in order. // Reversing the binding order for bindings after `@` changes the binding order in places @@ -155,12 +156,10 @@ impl<'a, 'tcx> Builder<'a, 'tcx> { ascription: thir::Ascription { ref annotation, variance }, } => { // Apply the type ascription to the value at `match_pair.place`, which is the - if let Ok(place_resolved) = - match_pair.place.clone().try_upvars_resolved(self.tcx, self.typeck_results) - { + if let Ok(place_resolved) = match_pair.place.clone().try_upvars_resolved(self) { candidate.ascriptions.push(Ascription { annotation: annotation.clone(), - source: place_resolved.into_place(self.tcx, self.typeck_results), + source: place_resolved.into_place(self), variance, }); } @@ -184,12 +183,10 @@ impl<'a, 'tcx> Builder<'a, 'tcx> { ref subpattern, is_primary: _, } => { - if let Ok(place_resolved) = - match_pair.place.clone().try_upvars_resolved(self.tcx, self.typeck_results) - { + if let Ok(place_resolved) = match_pair.place.clone().try_upvars_resolved(self) { candidate.bindings.push(Binding { span: match_pair.pattern.span, - source: place_resolved.into_place(self.tcx, self.typeck_results), + source: place_resolved.into_place(self), var_id: var, binding_mode: mode, }); diff --git a/compiler/rustc_mir_build/src/build/matches/test.rs b/compiler/rustc_mir_build/src/build/matches/test.rs index 598da80c574..63acd731db7 100644 --- a/compiler/rustc_mir_build/src/build/matches/test.rs +++ b/compiler/rustc_mir_build/src/build/matches/test.rs @@ -144,6 +144,7 @@ impl<'a, 'tcx> Builder<'a, 'tcx> { } } + #[instrument(skip(self, make_target_blocks, place_builder), level = "debug")] pub(super) fn perform_test( &mut self, match_start_span: Span, @@ -153,21 +154,9 @@ impl<'a, 'tcx> Builder<'a, 'tcx> { test: &Test<'tcx>, make_target_blocks: impl FnOnce(&mut Self) -> Vec<BasicBlock>, ) { - let place: Place<'tcx>; - if let Ok(test_place_builder) = - place_builder.try_upvars_resolved(self.tcx, self.typeck_results) - { - place = test_place_builder.into_place(self.tcx, self.typeck_results); - } else { - return; - } - debug!( - "perform_test({:?}, {:?}: {:?}, {:?})", - block, - place, - place.ty(&self.local_decls, self.tcx), - test - ); + let place = place_builder.into_place(self); + let place_ty = place.ty(&self.local_decls, self.tcx); + debug!(?place, ?place_ty,); let source_info = self.source_info(test.span); match test.kind { @@ -735,9 +724,7 @@ impl<'a, 'tcx> Builder<'a, 'tcx> { // So, if we have a match-pattern like `x @ Enum::Variant(P1, P2)`, // we want to create a set of derived match-patterns like // `(x as Variant).0 @ P1` and `(x as Variant).1 @ P1`. - let elem = - ProjectionElem::Downcast(Some(adt_def.variant(variant_index).name), variant_index); - let downcast_place = match_pair.place.project(elem); // `(x as Variant)` + let downcast_place = match_pair.place.downcast(adt_def, variant_index); // `(x as Variant)` let consequent_match_pairs = subpatterns.iter().map(|subpattern| { // e.g., `(x as Variant).0` let place = downcast_place.clone().field(subpattern.field, subpattern.pattern.ty); diff --git a/compiler/rustc_mir_build/src/build/matches/util.rs b/compiler/rustc_mir_build/src/build/matches/util.rs index 9a1e98d3bb1..4a7edc517f4 100644 --- a/compiler/rustc_mir_build/src/build/matches/util.rs +++ b/compiler/rustc_mir_build/src/build/matches/util.rs @@ -31,21 +31,15 @@ impl<'a, 'tcx> Builder<'a, 'tcx> { suffix: &'pat [Pat<'tcx>], ) { let tcx = self.tcx; - let (min_length, exact_size) = if let Ok(place_resolved) = - place.clone().try_upvars_resolved(tcx, self.typeck_results) - { - match place_resolved - .into_place(tcx, self.typeck_results) - .ty(&self.local_decls, tcx) - .ty - .kind() - { - ty::Array(_, length) => (length.eval_usize(tcx, self.param_env), true), - _ => ((prefix.len() + suffix.len()).try_into().unwrap(), false), - } - } else { - ((prefix.len() + suffix.len()).try_into().unwrap(), false) - }; + let (min_length, exact_size) = + if let Ok(place_resolved) = place.clone().try_upvars_resolved(self) { + match place_resolved.into_place(self).ty(&self.local_decls, tcx).ty.kind() { + ty::Array(_, length) => (length.eval_usize(tcx, self.param_env), true), + _ => ((prefix.len() + suffix.len()).try_into().unwrap(), false), + } + } else { + ((prefix.len() + suffix.len()).try_into().unwrap(), false) + }; match_pairs.extend(prefix.iter().enumerate().map(|(idx, subpattern)| { let elem = @@ -100,10 +94,14 @@ impl<'a, 'tcx> Builder<'a, 'tcx> { } impl<'pat, 'tcx> MatchPair<'pat, 'tcx> { - pub(crate) fn new( + pub(in crate::build) fn new( place: PlaceBuilder<'tcx>, pattern: &'pat Pat<'tcx>, ) -> MatchPair<'pat, 'tcx> { + // Force the place type to the pattern's type. + // FIXME(oli-obk): only do this when we don't already know the place type. + // FIXME(oli-obk): can we use this to simplify slice/array pattern hacks? + let place = place.project(ProjectionElem::OpaqueCast(pattern.ty)); MatchPair { place, pattern } } } diff --git a/compiler/rustc_mir_build/src/build/scope.rs b/compiler/rustc_mir_build/src/build/scope.rs index b9fd8c50e6a..ab37c480285 100644 --- a/compiler/rustc_mir_build/src/build/scope.rs +++ b/compiler/rustc_mir_build/src/build/scope.rs @@ -553,6 +553,7 @@ impl<'a, 'tcx> Builder<'a, 'tcx> { /// Convenience wrapper that pushes a scope and then executes `f` /// to build its contents, popping the scope afterwards. + #[instrument(skip(self, f), level = "debug")] pub(crate) fn in_scope<F, R>( &mut self, region_scope: (region::Scope, SourceInfo), @@ -562,7 +563,6 @@ impl<'a, 'tcx> Builder<'a, 'tcx> { where F: FnOnce(&mut Builder<'a, 'tcx>) -> BlockAnd<R>, { - debug!("in_scope(region_scope={:?})", region_scope); let source_scope = self.source_scope; let tcx = self.tcx; if let LintLevel::Explicit(current_hir_id) = lint_level { @@ -589,7 +589,7 @@ impl<'a, 'tcx> Builder<'a, 'tcx> { let rv = unpack!(block = f(self)); unpack!(block = self.pop_scope(region_scope, block)); self.source_scope = source_scope; - debug!("in_scope: exiting region_scope={:?} block={:?}", region_scope, block); + debug!(?block); block.and(rv) } diff --git a/compiler/rustc_mir_build/src/thir/cx/expr.rs b/compiler/rustc_mir_build/src/thir/cx/expr.rs index 4eb3607e9cc..05da33caa91 100644 --- a/compiler/rustc_mir_build/src/thir/cx/expr.rs +++ b/compiler/rustc_mir_build/src/thir/cx/expr.rs @@ -48,6 +48,8 @@ impl<'tcx> Cx<'tcx> { _ => None, }; + trace!(?expr.ty); + // Now apply adjustments, if any. for adjustment in self.typeck_results.expr_adjustments(hir_expr) { trace!(?expr, ?adjustment); @@ -56,6 +58,8 @@ impl<'tcx> Cx<'tcx> { self.apply_adjustment(hir_expr, expr, adjustment, adjustment_span.unwrap_or(span)); } + trace!(?expr.ty, "after adjustments"); + // Next, wrap this up in the expr's scope. expr = Expr { temp_lifetime, diff --git a/compiler/rustc_mir_build/src/thir/pattern/deconstruct_pat.rs b/compiler/rustc_mir_build/src/thir/pattern/deconstruct_pat.rs index 60db98073a3..c0fd19cf71c 100644 --- a/compiler/rustc_mir_build/src/thir/pattern/deconstruct_pat.rs +++ b/compiler/rustc_mir_build/src/thir/pattern/deconstruct_pat.rs @@ -1202,35 +1202,32 @@ impl<'p, 'tcx> Fields<'p, 'tcx> { /// Creates a new list of wildcard fields for a given constructor. The result must have a /// length of `constructor.arity()`. - pub(super) fn wildcards( - cx: &MatchCheckCtxt<'p, 'tcx>, - ty: Ty<'tcx>, - constructor: &Constructor<'tcx>, - ) -> Self { + #[instrument(level = "trace")] + pub(super) fn wildcards(pcx: PatCtxt<'_, 'p, 'tcx>, constructor: &Constructor<'tcx>) -> Self { let ret = match constructor { - Single | Variant(_) => match ty.kind() { - ty::Tuple(fs) => Fields::wildcards_from_tys(cx, fs.iter()), - ty::Ref(_, rty, _) => Fields::wildcards_from_tys(cx, once(*rty)), + Single | Variant(_) => match pcx.ty.kind() { + ty::Tuple(fs) => Fields::wildcards_from_tys(pcx.cx, fs.iter()), + ty::Ref(_, rty, _) => Fields::wildcards_from_tys(pcx.cx, once(*rty)), ty::Adt(adt, substs) => { if adt.is_box() { // The only legal patterns of type `Box` (outside `std`) are `_` and box // patterns. If we're here we can assume this is a box pattern. - Fields::wildcards_from_tys(cx, once(substs.type_at(0))) + Fields::wildcards_from_tys(pcx.cx, once(substs.type_at(0))) } else { let variant = &adt.variant(constructor.variant_index_for_adt(*adt)); - let tys = Fields::list_variant_nonhidden_fields(cx, ty, variant) + let tys = Fields::list_variant_nonhidden_fields(pcx.cx, pcx.ty, variant) .map(|(_, ty)| ty); - Fields::wildcards_from_tys(cx, tys) + Fields::wildcards_from_tys(pcx.cx, tys) } } - _ => bug!("Unexpected type for `Single` constructor: {:?}", ty), + _ => bug!("Unexpected type for `Single` constructor: {:?}", pcx), }, - Slice(slice) => match *ty.kind() { + Slice(slice) => match *pcx.ty.kind() { ty::Slice(ty) | ty::Array(ty, _) => { let arity = slice.arity(); - Fields::wildcards_from_tys(cx, (0..arity).map(|_| ty)) + Fields::wildcards_from_tys(pcx.cx, (0..arity).map(|_| ty)) } - _ => bug!("bad slice pattern {:?} {:?}", constructor, ty), + _ => bug!("bad slice pattern {:?} {:?}", constructor, pcx), }, Str(..) | FloatRange(..) @@ -1243,7 +1240,7 @@ impl<'p, 'tcx> Fields<'p, 'tcx> { bug!("called `Fields::wildcards` on an `Or` ctor") } }; - debug!("Fields::wildcards({:?}, {:?}) = {:#?}", constructor, ty, ret); + debug!(?ret); ret } @@ -1286,7 +1283,7 @@ impl<'p, 'tcx> DeconstructedPat<'p, 'tcx> { /// For example, if `ctor` is a `Constructor::Variant` for `Option::Some`, we get the pattern /// `Some(_)`. pub(super) fn wild_from_ctor(pcx: PatCtxt<'_, 'p, 'tcx>, ctor: Constructor<'tcx>) -> Self { - let fields = Fields::wildcards(pcx.cx, pcx.ty, &ctor); + let fields = Fields::wildcards(pcx, &ctor); DeconstructedPat::new(ctor, fields, pcx.ty, DUMMY_SP) } @@ -1553,13 +1550,13 @@ impl<'p, 'tcx> DeconstructedPat<'p, 'tcx> { /// `other_ctor` can be different from `self.ctor`, but must be covered by it. pub(super) fn specialize<'a>( &'a self, - cx: &MatchCheckCtxt<'p, 'tcx>, + pcx: PatCtxt<'_, 'p, 'tcx>, other_ctor: &Constructor<'tcx>, ) -> SmallVec<[&'p DeconstructedPat<'p, 'tcx>; 2]> { match (&self.ctor, other_ctor) { (Wildcard, _) => { // We return a wildcard for each field of `other_ctor`. - Fields::wildcards(cx, self.ty, other_ctor).iter_patterns().collect() + Fields::wildcards(pcx, other_ctor).iter_patterns().collect() } (Slice(self_slice), Slice(other_slice)) if self_slice.arity() != other_slice.arity() => @@ -1578,7 +1575,7 @@ impl<'p, 'tcx> DeconstructedPat<'p, 'tcx> { let prefix = &self.fields.fields[..prefix]; let suffix = &self.fields.fields[self_slice.arity() - suffix..]; let wildcard: &_ = - cx.pattern_arena.alloc(DeconstructedPat::wildcard(inner_ty)); + pcx.cx.pattern_arena.alloc(DeconstructedPat::wildcard(inner_ty)); let extra_wildcards = other_slice.arity() - self_slice.arity(); let extra_wildcards = (0..extra_wildcards).map(|_| wildcard); prefix.iter().chain(extra_wildcards).chain(suffix).collect() diff --git a/compiler/rustc_mir_build/src/thir/pattern/mod.rs b/compiler/rustc_mir_build/src/thir/pattern/mod.rs index a13748a2d47..7d22f7b69d8 100644 --- a/compiler/rustc_mir_build/src/thir/pattern/mod.rs +++ b/compiler/rustc_mir_build/src/thir/pattern/mod.rs @@ -196,6 +196,7 @@ impl<'a, 'tcx> PatCtxt<'a, 'tcx> { } } + #[instrument(skip(self), level = "debug")] fn lower_pattern_unadjusted(&mut self, pat: &'tcx hir::Pat<'tcx>) -> Pat<'tcx> { let mut ty = self.typeck_results.node_type(pat.hir_id); diff --git a/compiler/rustc_mir_build/src/thir/pattern/usefulness.rs b/compiler/rustc_mir_build/src/thir/pattern/usefulness.rs index 9e7a267ecbd..f27ec22a8de 100644 --- a/compiler/rustc_mir_build/src/thir/pattern/usefulness.rs +++ b/compiler/rustc_mir_build/src/thir/pattern/usefulness.rs @@ -411,12 +411,12 @@ impl<'p, 'tcx> PatStack<'p, 'tcx> { /// This is roughly the inverse of `Constructor::apply`. fn pop_head_constructor( &self, - cx: &MatchCheckCtxt<'p, 'tcx>, + pcx: PatCtxt<'_, 'p, 'tcx>, ctor: &Constructor<'tcx>, ) -> PatStack<'p, 'tcx> { // We pop the head pattern and push the new fields extracted from the arguments of // `self.head()`. - let mut new_fields: SmallVec<[_; 2]> = self.head().specialize(cx, ctor); + let mut new_fields: SmallVec<[_; 2]> = self.head().specialize(pcx, ctor); new_fields.extend_from_slice(&self.pats[1..]); PatStack::from_vec(new_fields) } @@ -475,7 +475,7 @@ impl<'p, 'tcx> Matrix<'p, 'tcx> { let mut matrix = Matrix::empty(); for row in &self.patterns { if ctor.is_covered_by(pcx, row.head().ctor()) { - let new_row = row.pop_head_constructor(pcx.cx, ctor); + let new_row = row.pop_head_constructor(pcx, ctor); matrix.push(new_row); } } @@ -786,7 +786,7 @@ fn is_useful<'p, 'tcx>( is_under_guard: bool, is_top_level: bool, ) -> Usefulness<'p, 'tcx> { - debug!("matrix,v={:?}{:?}", matrix, v); + debug!(?matrix, ?v); let Matrix { patterns: rows, .. } = matrix; // The base case. We are pattern-matching on () and the return value is @@ -806,11 +806,6 @@ fn is_useful<'p, 'tcx>( debug_assert!(rows.iter().all(|r| r.len() == v.len())); - let ty = v.head().ty(); - let is_non_exhaustive = cx.is_foreign_non_exhaustive_enum(ty); - debug!("v.head: {:?}, v.span: {:?}", v.head(), v.head().span()); - let pcx = PatCtxt { cx, ty, span: v.head().span(), is_top_level, is_non_exhaustive }; - // If the first pattern is an or-pattern, expand it. let mut ret = Usefulness::new_not_useful(witness_preference); if v.head().is_or_pat() { @@ -832,6 +827,19 @@ fn is_useful<'p, 'tcx>( } } } else { + let mut ty = v.head().ty(); + + // Opaque types can't get destructured/split, but the patterns can + // actually hint at hidden types, so we use the patterns' types instead. + if let ty::Opaque(..) = v.head().ty().kind() { + if let Some(row) = rows.first() { + ty = row.head().ty(); + } + } + let is_non_exhaustive = cx.is_foreign_non_exhaustive_enum(ty); + debug!("v.head: {:?}, v.span: {:?}", v.head(), v.head().span()); + let pcx = PatCtxt { cx, ty, span: v.head().span(), is_top_level, is_non_exhaustive }; + let v_ctor = v.head().ctor(); debug!(?v_ctor); if let Constructor::IntRange(ctor_range) = &v_ctor { @@ -853,7 +861,7 @@ fn is_useful<'p, 'tcx>( debug!("specialize({:?})", ctor); // We cache the result of `Fields::wildcards` because it is used a lot. let spec_matrix = start_matrix.specialize_constructor(pcx, &ctor); - let v = v.pop_head_constructor(cx, &ctor); + let v = v.pop_head_constructor(pcx, &ctor); let usefulness = ensure_sufficient_stack(|| { is_useful(cx, &spec_matrix, &v, witness_preference, hir_id, is_under_guard, false) }); diff --git a/compiler/rustc_mir_dataflow/src/move_paths/abs_domain.rs b/compiler/rustc_mir_dataflow/src/move_paths/abs_domain.rs index 28936274baa..7806e8f45d3 100644 --- a/compiler/rustc_mir_dataflow/src/move_paths/abs_domain.rs +++ b/compiler/rustc_mir_dataflow/src/move_paths/abs_domain.rs @@ -48,6 +48,7 @@ impl<'tcx> Lift for PlaceElem<'tcx> { match *self { ProjectionElem::Deref => ProjectionElem::Deref, ProjectionElem::Field(f, ty) => ProjectionElem::Field(f, ty.lift()), + ProjectionElem::OpaqueCast(ty) => ProjectionElem::OpaqueCast(ty.lift()), ProjectionElem::Index(ref i) => ProjectionElem::Index(i.lift()), ProjectionElem::Subslice { from, to, from_end } => { ProjectionElem::Subslice { from, to, from_end } diff --git a/compiler/rustc_mir_transform/src/add_retag.rs b/compiler/rustc_mir_transform/src/add_retag.rs index b91ae083cf5..86327ade94b 100644 --- a/compiler/rustc_mir_transform/src/add_retag.rs +++ b/compiler/rustc_mir_transform/src/add_retag.rs @@ -28,6 +28,7 @@ fn is_stable(place: PlaceRef<'_>) -> bool { ProjectionElem::Field { .. } | ProjectionElem::ConstantIndex { .. } | ProjectionElem::Subslice { .. } | + ProjectionElem::OpaqueCast { .. } | ProjectionElem::Downcast { .. } => true, } }) diff --git a/compiler/rustc_passes/Cargo.toml b/compiler/rustc_passes/Cargo.toml index 676812db59a..faa9c493d88 100644 --- a/compiler/rustc_passes/Cargo.toml +++ b/compiler/rustc_passes/Cargo.toml @@ -15,6 +15,7 @@ rustc_hir = { path = "../rustc_hir" } rustc_index = { path = "../rustc_index" } rustc_session = { path = "../rustc_session" } rustc_target = { path = "../rustc_target" } +rustc_macros = { path = "../rustc_macros" } rustc_ast = { path = "../rustc_ast" } rustc_serialize = { path = "../rustc_serialize" } rustc_span = { path = "../rustc_span" } diff --git a/compiler/rustc_passes/src/check_attr.rs b/compiler/rustc_passes/src/check_attr.rs index e626a1e4ed1..d96e7d3efe8 100644 --- a/compiler/rustc_passes/src/check_attr.rs +++ b/compiler/rustc_passes/src/check_attr.rs @@ -4,9 +4,10 @@ //! conflicts between multiple such attributes attached to the same //! item. +use crate::errors; use rustc_ast::{ast, AttrStyle, Attribute, Lit, LitKind, MetaItemKind, NestedMetaItem}; use rustc_data_structures::fx::FxHashMap; -use rustc_errors::{pluralize, struct_span_err, Applicability, MultiSpan}; +use rustc_errors::{fluent, pluralize, struct_span_err, Applicability, MultiSpan}; use rustc_expand::base::resolve_path; use rustc_feature::{AttributeDuplicates, AttributeType, BuiltinAttribute, BUILTIN_ATTRIBUTE_MAP}; use rustc_hir as hir; @@ -175,16 +176,20 @@ impl CheckAttrVisitor<'_> { if let Some(BuiltinAttribute { type_: AttributeType::CrateLevel, .. }) = attr.ident().and_then(|ident| BUILTIN_ATTRIBUTE_MAP.get(&ident.name)) { - self.tcx.struct_span_lint_hir(UNUSED_ATTRIBUTES, hir_id, attr.span, |lint| { - let msg = match attr.style { - ast::AttrStyle::Outer => { - "crate-level attribute should be an inner attribute: add an exclamation \ - mark: `#![foo]`" - } - ast::AttrStyle::Inner => "crate-level attribute should be in the root module", - }; - lint.build(msg).emit(); - }); + match attr.style { + ast::AttrStyle::Outer => self.tcx.emit_spanned_lint( + UNUSED_ATTRIBUTES, + hir_id, + attr.span, + errors::OuterCrateLevelAttr, + ), + ast::AttrStyle::Inner => self.tcx.emit_spanned_lint( + UNUSED_ATTRIBUTES, + hir_id, + attr.span, + errors::InnerCrateLevelAttr, + ), + } } } @@ -209,37 +214,21 @@ impl CheckAttrVisitor<'_> { } fn inline_attr_str_error_with_macro_def(&self, hir_id: HirId, attr: &Attribute, sym: &str) { - self.tcx.struct_span_lint_hir(UNUSED_ATTRIBUTES, hir_id, attr.span, |lint| { - lint.build(&format!( - "`#[{sym}]` is ignored on struct fields, match arms and macro defs", - )) - .warn( - "this was previously accepted by the compiler but is \ - being phased out; it will become a hard error in \ - a future release!", - ) - .note( - "see issue #80564 <https://github.com/rust-lang/rust/issues/80564> \ - for more information", - ) - .emit(); - }); + self.tcx.emit_spanned_lint( + UNUSED_ATTRIBUTES, + hir_id, + attr.span, + errors::IgnoredAttrWithMacro { sym }, + ); } fn inline_attr_str_error_without_macro_def(&self, hir_id: HirId, attr: &Attribute, sym: &str) { - self.tcx.struct_span_lint_hir(UNUSED_ATTRIBUTES, hir_id, attr.span, |lint| { - lint.build(&format!("`#[{sym}]` is ignored on struct fields and match arms")) - .warn( - "this was previously accepted by the compiler but is \ - being phased out; it will become a hard error in \ - a future release!", - ) - .note( - "see issue #80564 <https://github.com/rust-lang/rust/issues/80564> \ - for more information", - ) - .emit(); - }); + self.tcx.emit_spanned_lint( + UNUSED_ATTRIBUTES, + hir_id, + attr.span, + errors::IgnoredAttr { sym }, + ); } /// Checks if an `#[inline]` is applied to a function or a closure. Returns `true` if valid. @@ -249,9 +238,12 @@ impl CheckAttrVisitor<'_> { | Target::Closure | Target::Method(MethodKind::Trait { body: true } | MethodKind::Inherent) => true, Target::Method(MethodKind::Trait { body: false }) | Target::ForeignFn => { - self.tcx.struct_span_lint_hir(UNUSED_ATTRIBUTES, hir_id, attr.span, |lint| { - lint.build("`#[inline]` is ignored on function prototypes").emit(); - }); + self.tcx.emit_spanned_lint( + UNUSED_ATTRIBUTES, + hir_id, + attr.span, + errors::IgnoredInlineAttrFnProto, + ); true } // FIXME(#65833): We permit associated consts to have an `#[inline]` attribute with @@ -259,19 +251,12 @@ impl CheckAttrVisitor<'_> { // accidentally, to to be compatible with crates depending on them, we can't throw an // error here. Target::AssocConst => { - self.tcx.struct_span_lint_hir(UNUSED_ATTRIBUTES, hir_id, attr.span, |lint| { - lint.build("`#[inline]` is ignored on constants") - .warn( - "this was previously accepted by the compiler but is \ - being phased out; it will become a hard error in \ - a future release!", - ) - .note( - "see issue #65833 <https://github.com/rust-lang/rust/issues/65833> \ - for more information", - ) - .emit(); - }); + self.tcx.emit_spanned_lint( + UNUSED_ATTRIBUTES, + hir_id, + attr.span, + errors::IgnoredInlineAttrConstants, + ); true } // FIXME(#80564): Same for fields, arms, and macro defs @@ -280,14 +265,10 @@ impl CheckAttrVisitor<'_> { true } _ => { - struct_span_err!( - self.tcx.sess, - attr.span, - E0518, - "attribute should be applied to function or closure", - ) - .span_label(span, "not a function or closure") - .emit(); + self.tcx.sess.emit_err(errors::InlineNotFnOrClosure { + attr_span: attr.span, + defn_span: span, + }); false } } @@ -309,36 +290,40 @@ impl CheckAttrVisitor<'_> { // function prototypes can't be covered Target::Method(MethodKind::Trait { body: false }) | Target::ForeignFn => { - self.tcx.struct_span_lint_hir(UNUSED_ATTRIBUTES, hir_id, attr.span, |lint| { - lint.build("`#[no_coverage]` is ignored on function prototypes").emit(); - }); + self.tcx.emit_spanned_lint( + UNUSED_ATTRIBUTES, + hir_id, + attr.span, + errors::IgnoredNoCoverageFnProto, + ); true } Target::Mod | Target::ForeignMod | Target::Impl | Target::Trait => { - self.tcx.struct_span_lint_hir(UNUSED_ATTRIBUTES, hir_id, attr.span, |lint| { - lint.build("`#[no_coverage]` does not propagate into items and must be applied to the contained functions directly").emit(); - }); + self.tcx.emit_spanned_lint( + UNUSED_ATTRIBUTES, + hir_id, + attr.span, + errors::IgnoredNoCoveragePropagate, + ); true } Target::Expression | Target::Statement | Target::Arm => { - self.tcx.struct_span_lint_hir(UNUSED_ATTRIBUTES, hir_id, attr.span, |lint| { - lint.build("`#[no_coverage]` may only be applied to function definitions") - .emit(); - }); + self.tcx.emit_spanned_lint( + UNUSED_ATTRIBUTES, + hir_id, + attr.span, + errors::IgnoredNoCoverageFnDefn, + ); true } _ => { - struct_span_err!( - self.tcx.sess, - attr.span, - E0788, - "`#[no_coverage]` must be applied to coverable code", - ) - .span_label(span, "not coverable code") - .emit(); + self.tcx.sess.emit_err(errors::IgnoredNoCoverageNotCoverable { + attr_span: attr.span, + defn_span: span, + }); false } } @@ -389,14 +374,10 @@ impl CheckAttrVisitor<'_> { true } _ => { - self.tcx - .sess - .struct_span_err( - attr.span, - "attribute should be applied to a function definition", - ) - .span_label(span, "not a function definition") - .emit(); + self.tcx.sess.emit_err(errors::AttrShouldBeAppliedToFn { + attr_span: attr.span, + defn_span: span, + }); false } } @@ -408,14 +389,10 @@ impl CheckAttrVisitor<'_> { Target::Fn | Target::Method(MethodKind::Trait { body: true } | MethodKind::Inherent) => true, _ => { - self.tcx - .sess - .struct_span_err( - attr.span, - "attribute should be applied to a function definition", - ) - .span_label(span, "not a function definition") - .emit(); + self.tcx.sess.emit_err(errors::AttrShouldBeAppliedToFn { + attr_span: attr.span, + defn_span: span, + }); false } } @@ -432,13 +409,7 @@ impl CheckAttrVisitor<'_> { ) -> bool { match target { _ if attrs.iter().any(|attr| attr.has_name(sym::naked)) => { - struct_span_err!( - self.tcx.sess, - attr_span, - E0736, - "cannot use `#[track_caller]` with `#[naked]`", - ) - .emit(); + self.tcx.sess.emit_err(errors::NakedTrackedCaller { attr_span }); false } Target::Fn | Target::Method(..) | Target::ForeignFn | Target::Closure => true, @@ -453,14 +424,9 @@ impl CheckAttrVisitor<'_> { true } _ => { - struct_span_err!( - self.tcx.sess, - attr_span, - E0739, - "attribute should be applied to function" - ) - .span_label(span, "not a function") - .emit(); + self.tcx + .sess + .emit_err(errors::TrackedCallerWrongLocation { attr_span, defn_span: span }); false } } @@ -485,14 +451,10 @@ impl CheckAttrVisitor<'_> { true } _ => { - struct_span_err!( - self.tcx.sess, - attr.span, - E0701, - "attribute can only be applied to a struct or enum" - ) - .span_label(span, "not a struct or enum") - .emit(); + self.tcx.sess.emit_err(errors::NonExhaustiveWrongLocation { + attr_span: attr.span, + defn_span: span, + }); false } } @@ -511,11 +473,10 @@ impl CheckAttrVisitor<'_> { true } _ => { - self.tcx - .sess - .struct_span_err(attr.span, "attribute can only be applied to a trait") - .span_label(span, "not a trait") - .emit(); + self.tcx.sess.emit_err(errors::AttrShouldBeAppliedToTrait { + attr_span: attr.span, + defn_span: span, + }); false } } @@ -531,11 +492,10 @@ impl CheckAttrVisitor<'_> { match target { Target::Trait => true, _ => { - self.tcx - .sess - .struct_span_err(attr.span, "attribute can only be applied to a trait") - .span_label(span, "not a trait") - .emit(); + self.tcx.sess.emit_err(errors::AttrShouldBeAppliedToTrait { + attr_span: attr.span, + defn_span: span, + }); false } } @@ -555,16 +515,12 @@ impl CheckAttrVisitor<'_> { // FIXME: #[target_feature] was previously erroneously allowed on statements and some // crates used this, so only emit a warning. Target::Statement => { - self.tcx.struct_span_lint_hir(UNUSED_ATTRIBUTES, hir_id, attr.span, |lint| { - lint.build("attribute should be applied to a function") - .warn( - "this was previously accepted by the compiler but is \ - being phased out; it will become a hard error in \ - a future release!", - ) - .span_label(span, "not a function") - .emit(); - }); + self.tcx.emit_spanned_lint( + UNUSED_ATTRIBUTES, + hir_id, + attr.span, + errors::TargetFeatureOnStatement, + ); true } // FIXME(#80564): We permit struct fields, match arms and macro defs to have an @@ -576,11 +532,10 @@ impl CheckAttrVisitor<'_> { true } _ => { - self.tcx - .sess - .struct_span_err(attr.span, "attribute should be applied to a function") - .span_label(span, "not a function") - .emit(); + self.tcx.sess.emit_err(errors::AttrShouldBeAppliedToFn { + attr_span: attr.span, + defn_span: span, + }); false } } @@ -591,24 +546,17 @@ impl CheckAttrVisitor<'_> { match target { Target::ForeignStatic | Target::Static => true, _ => { - self.tcx - .sess - .struct_span_err(attr.span, "attribute should be applied to a static") - .span_label(span, "not a static") - .emit(); + self.tcx.sess.emit_err(errors::AttrShouldBeAppliedToStatic { + attr_span: attr.span, + defn_span: span, + }); false } } } fn doc_attr_str_error(&self, meta: &NestedMetaItem, attr_name: &str) { - self.tcx - .sess - .struct_span_err( - meta.span(), - &format!("doc {0} attribute expects a string: #[doc({0} = \"a\")]", attr_name), - ) - .emit(); + self.tcx.sess.emit_err(errors::DocExpectStr { attr_span: meta.span(), attr_name }); } fn check_doc_alias_value( @@ -621,22 +569,12 @@ impl CheckAttrVisitor<'_> { aliases: &mut FxHashMap<String, Span>, ) -> bool { let tcx = self.tcx; - let err_fn = move |span: Span, msg: &str| { - tcx.sess.span_err( - span, - &format!( - "`#[doc(alias{})]` {}", - if is_list { "(\"...\")" } else { " = \"...\"" }, - msg, - ), - ); - false - }; + let span = meta.name_value_literal_span().unwrap_or_else(|| meta.span()); + let attr_str = + &format!("`#[doc(alias{})]`", if is_list { "(\"...\")" } else { " = \"...\"" }); if doc_alias == kw::Empty { - return err_fn( - meta.name_value_literal_span().unwrap_or_else(|| meta.span()), - "attribute cannot have empty value", - ); + tcx.sess.emit_err(errors::DocAliasEmpty { span, attr_str }); + return false; } let doc_alias_str = doc_alias.as_str(); @@ -644,23 +582,16 @@ impl CheckAttrVisitor<'_> { .chars() .find(|&c| c == '"' || c == '\'' || (c.is_whitespace() && c != ' ')) { - self.tcx.sess.span_err( - meta.name_value_literal_span().unwrap_or_else(|| meta.span()), - &format!( - "{:?} character isn't allowed in `#[doc(alias{})]`", - c, - if is_list { "(\"...\")" } else { " = \"...\"" }, - ), - ); + tcx.sess.emit_err(errors::DocAliasBadChar { span, attr_str, char_: c }); return false; } if doc_alias_str.starts_with(' ') || doc_alias_str.ends_with(' ') { - return err_fn( - meta.name_value_literal_span().unwrap_or_else(|| meta.span()), - "cannot start or end with ' '", - ); + tcx.sess.emit_err(errors::DocAliasStartEnd { span, attr_str }); + return false; } - if let Some(err) = match target { + + let span = meta.span(); + if let Some(location) = match target { Target::Impl => Some("implementation block"), Target::ForeignMod => Some("extern block"), Target::AssocTy => { @@ -686,19 +617,21 @@ impl CheckAttrVisitor<'_> { Target::Param => return false, _ => None, } { - return err_fn(meta.span(), &format!("isn't allowed on {}", err)); + tcx.sess.emit_err(errors::DocAliasBadLocation { span, attr_str, location }); + return false; } let item_name = self.tcx.hir().name(hir_id); if item_name == doc_alias { - return err_fn(meta.span(), "is the same as the item's name"); + tcx.sess.emit_err(errors::DocAliasNotAnAlias { span, attr_str }); + return false; } - let span = meta.span(); if let Err(entry) = aliases.try_insert(doc_alias_str.to_owned(), span) { - self.tcx.struct_span_lint_hir(UNUSED_ATTRIBUTES, hir_id, span, |lint| { - lint.build("doc alias is duplicated") - .span_label(*entry.entry.get(), "first defined here") - .emit(); - }); + self.tcx.emit_spanned_lint( + UNUSED_ATTRIBUTES, + hir_id, + span, + errors::DocAliasDuplicated { first_defn: *entry.entry.get() }, + ); } true } @@ -723,22 +656,12 @@ impl CheckAttrVisitor<'_> { _ => { self.tcx .sess - .struct_span_err( - v.span(), - "`#[doc(alias(\"a\"))]` expects string literals", - ) - .emit(); + .emit_err(errors::DocAliasNotStringLiteral { span: v.span() }); errors += 1; } }, None => { - self.tcx - .sess - .struct_span_err( - v.span(), - "`#[doc(alias(\"a\"))]` expects string literals", - ) - .emit(); + self.tcx.sess.emit_err(errors::DocAliasNotStringLiteral { span: v.span() }); errors += 1; } } @@ -747,14 +670,7 @@ impl CheckAttrVisitor<'_> { } else if let Some(doc_alias) = meta.value_str() { self.check_doc_alias_value(meta, doc_alias, hir_id, target, false, aliases) } else { - self.tcx - .sess - .struct_span_err( - meta.span(), - "doc alias attribute expects a string `#[doc(alias = \"a\")]` or a list of \ - strings `#[doc(alias(\"a\", \"b\"))]`", - ) - .emit(); + self.tcx.sess.emit_err(errors::DocAliasMalformed { span: meta.span() }); false } } @@ -771,35 +687,20 @@ impl CheckAttrVisitor<'_> { }) { Some(ItemKind::Mod(ref module)) => { if !module.item_ids.is_empty() { - self.tcx - .sess - .struct_span_err( - meta.span(), - "`#[doc(keyword = \"...\")]` can only be used on empty modules", - ) - .emit(); + self.tcx.sess.emit_err(errors::DocKeywordEmptyMod { span: meta.span() }); return false; } } _ => { - self.tcx - .sess - .struct_span_err( - meta.span(), - "`#[doc(keyword = \"...\")]` can only be used on modules", - ) - .emit(); + self.tcx.sess.emit_err(errors::DocKeywordNotMod { span: meta.span() }); return false; } } if !rustc_lexer::is_ident(doc_keyword.as_str()) { - self.tcx - .sess - .struct_span_err( - meta.name_value_literal_span().unwrap_or_else(|| meta.span()), - &format!("`{doc_keyword}` is not a valid identifier"), - ) - .emit(); + self.tcx.sess.emit_err(errors::DocKeywordInvalidIdent { + span: meta.name_value_literal_span().unwrap_or_else(|| meta.span()), + doc_keyword, + }); return false; } true @@ -812,24 +713,12 @@ impl CheckAttrVisitor<'_> { }) { Some(ItemKind::Impl(ref i)) => { if !matches!(&i.self_ty.kind, hir::TyKind::Tup([_])) { - self.tcx - .sess - .struct_span_err( - meta.span(), - "`#[doc(tuple_variadic)]` must be used on the first of a set of tuple trait impls with varying arity", - ) - .emit(); + self.tcx.sess.emit_err(errors::DocTupleVariadicNotFirst { span: meta.span() }); return false; } } _ => { - self.tcx - .sess - .struct_span_err( - meta.span(), - "`#[doc(keyword = \"...\")]` can only be used on impl blocks", - ) - .emit(); + self.tcx.sess.emit_err(errors::DocKeywordOnlyImpl { span: meta.span() }); return false; } } @@ -858,13 +747,9 @@ impl CheckAttrVisitor<'_> { if let Some((prev_inline, prev_span)) = *specified_inline { if do_inline != prev_inline { let mut spans = MultiSpan::from_spans(vec![prev_span, meta.span()]); - spans.push_span_label(prev_span, "this attribute..."); - spans.push_span_label(meta.span(), "...conflicts with this attribute"); - self.tcx - .sess - .struct_span_err(spans, "conflicting doc inlining attributes") - .help("remove one of the conflicting attributes") - .emit(); + spans.push_span_label(prev_span, fluent::passes::doc_inline_conflict_first); + spans.push_span_label(meta.span(), fluent::passes::doc_inline_conflict_second); + self.tcx.sess.emit_err(errors::DocKeywordConflict { spans }); return false; } true @@ -873,23 +758,14 @@ impl CheckAttrVisitor<'_> { true } } else { - self.tcx.struct_span_lint_hir( + self.tcx.emit_spanned_lint( INVALID_DOC_ATTRIBUTES, hir_id, meta.span(), - |lint| { - let mut err = lint.build( - "this attribute can only be applied to a `use` item", - ); - err.span_label(meta.span(), "only applicable on `use` items"); - if attr.style == AttrStyle::Outer { - err.span_label( - self.tcx.hir().span(hir_id), - "not a `use` item", - ); - } - err.note("read https://doc.rust-lang.org/nightly/rustdoc/the-doc-attribute.html#inline-and-no_inline for more information") - .emit(); + errors::DocInlineOnlyUse { + attr_span: meta.span(), + item_span: (attr.style == AttrStyle::Outer) + .then(|| self.tcx.hir().span(hir_id)), }, ); false @@ -904,15 +780,7 @@ impl CheckAttrVisitor<'_> { attr_name: &str, ) -> bool { if CRATE_HIR_ID == hir_id { - self.tcx - .sess - .struct_span_err( - meta.span(), - &format!( - "`#![doc({attr_name} = \"...\")]` isn't allowed as a crate-level attribute", - ), - ) - .emit(); + self.tcx.sess.emit_err(errors::DocAttrNotCrateLevel { span: meta.span(), attr_name }); return false; } true @@ -926,36 +794,25 @@ impl CheckAttrVisitor<'_> { hir_id: HirId, ) -> bool { if hir_id != CRATE_HIR_ID { - self.tcx.struct_span_lint_hir( - INVALID_DOC_ATTRIBUTES, - hir_id, - meta.span(), - |lint| { - let mut err = lint.build( - "this attribute can only be applied at the crate level", - ); - if attr.style == AttrStyle::Outer && self.tcx.hir().get_parent_item(hir_id) == CRATE_DEF_ID { - if let Ok(mut src) = - self.tcx.sess.source_map().span_to_snippet(attr.span) - { - src.insert(1, '!'); - err.span_suggestion_verbose( - attr.span, - "to apply to the crate, use an inner attribute", - src, - Applicability::MaybeIncorrect, - ); - } else { - err.span_help( - attr.span, - "to apply to the crate, use an inner attribute", - ); - } + self.tcx.struct_span_lint_hir(INVALID_DOC_ATTRIBUTES, hir_id, meta.span(), |lint| { + let mut err = lint.build(fluent::passes::attr_crate_level); + if attr.style == AttrStyle::Outer + && self.tcx.hir().get_parent_item(hir_id) == CRATE_DEF_ID + { + if let Ok(mut src) = self.tcx.sess.source_map().span_to_snippet(attr.span) { + src.insert(1, '!'); + err.span_suggestion_verbose( + attr.span, + fluent::passes::suggestion, + src, + Applicability::MaybeIncorrect, + ); + } else { + err.span_help(attr.span, fluent::passes::help); } - err.note("read https://doc.rust-lang.org/nightly/rustdoc/the-doc-attribute.html#at-the-crate-level for more information") - .emit(); - }, - ); + } + err.note(fluent::passes::note).emit(); + }); return false; } true @@ -970,18 +827,14 @@ impl CheckAttrVisitor<'_> { match i_meta.name_or_empty() { sym::attr | sym::no_crate_inject => {} _ => { - self.tcx.struct_span_lint_hir( + self.tcx.emit_spanned_lint( INVALID_DOC_ATTRIBUTES, hir_id, i_meta.span(), - |lint| { - lint.build(&format!( - "unknown `doc(test)` attribute `{}`", - rustc_ast_pretty::pprust::path_to_string( - &i_meta.meta_item().unwrap().path - ), - )) - .emit(); + errors::DocTestUnknown { + path: rustc_ast_pretty::pprust::path_to_string( + &i_meta.meta_item().unwrap().path, + ), }, ); is_valid = false; @@ -989,9 +842,12 @@ impl CheckAttrVisitor<'_> { } } } else { - self.tcx.struct_span_lint_hir(INVALID_DOC_ATTRIBUTES, hir_id, meta.span(), |lint| { - lint.build("`#[doc(test(...)]` takes a list of attributes").emit(); - }); + self.tcx.emit_spanned_lint( + INVALID_DOC_ATTRIBUTES, + hir_id, + meta.span(), + errors::DocTestTakesList, + ); is_valid = false; } is_valid @@ -1093,79 +949,66 @@ impl CheckAttrVisitor<'_> { sym::primitive => { if !self.tcx.features().rustdoc_internals { - self.tcx.struct_span_lint_hir( + self.tcx.emit_spanned_lint( INVALID_DOC_ATTRIBUTES, hir_id, i_meta.span, - |lint| { - let mut diag = lint.build( - "`doc(primitive)` should never have been stable", - ); - diag.emit(); - }, + errors::DocPrimitive, ); } } _ => { - self.tcx.struct_span_lint_hir( - INVALID_DOC_ATTRIBUTES, - hir_id, - i_meta.span, - |lint| { - let mut diag = lint.build(&format!( - "unknown `doc` attribute `{}`", - rustc_ast_pretty::pprust::path_to_string(&i_meta.path), - )); - if i_meta.has_name(sym::spotlight) { - diag.note( - "`doc(spotlight)` was renamed to `doc(notable_trait)`", - ); - diag.span_suggestion_short( - i_meta.span, - "use `notable_trait` instead", - "notable_trait", - Applicability::MachineApplicable, - ); - diag.note("`doc(spotlight)` is now a no-op"); + let path = rustc_ast_pretty::pprust::path_to_string(&i_meta.path); + if i_meta.has_name(sym::spotlight) { + self.tcx.emit_spanned_lint( + INVALID_DOC_ATTRIBUTES, + hir_id, + i_meta.span, + errors::DocTestUnknownSpotlight { + path, + span: i_meta.span } - if i_meta.has_name(sym::include) { - if let Some(value) = i_meta.value_str() { - // if there are multiple attributes, the suggestion would suggest deleting all of them, which is incorrect - let applicability = if list.len() == 1 { - Applicability::MachineApplicable - } else { - Applicability::MaybeIncorrect - }; - let inner = if attr.style == AttrStyle::Inner { - "!" - } else { - "" - }; - diag.span_suggestion( - attr.meta().unwrap().span, - "use `doc = include_str!` instead", - format!( - "#{inner}[doc = include_str!(\"{value}\")]", - ), - applicability, - ); - } + ); + } else if i_meta.has_name(sym::include) && + let Some(value) = i_meta.value_str() { + let applicability = if list.len() == 1 { + Applicability::MachineApplicable + } else { + Applicability::MaybeIncorrect + }; + // If there are multiple attributes, the suggestion would suggest + // deleting all of them, which is incorrect. + self.tcx.emit_spanned_lint( + INVALID_DOC_ATTRIBUTES, + hir_id, + i_meta.span, + errors::DocTestUnknownInclude { + path, + value: value.to_string(), + inner: (attr.style == AttrStyle::Inner) + .then_some("!") + .unwrap_or(""), + sugg: (attr.meta().unwrap().span, applicability), } - diag.emit(); - }, - ); + ); + } else { + self.tcx.emit_spanned_lint( + INVALID_DOC_ATTRIBUTES, + hir_id, + i_meta.span, + errors::DocTestUnknownAny { path } + ); + } is_valid = false; } } } else { - self.tcx.struct_span_lint_hir( + self.tcx.emit_spanned_lint( INVALID_DOC_ATTRIBUTES, hir_id, meta.span(), - |lint| { - lint.build("invalid `doc` attribute").emit(); - }, + errors::DocInvalid, ); is_valid = false; } @@ -1180,14 +1023,7 @@ impl CheckAttrVisitor<'_> { match target { Target::Struct | Target::Enum | Target::TyAlias => true, _ => { - self.tcx - .sess - .struct_span_err( - attr.span, - "`pass_by_value` attribute should be applied to a struct, enum or type alias.", - ) - .span_label(span, "is not a struct, enum or type alias") - .emit(); + self.tcx.sess.emit_err(errors::PassByValue { attr_span: attr.span, span }); false } } @@ -1197,14 +1033,7 @@ impl CheckAttrVisitor<'_> { match target { Target::Method(MethodKind::Inherent) => true, _ => { - self.tcx - .sess - .struct_span_err( - attr.span, - "`rustc_allow_incoherent_impl` attribute should be applied to impl items.", - ) - .span_label(span, "the only currently supported targets are inherent methods") - .emit(); + self.tcx.sess.emit_err(errors::AllowIncoherentImpl { attr_span: attr.span, span }); false } } @@ -1223,12 +1052,7 @@ impl CheckAttrVisitor<'_> { _ => { self.tcx .sess - .struct_span_err( - attr.span, - "`rustc_has_incoherent_inherent_impls` attribute should be applied to types or traits.", - ) - .span_label(span, "only adts, extern types and traits are supported") - .emit(); + .emit_err(errors::HasIncoherentInherentImpl { attr_span: attr.span, span }); false } } @@ -1238,19 +1062,12 @@ impl CheckAttrVisitor<'_> { fn check_must_use(&self, hir_id: HirId, attr: &Attribute, span: Span, target: Target) -> bool { let node = self.tcx.hir().get(hir_id); if let Some(kind) = node.fn_kind() && let rustc_hir::IsAsync::Async = kind.asyncness() { - self.tcx.struct_span_lint_hir(UNUSED_ATTRIBUTES, hir_id, attr.span, |lint| { - lint.build( - "`must_use` attribute on `async` functions \ - applies to the anonymous `Future` returned by the \ - function, not the value within", - ) - .span_label( - span, - "this attribute does nothing, the `Future`s \ - returned by async functions are already `must_use`", - ) - .emit(); - }); + self.tcx.emit_spanned_lint( + UNUSED_ATTRIBUTES, + hir_id, + attr.span, + errors::MustUseAsync { span } + ); } if !matches!( @@ -1278,12 +1095,12 @@ impl CheckAttrVisitor<'_> { _ => "a", }; - self.tcx.struct_span_lint_hir(UNUSED_ATTRIBUTES, hir_id, attr.span, |lint| { - lint.build(&format!( - "`#[must_use]` has no effect when applied to {article} {target}" - )) - .emit(); - }); + self.tcx.emit_spanned_lint( + UNUSED_ATTRIBUTES, + hir_id, + attr.span, + errors::MustUseNoEffect { article, target }, + ); } // For now, its always valid @@ -1295,11 +1112,7 @@ impl CheckAttrVisitor<'_> { match target { Target::Struct | Target::Enum | Target::Union | Target::Trait => true, _ => { - self.tcx - .sess - .struct_span_err(attr.span, "`must_not_suspend` attribute should be applied to a struct, enum, or trait") - .span_label(span, "is not a struct, enum, or trait") - .emit(); + self.tcx.sess.emit_err(errors::MustNotSuspend { attr_span: attr.span, span }); false } } @@ -1319,16 +1132,12 @@ impl CheckAttrVisitor<'_> { _ => { // FIXME: #[cold] was previously allowed on non-functions and some crates used // this, so only emit a warning. - self.tcx.struct_span_lint_hir(UNUSED_ATTRIBUTES, hir_id, attr.span, |lint| { - lint.build("attribute should be applied to a function") - .warn( - "this was previously accepted by the compiler but is \ - being phased out; it will become a hard error in \ - a future release!", - ) - .span_label(span, "not a function") - .emit(); - }); + self.tcx.emit_spanned_lint( + UNUSED_ATTRIBUTES, + hir_id, + attr.span, + errors::Cold { span }, + ); } } } @@ -1343,19 +1152,12 @@ impl CheckAttrVisitor<'_> { return; } - self.tcx.struct_span_lint_hir(UNUSED_ATTRIBUTES, hir_id, attr.span, |lint| { - let mut diag = - lint.build("attribute should be applied to an `extern` block with non-Rust ABI"); - diag.warn( - "this was previously accepted by the compiler but is \ - being phased out; it will become a hard error in \ - a future release!", - ); - if target != Target::ForeignMod { - diag.span_label(span, "not an `extern` block"); - } - diag.emit(); - }); + self.tcx.emit_spanned_lint( + UNUSED_ATTRIBUTES, + hir_id, + attr.span, + errors::Link { span: (target != Target::ForeignMod).then_some(span) }, + ); } /// Checks if `#[link_name]` is applied to an item other than a foreign function or static. diff --git a/compiler/rustc_passes/src/errors.rs b/compiler/rustc_passes/src/errors.rs new file mode 100644 index 00000000000..f8e8720ab54 --- /dev/null +++ b/compiler/rustc_passes/src/errors.rs @@ -0,0 +1,362 @@ +use rustc_errors::{Applicability, MultiSpan}; +use rustc_macros::{LintDiagnostic, SessionDiagnostic}; +use rustc_span::{Span, Symbol}; + +#[derive(LintDiagnostic)] +#[lint(passes::outer_crate_level_attr)] +pub struct OuterCrateLevelAttr; + +#[derive(LintDiagnostic)] +#[lint(passes::inner_crate_level_attr)] +pub struct InnerCrateLevelAttr; + +#[derive(LintDiagnostic)] +#[lint(passes::ignored_attr_with_macro)] +pub struct IgnoredAttrWithMacro<'a> { + pub sym: &'a str, +} + +#[derive(LintDiagnostic)] +#[lint(passes::ignored_attr)] +pub struct IgnoredAttr<'a> { + pub sym: &'a str, +} + +#[derive(LintDiagnostic)] +#[lint(passes::inline_ignored_function_prototype)] +pub struct IgnoredInlineAttrFnProto; + +#[derive(LintDiagnostic)] +#[lint(passes::inline_ignored_constants)] +#[warn_] +#[note] +pub struct IgnoredInlineAttrConstants; + +#[derive(SessionDiagnostic)] +#[error(passes::inline_not_fn_or_closure, code = "E0518")] +pub struct InlineNotFnOrClosure { + #[primary_span] + pub attr_span: Span, + #[label] + pub defn_span: Span, +} + +#[derive(LintDiagnostic)] +#[lint(passes::no_coverage_ignored_function_prototype)] +pub struct IgnoredNoCoverageFnProto; + +#[derive(LintDiagnostic)] +#[lint(passes::no_coverage_propagate)] +pub struct IgnoredNoCoveragePropagate; + +#[derive(LintDiagnostic)] +#[lint(passes::no_coverage_fn_defn)] +pub struct IgnoredNoCoverageFnDefn; + +#[derive(SessionDiagnostic)] +#[error(passes::no_coverage_not_coverable, code = "E0788")] +pub struct IgnoredNoCoverageNotCoverable { + #[primary_span] + pub attr_span: Span, + #[label] + pub defn_span: Span, +} + +#[derive(SessionDiagnostic)] +#[error(passes::should_be_applied_to_fn)] +pub struct AttrShouldBeAppliedToFn { + #[primary_span] + pub attr_span: Span, + #[label] + pub defn_span: Span, +} + +#[derive(SessionDiagnostic)] +#[error(passes::naked_tracked_caller, code = "E0736")] +pub struct NakedTrackedCaller { + #[primary_span] + pub attr_span: Span, +} + +#[derive(SessionDiagnostic)] +#[error(passes::should_be_applied_to_fn, code = "E0739")] +pub struct TrackedCallerWrongLocation { + #[primary_span] + pub attr_span: Span, + #[label] + pub defn_span: Span, +} + +#[derive(SessionDiagnostic)] +#[error(passes::should_be_applied_to_struct_enum, code = "E0701")] +pub struct NonExhaustiveWrongLocation { + #[primary_span] + pub attr_span: Span, + #[label] + pub defn_span: Span, +} + +#[derive(SessionDiagnostic)] +#[error(passes::should_be_applied_to_trait)] +pub struct AttrShouldBeAppliedToTrait { + #[primary_span] + pub attr_span: Span, + #[label] + pub defn_span: Span, +} + +#[derive(LintDiagnostic)] +#[lint(passes::target_feature_on_statement)] +pub struct TargetFeatureOnStatement; + +#[derive(SessionDiagnostic)] +#[error(passes::should_be_applied_to_static)] +pub struct AttrShouldBeAppliedToStatic { + #[primary_span] + pub attr_span: Span, + #[label] + pub defn_span: Span, +} + +#[derive(SessionDiagnostic)] +#[error(passes::doc_expect_str)] +pub struct DocExpectStr<'a> { + #[primary_span] + pub attr_span: Span, + pub attr_name: &'a str, +} + +#[derive(SessionDiagnostic)] +#[error(passes::doc_alias_empty)] +pub struct DocAliasEmpty<'a> { + #[primary_span] + pub span: Span, + pub attr_str: &'a str, +} + +#[derive(SessionDiagnostic)] +#[error(passes::doc_alias_bad_char)] +pub struct DocAliasBadChar<'a> { + #[primary_span] + pub span: Span, + pub attr_str: &'a str, + pub char_: char, +} + +#[derive(SessionDiagnostic)] +#[error(passes::doc_alias_start_end)] +pub struct DocAliasStartEnd<'a> { + #[primary_span] + pub span: Span, + pub attr_str: &'a str, +} + +#[derive(SessionDiagnostic)] +#[error(passes::doc_alias_bad_location)] +pub struct DocAliasBadLocation<'a> { + #[primary_span] + pub span: Span, + pub attr_str: &'a str, + pub location: &'a str, +} + +#[derive(SessionDiagnostic)] +#[error(passes::doc_alias_not_an_alias)] +pub struct DocAliasNotAnAlias<'a> { + #[primary_span] + pub span: Span, + pub attr_str: &'a str, +} + +#[derive(LintDiagnostic)] +#[lint(passes::doc_alias_duplicated)] +pub struct DocAliasDuplicated { + #[label] + pub first_defn: Span, +} + +#[derive(SessionDiagnostic)] +#[error(passes::doc_alias_not_string_literal)] +pub struct DocAliasNotStringLiteral { + #[primary_span] + pub span: Span, +} + +#[derive(SessionDiagnostic)] +#[error(passes::doc_alias_malformed)] +pub struct DocAliasMalformed { + #[primary_span] + pub span: Span, +} + +#[derive(SessionDiagnostic)] +#[error(passes::doc_keyword_empty_mod)] +pub struct DocKeywordEmptyMod { + #[primary_span] + pub span: Span, +} + +#[derive(SessionDiagnostic)] +#[error(passes::doc_keyword_not_mod)] +pub struct DocKeywordNotMod { + #[primary_span] + pub span: Span, +} + +#[derive(SessionDiagnostic)] +#[error(passes::doc_keyword_invalid_ident)] +pub struct DocKeywordInvalidIdent { + #[primary_span] + pub span: Span, + pub doc_keyword: Symbol, +} + +#[derive(SessionDiagnostic)] +#[error(passes::doc_tuple_variadic_not_first)] +pub struct DocTupleVariadicNotFirst { + #[primary_span] + pub span: Span, +} + +#[derive(SessionDiagnostic)] +#[error(passes::doc_keyword_only_impl)] +pub struct DocKeywordOnlyImpl { + #[primary_span] + pub span: Span, +} + +#[derive(SessionDiagnostic)] +#[error(passes::doc_inline_conflict)] +#[help] +pub struct DocKeywordConflict { + #[primary_span] + pub spans: MultiSpan, +} + +#[derive(LintDiagnostic)] +#[lint(passes::doc_inline_only_use)] +#[note] +pub struct DocInlineOnlyUse { + #[label] + pub attr_span: Span, + #[label(passes::not_a_use_item_label)] + pub item_span: Option<Span>, +} + +#[derive(SessionDiagnostic)] +#[error(passes::doc_attr_not_crate_level)] +pub struct DocAttrNotCrateLevel<'a> { + #[primary_span] + pub span: Span, + pub attr_name: &'a str, +} + +#[derive(LintDiagnostic)] +#[lint(passes::doc_test_unknown)] +pub struct DocTestUnknown { + pub path: String, +} + +#[derive(LintDiagnostic)] +#[lint(passes::doc_test_takes_list)] +pub struct DocTestTakesList; + +#[derive(LintDiagnostic)] +#[lint(passes::doc_primitive)] +pub struct DocPrimitive; + +#[derive(LintDiagnostic)] +#[lint(passes::doc_test_unknown_any)] +pub struct DocTestUnknownAny { + pub path: String, +} + +#[derive(LintDiagnostic)] +#[lint(passes::doc_test_unknown_spotlight)] +#[note] +#[note(passes::no_op_note)] +pub struct DocTestUnknownSpotlight { + pub path: String, + #[suggestion_short(applicability = "machine-applicable", code = "notable_trait")] + pub span: Span, +} + +#[derive(LintDiagnostic)] +#[lint(passes::doc_test_unknown_include)] +pub struct DocTestUnknownInclude { + pub path: String, + pub value: String, + pub inner: &'static str, + #[suggestion(code = "#{inner}[doc = include_str!(\"{value}\")]")] + pub sugg: (Span, Applicability), +} + +#[derive(LintDiagnostic)] +#[lint(passes::doc_invalid)] +pub struct DocInvalid; + +#[derive(SessionDiagnostic)] +#[error(passes::pass_by_value)] +pub struct PassByValue { + #[primary_span] + pub attr_span: Span, + #[label] + pub span: Span, +} + +#[derive(SessionDiagnostic)] +#[error(passes::allow_incoherent_impl)] +pub struct AllowIncoherentImpl { + #[primary_span] + pub attr_span: Span, + #[label] + pub span: Span, +} + +#[derive(SessionDiagnostic)] +#[error(passes::has_incoherent_inherent_impl)] +pub struct HasIncoherentInherentImpl { + #[primary_span] + pub attr_span: Span, + #[label] + pub span: Span, +} + +#[derive(LintDiagnostic)] +#[lint(passes::must_use_async)] +pub struct MustUseAsync { + #[label] + pub span: Span, +} + +#[derive(LintDiagnostic)] +#[lint(passes::must_use_no_effect)] +pub struct MustUseNoEffect { + pub article: &'static str, + pub target: rustc_hir::Target, +} + +#[derive(SessionDiagnostic)] +#[error(passes::must_not_suspend)] +pub struct MustNotSuspend { + #[primary_span] + pub attr_span: Span, + #[label] + pub span: Span, +} + +#[derive(LintDiagnostic)] +#[lint(passes::cold)] +#[warn_] +pub struct Cold { + #[label] + pub span: Span, +} + +#[derive(LintDiagnostic)] +#[lint(passes::link)] +#[warn_] +pub struct Link { + #[label] + pub span: Option<Span>, +} diff --git a/compiler/rustc_passes/src/lib.rs b/compiler/rustc_passes/src/lib.rs index 497c0931c21..7b2f83958af 100644 --- a/compiler/rustc_passes/src/lib.rs +++ b/compiler/rustc_passes/src/lib.rs @@ -7,8 +7,8 @@ #![allow(rustc::potential_query_instability)] #![doc(html_root_url = "https://doc.rust-lang.org/nightly/nightly-rustc/")] #![feature(iter_intersperse)] -#![feature(let_else)] #![feature(let_chains)] +#![feature(let_else)] #![feature(map_try_insert)] #![feature(min_specialization)] #![feature(try_blocks)] @@ -27,6 +27,7 @@ pub mod dead; mod debugger_visualizer; mod diagnostic_items; pub mod entry; +mod errors; pub mod hir_id_validator; pub mod hir_stats; mod lang_items; diff --git a/compiler/rustc_privacy/src/errors.rs b/compiler/rustc_privacy/src/errors.rs index 482721d373a..b0fac91f6eb 100644 --- a/compiler/rustc_privacy/src/errors.rs +++ b/compiler/rustc_privacy/src/errors.rs @@ -1,4 +1,4 @@ -use rustc_macros::{SessionDiagnostic, SessionSubdiagnostic}; +use rustc_macros::{LintDiagnostic, SessionDiagnostic, SessionSubdiagnostic}; use rustc_span::{Span, Symbol}; #[derive(SessionDiagnostic)] @@ -73,3 +73,19 @@ pub struct InPublicInterface<'a> { #[label(privacy::visibility_label)] pub vis_span: Span, } + +#[derive(LintDiagnostic)] +#[lint(privacy::from_private_dep_in_public_interface)] +pub struct FromPrivateDependencyInPublicInterface<'a> { + pub kind: &'a str, + pub descr: String, + pub krate: Symbol, +} + +#[derive(LintDiagnostic)] +#[lint(privacy::private_in_public_lint)] +pub struct PrivateInPublicLint<'a> { + pub vis_descr: &'static str, + pub kind: &'a str, + pub descr: String, +} diff --git a/compiler/rustc_privacy/src/lib.rs b/compiler/rustc_privacy/src/lib.rs index 5b21c046647..9a835808d49 100644 --- a/compiler/rustc_privacy/src/lib.rs +++ b/compiler/rustc_privacy/src/lib.rs @@ -38,8 +38,8 @@ use std::ops::ControlFlow; use std::{cmp, fmt, mem}; use errors::{ - FieldIsPrivate, FieldIsPrivateLabel, InPublicInterface, InPublicInterfaceTraits, ItemIsPrivate, - UnnamedItemIsPrivate, + FieldIsPrivate, FieldIsPrivateLabel, FromPrivateDependencyInPublicInterface, InPublicInterface, + InPublicInterfaceTraits, ItemIsPrivate, PrivateInPublicLint, UnnamedItemIsPrivate, }; //////////////////////////////////////////////////////////////////////////////// @@ -1716,19 +1716,14 @@ impl SearchInterfaceForPrivateItemsVisitor<'_> { fn check_def_id(&mut self, def_id: DefId, kind: &str, descr: &dyn fmt::Display) -> bool { if self.leaks_private_dep(def_id) { - self.tcx.struct_span_lint_hir( + self.tcx.emit_spanned_lint( lint::builtin::EXPORTED_PRIVATE_DEPENDENCIES, self.tcx.hir().local_def_id_to_hir_id(self.item_def_id), self.tcx.def_span(self.item_def_id.to_def_id()), - |lint| { - lint.build(&format!( - "{} `{}` from private dependency '{}' in public \ - interface", - kind, - descr, - self.tcx.crate_name(def_id.krate) - )) - .emit(); + FromPrivateDependencyInPublicInterface { + kind, + descr: descr.to_string(), + krate: self.tcx.crate_name(def_id.krate), }, ); } @@ -1754,12 +1749,14 @@ impl SearchInterfaceForPrivateItemsVisitor<'_> { } }; let span = self.tcx.def_span(self.item_def_id.to_def_id()); + let descr = descr.to_string(); if self.has_old_errors || self.in_assoc_ty || self.tcx.resolutions(()).has_pub_restricted { let descr = descr.to_string(); - let vis_span = self.tcx.def_span(def_id); + let vis_span = + self.tcx.sess.source_map().guess_head_span(self.tcx.def_span(def_id)); if kind == "trait" { self.tcx.sess.emit_err(InPublicInterfaceTraits { span, @@ -1778,19 +1775,11 @@ impl SearchInterfaceForPrivateItemsVisitor<'_> { }); } } else { - let err_code = if kind == "trait" { "E0445" } else { "E0446" }; - self.tcx.struct_span_lint_hir( + self.tcx.emit_spanned_lint( lint::builtin::PRIVATE_IN_PUBLIC, hir_id, span, - |lint| { - lint.build(&format!( - "{} (error {})", - format!("{} {} `{}` in public interface", vis_descr, kind, descr), - err_code - )) - .emit(); - }, + PrivateInPublicLint { vis_descr, kind, descr }, ); } } diff --git a/compiler/rustc_session/src/code_stats.rs b/compiler/rustc_session/src/code_stats.rs index cbb03ffd7a0..eede4d16ea3 100644 --- a/compiler/rustc_session/src/code_stats.rs +++ b/compiler/rustc_session/src/code_stats.rs @@ -1,11 +1,12 @@ use rustc_data_structures::fx::FxHashSet; use rustc_data_structures::sync::Lock; +use rustc_span::Symbol; use rustc_target::abi::{Align, Size}; use std::cmp::{self, Ordering}; #[derive(Clone, PartialEq, Eq, Hash, Debug)] pub struct VariantInfo { - pub name: Option<String>, + pub name: Option<Symbol>, pub kind: SizeKind, pub size: u64, pub align: u64, @@ -20,7 +21,7 @@ pub enum SizeKind { #[derive(Clone, PartialEq, Eq, Hash, Debug)] pub struct FieldInfo { - pub name: String, + pub name: Symbol, pub offset: u64, pub size: u64, pub align: u64, @@ -119,7 +120,7 @@ impl CodeStats { let VariantInfo { ref name, kind: _, align: _, size, ref fields } = *variant_info; let indent = if !struct_like { let name = match name.as_ref() { - Some(name) => name.to_owned(), + Some(name) => name.to_string(), None => i.to_string(), }; println!( diff --git a/compiler/rustc_trait_selection/src/traits/error_reporting/mod.rs b/compiler/rustc_trait_selection/src/traits/error_reporting/mod.rs index c1af1a05972..8a679ca005f 100644 --- a/compiler/rustc_trait_selection/src/traits/error_reporting/mod.rs +++ b/compiler/rustc_trait_selection/src/traits/error_reporting/mod.rs @@ -23,7 +23,7 @@ use rustc_hir::GenericParam; use rustc_hir::Item; use rustc_hir::Node; use rustc_infer::infer::error_reporting::same_type_modulo_infer; -use rustc_infer::traits::{AmbiguousSelection, TraitEngine}; +use rustc_infer::traits::TraitEngine; use rustc_middle::traits::select::OverflowError; use rustc_middle::ty::abstract_const::NotConstEvaluatable; use rustc_middle::ty::error::ExpectedFound; @@ -1403,7 +1403,7 @@ trait InferCtxtPrivExt<'hir, 'tcx> { fn annotate_source_of_ambiguity( &self, err: &mut Diagnostic, - impls: &[AmbiguousSelection], + impls: &[DefId], predicate: ty::Predicate<'tcx>, ); @@ -2036,14 +2036,6 @@ impl<'a, 'tcx> InferCtxtPrivExt<'a, 'tcx> for InferCtxt<'a, 'tcx> { ); match selcx.select_from_obligation(&obligation) { Err(SelectionError::Ambiguous(impls)) if impls.len() > 1 => { - if self.is_tainted_by_errors() && subst.is_none() { - // If `subst.is_none()`, then this is probably two param-env - // candidates or impl candidates that are equal modulo lifetimes. - // Therefore, if we've already emitted an error, just skip this - // one, since it's not particularly actionable. - err.cancel(); - return; - } self.annotate_source_of_ambiguity(&mut err, &impls, predicate); } _ => { @@ -2224,35 +2216,24 @@ impl<'a, 'tcx> InferCtxtPrivExt<'a, 'tcx> for InferCtxt<'a, 'tcx> { fn annotate_source_of_ambiguity( &self, err: &mut Diagnostic, - impls: &[AmbiguousSelection], + impls: &[DefId], predicate: ty::Predicate<'tcx>, ) { let mut spans = vec![]; let mut crates = vec![]; let mut post = vec![]; - let mut or_where_clause = false; - for ambig in impls { - match ambig { - AmbiguousSelection::Impl(def_id) => match self.tcx.span_of_impl(*def_id) { - Ok(span) => spans.push(span), - Err(name) => { - crates.push(name); - if let Some(header) = to_pretty_impl_header(self.tcx, *def_id) { - post.push(header); - } + for def_id in impls { + match self.tcx.span_of_impl(*def_id) { + Ok(span) => spans.push(span), + Err(name) => { + crates.push(name); + if let Some(header) = to_pretty_impl_header(self.tcx, *def_id) { + post.push(header); } - }, - AmbiguousSelection::ParamEnv(span) => { - or_where_clause = true; - spans.push(*span); } } } - let msg = format!( - "multiple `impl`s{} satisfying `{}` found", - if or_where_clause { " or `where` clauses" } else { "" }, - predicate - ); + let msg = format!("multiple `impl`s satisfying `{}` found", predicate); let mut crate_names: Vec<_> = crates.iter().map(|n| format!("`{}`", n)).collect(); crate_names.sort(); crate_names.dedup(); diff --git a/compiler/rustc_trait_selection/src/traits/select/candidate_assembly.rs b/compiler/rustc_trait_selection/src/traits/select/candidate_assembly.rs index 96d83deeeb7..6e8581128dd 100644 --- a/compiler/rustc_trait_selection/src/traits/select/candidate_assembly.rs +++ b/compiler/rustc_trait_selection/src/traits/select/candidate_assembly.rs @@ -6,11 +6,9 @@ //! //! [rustc dev guide]:https://rustc-dev-guide.rust-lang.org/traits/resolution.html#candidate-assembly use hir::LangItem; -use rustc_data_structures::fx::FxHashMap; use rustc_hir as hir; use rustc_hir::def_id::DefId; -use rustc_infer::traits::util::elaborate_predicates_with_span; -use rustc_infer::traits::{AmbiguousSelection, TraitEngine}; +use rustc_infer::traits::TraitEngine; use rustc_infer::traits::{Obligation, SelectionError, TraitObligation}; use rustc_lint_defs::builtin::DEREF_INTO_DYN_SUPERTRAIT; use rustc_middle::ty::print::with_no_trimmed_paths; @@ -201,48 +199,11 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> { // and report ambiguity. if i > 1 { debug!("multiple matches, ambig"); - - // Collect a list of (probable) spans that point to a param-env candidate - let tcx = self.infcx.tcx; - let owner = stack.obligation.cause.body_id.owner.to_def_id(); - let predicates = tcx.predicates_of(owner).instantiate_identity(tcx); - let param_env_spans: FxHashMap<_, _> = elaborate_predicates_with_span( - tcx, - std::iter::zip(predicates.predicates, predicates.spans), - ) - .filter_map(|obligation| { - let kind = obligation.predicate.kind(); - if let ty::PredicateKind::Trait(trait_pred) = kind.skip_binder() { - if trait_pred.trait_ref - == ty::TraitRef::identity(tcx, trait_pred.def_id()) - .skip_binder() - { - // HACK: Remap the `Self: Trait` predicate that every trait has to a more useful span - Some(( - kind.rebind(trait_pred), - tcx.def_span(trait_pred.def_id()), - )) - } else { - Some((kind.rebind(trait_pred), obligation.cause.span)) - } - } else { - None - } - }) - .collect(); - return Err(Ambiguous( candidates .into_iter() .filter_map(|c| match c.candidate { - SelectionCandidate::ImplCandidate(def_id) => { - Some(AmbiguousSelection::Impl(def_id)) - } - SelectionCandidate::ParamCandidate(predicate) => { - Some(AmbiguousSelection::ParamEnv( - *param_env_spans.get(&predicate)?, - )) - } + SelectionCandidate::ImplCandidate(def_id) => Some(def_id), _ => None, }) .collect(), diff --git a/compiler/rustc_typeck/src/astconv/mod.rs b/compiler/rustc_typeck/src/astconv/mod.rs index c3205aeb074..9e4da058052 100644 --- a/compiler/rustc_typeck/src/astconv/mod.rs +++ b/compiler/rustc_typeck/src/astconv/mod.rs @@ -2486,7 +2486,7 @@ impl<'o, 'tcx> dyn AstConv<'tcx> + 'o { concrete type's name `{type_name}` instead if you want to \ specify its type parameters" ), - type_name.to_string(), + type_name, Applicability::MaybeIncorrect, ); } diff --git a/compiler/rustc_typeck/src/check/compare_method.rs b/compiler/rustc_typeck/src/check/compare_method.rs index 1f921ca8358..a53217ef818 100644 --- a/compiler/rustc_typeck/src/check/compare_method.rs +++ b/compiler/rustc_typeck/src/check/compare_method.rs @@ -544,7 +544,7 @@ fn compare_self_type<'tcx>( if let Some(span) = tcx.hir().span_if_local(trait_m.def_id) { err.span_label(span, format!("trait method declared without `{self_descr}`")); } else { - err.note_trait_signature(trait_m.name.to_string(), trait_m.signature(tcx)); + err.note_trait_signature(trait_m.name, trait_m.signature(tcx)); } let reported = err.emit(); return Err(reported); @@ -564,7 +564,7 @@ fn compare_self_type<'tcx>( if let Some(span) = tcx.hir().span_if_local(trait_m.def_id) { err.span_label(span, format!("`{self_descr}` used in trait")); } else { - err.note_trait_signature(trait_m.name.to_string(), trait_m.signature(tcx)); + err.note_trait_signature(trait_m.name, trait_m.signature(tcx)); } let reported = err.emit(); return Err(reported); @@ -803,7 +803,7 @@ fn compare_number_of_method_arguments<'tcx>( ), ); } else { - err.note_trait_signature(trait_m.name.to_string(), trait_m.signature(tcx)); + err.note_trait_signature(trait_m.name, trait_m.signature(tcx)); } err.span_label( impl_span, diff --git a/compiler/rustc_typeck/src/check/expr.rs b/compiler/rustc_typeck/src/check/expr.rs index b52cb8e99d1..02e493f7258 100644 --- a/compiler/rustc_typeck/src/check/expr.rs +++ b/compiler/rustc_typeck/src/check/expr.rs @@ -1856,7 +1856,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { let remaining_private_fields_len = remaining_private_fields.len(); let names = match &remaining_private_fields .iter() - .map(|(name, _, _)| name.to_string()) + .map(|(name, _, _)| name) .collect::<Vec<_>>()[..] { _ if remaining_private_fields_len > 6 => String::new(), diff --git a/compiler/rustc_typeck/src/check/method/suggest.rs b/compiler/rustc_typeck/src/check/method/suggest.rs index 7bf167426f7..7f96e421a9a 100644 --- a/compiler/rustc_typeck/src/check/method/suggest.rs +++ b/compiler/rustc_typeck/src/check/method/suggest.rs @@ -19,6 +19,7 @@ use rustc_middle::ty::print::with_crate_prefix; use rustc_middle::ty::ToPolyTraitRef; use rustc_middle::ty::{self, DefIdTree, ToPredicate, Ty, TyCtxt, TypeVisitable}; use rustc_span::symbol::{kw, sym, Ident}; +use rustc_span::Symbol; use rustc_span::{lev_distance, source_map, ExpnKind, FileName, MacroKind, Span}; use rustc_trait_selection::traits::error_reporting::on_unimplemented::InferCtxtExt as _; use rustc_trait_selection::traits::query::evaluate_obligation::InferCtxtExt as _; @@ -1548,7 +1549,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { Option<ObligationCause<'tcx>>, )], ) { - let mut derives = Vec::<(String, Span, String)>::new(); + let mut derives = Vec::<(String, Span, Symbol)>::new(); let mut traits = Vec::<Span>::new(); for (pred, _, _) in unsatisfied_predicates { let ty::PredicateKind::Trait(trait_pred) = pred.kind().skip_binder() else { continue }; @@ -1581,12 +1582,12 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { derives.push(( self_name.clone(), self_span, - parent_diagnostic_name.to_string(), + parent_diagnostic_name, )); } } } - derives.push((self_name, self_span, diagnostic_name.to_string())); + derives.push((self_name, self_span, diagnostic_name)); } else { traits.push(self.tcx.def_span(trait_pred.def_id())); } @@ -1609,7 +1610,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { continue; } } - derives_grouped.push((self_name, self_span, trait_name)); + derives_grouped.push((self_name, self_span, trait_name.to_string())); } let len = traits.len(); diff --git a/compiler/rustc_typeck/src/check/mod.rs b/compiler/rustc_typeck/src/check/mod.rs index d6160266dd7..849e96445d3 100644 --- a/compiler/rustc_typeck/src/check/mod.rs +++ b/compiler/rustc_typeck/src/check/mod.rs @@ -25,7 +25,7 @@ can be broken down into several distinct phases: - regionck: after main is complete, the regionck pass goes over all types looking for regions and making sure that they did not escape - into places they are not in scope. This may also influence the + into places where they are not in scope. This may also influence the final assignments of the various region variables if there is some flexibility. diff --git a/compiler/rustc_typeck/src/impl_wf_check.rs b/compiler/rustc_typeck/src/impl_wf_check.rs index e7ca70de4ba..8c26c96816d 100644 --- a/compiler/rustc_typeck/src/impl_wf_check.rs +++ b/compiler/rustc_typeck/src/impl_wf_check.rs @@ -17,7 +17,7 @@ use rustc_hir::def::DefKind; use rustc_hir::def_id::LocalDefId; use rustc_middle::ty::query::Providers; use rustc_middle::ty::{self, TyCtxt, TypeVisitable}; -use rustc_span::Span; +use rustc_span::{Span, Symbol}; use std::collections::hash_map::Entry::{Occupied, Vacant}; @@ -123,12 +123,7 @@ fn enforce_impl_params_are_constrained(tcx: TyCtxt<'_>, impl_def_id: LocalDefId) ty::GenericParamDefKind::Type { .. } => { let param_ty = ty::ParamTy::for_def(param); if !input_parameters.contains(&cgp::Parameter::from(param_ty)) { - report_unused_parameter( - tcx, - tcx.def_span(param.def_id), - "type", - ¶m_ty.to_string(), - ); + report_unused_parameter(tcx, tcx.def_span(param.def_id), "type", param_ty.name); } } ty::GenericParamDefKind::Lifetime => { @@ -140,7 +135,7 @@ fn enforce_impl_params_are_constrained(tcx: TyCtxt<'_>, impl_def_id: LocalDefId) tcx, tcx.def_span(param.def_id), "lifetime", - ¶m.name.to_string(), + param.name, ); } } @@ -151,7 +146,7 @@ fn enforce_impl_params_are_constrained(tcx: TyCtxt<'_>, impl_def_id: LocalDefId) tcx, tcx.def_span(param.def_id), "const", - ¶m_ct.to_string(), + param_ct.name, ); } } @@ -178,7 +173,7 @@ fn enforce_impl_params_are_constrained(tcx: TyCtxt<'_>, impl_def_id: LocalDefId) // used elsewhere are not projected back out. } -fn report_unused_parameter(tcx: TyCtxt<'_>, span: Span, kind: &str, name: &str) { +fn report_unused_parameter(tcx: TyCtxt<'_>, span: Span, kind: &str, name: Symbol) { let mut err = struct_span_err!( tcx.sess, span, |
