From e8d4fb8aaafa598d3021f2378705f780ee173458 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Esteban=20K=C3=BCber?= Date: Wed, 18 Oct 2023 22:54:35 +0000 Subject: [PATCH 01/13] Suggest relaxing implicit `type Assoc: Sized;` bound Fix #85378. --- .../src/traits/error_reporting/suggestions.rs | 23 +++++++++++++++++++ .../assoc_type_bounds_implicit_sized.fixed | 10 ++++++++ .../assoc_type_bounds_implicit_sized.rs | 10 ++++++++ .../assoc_type_bounds_implicit_sized.stderr | 20 ++++++++++++++++ .../assoc_type_bounds_sized_used.stderr | 4 ++++ 5 files changed, 67 insertions(+) create mode 100644 tests/ui/object-safety/assoc_type_bounds_implicit_sized.fixed create mode 100644 tests/ui/object-safety/assoc_type_bounds_implicit_sized.rs create mode 100644 tests/ui/object-safety/assoc_type_bounds_implicit_sized.stderr diff --git a/compiler/rustc_trait_selection/src/traits/error_reporting/suggestions.rs b/compiler/rustc_trait_selection/src/traits/error_reporting/suggestions.rs index 78f7f915f7269..8f1ebc24b9455 100644 --- a/compiler/rustc_trait_selection/src/traits/error_reporting/suggestions.rs +++ b/compiler/rustc_trait_selection/src/traits/error_reporting/suggestions.rs @@ -2652,6 +2652,29 @@ impl<'tcx> TypeErrCtxtExt<'tcx> for TypeErrCtxt<'_, 'tcx> { // Check for foreign traits being reachable. self.tcx.visible_parent_map(()).get(&def_id).is_some() }; + if Some(def_id) == self.tcx.lang_items().sized_trait() + && let Some(hir::Node::TraitItem(hir::TraitItem { + ident, + kind: hir::TraitItemKind::Type(bounds, None), + .. + })) = tcx.hir().get_if_local(item_def_id) + // Do not suggest relaxing if there is an explicit `Sized` obligation. + && !bounds.iter() + .filter_map(|bound| bound.trait_ref()) + .any(|tr| tr.trait_def_id() == self.tcx.lang_items().sized_trait()) + { + let (span, separator) = if let [.., last] = bounds { + (last.span().shrink_to_hi(), " +") + } else { + (ident.span.shrink_to_hi(), ":") + }; + err.span_suggestion_verbose( + span, + "consider relaxing the implicit `Sized` restriction", + format!("{separator} ?Sized"), + Applicability::MachineApplicable, + ); + } if let DefKind::Trait = tcx.def_kind(item_def_id) && !visible_item { diff --git a/tests/ui/object-safety/assoc_type_bounds_implicit_sized.fixed b/tests/ui/object-safety/assoc_type_bounds_implicit_sized.fixed new file mode 100644 index 0000000000000..45c7e07a26471 --- /dev/null +++ b/tests/ui/object-safety/assoc_type_bounds_implicit_sized.fixed @@ -0,0 +1,10 @@ +// run-rustfix +trait TraitWithAType { + type Item: ?Sized; +} +trait Trait {} +struct A {} +impl TraitWithAType for A { + type Item = dyn Trait; //~ ERROR E0277 +} +fn main() {} diff --git a/tests/ui/object-safety/assoc_type_bounds_implicit_sized.rs b/tests/ui/object-safety/assoc_type_bounds_implicit_sized.rs new file mode 100644 index 0000000000000..c3e958f498390 --- /dev/null +++ b/tests/ui/object-safety/assoc_type_bounds_implicit_sized.rs @@ -0,0 +1,10 @@ +// run-rustfix +trait TraitWithAType { + type Item; +} +trait Trait {} +struct A {} +impl TraitWithAType for A { + type Item = dyn Trait; //~ ERROR E0277 +} +fn main() {} diff --git a/tests/ui/object-safety/assoc_type_bounds_implicit_sized.stderr b/tests/ui/object-safety/assoc_type_bounds_implicit_sized.stderr new file mode 100644 index 0000000000000..110e715073371 --- /dev/null +++ b/tests/ui/object-safety/assoc_type_bounds_implicit_sized.stderr @@ -0,0 +1,20 @@ +error[E0277]: the size for values of type `(dyn Trait + 'static)` cannot be known at compilation time + --> $DIR/assoc_type_bounds_implicit_sized.rs:8:17 + | +LL | type Item = dyn Trait; + | ^^^^^^^^^ doesn't have a size known at compile-time + | + = help: the trait `Sized` is not implemented for `(dyn Trait + 'static)` +note: required by a bound in `TraitWithAType::Item` + --> $DIR/assoc_type_bounds_implicit_sized.rs:3:5 + | +LL | type Item; + | ^^^^^^^^^^ required by this bound in `TraitWithAType::Item` +help: consider relaxing the implicit `Sized` restriction + | +LL | type Item: ?Sized; + | ++++++++ + +error: aborting due to previous error + +For more information about this error, try `rustc --explain E0277`. diff --git a/tests/ui/object-safety/assoc_type_bounds_sized_used.stderr b/tests/ui/object-safety/assoc_type_bounds_sized_used.stderr index 224d33fb2da18..b67a1244eceab 100644 --- a/tests/ui/object-safety/assoc_type_bounds_sized_used.stderr +++ b/tests/ui/object-safety/assoc_type_bounds_sized_used.stderr @@ -33,6 +33,10 @@ help: consider removing the `?Sized` bound to make the type parameter `Sized` LL - fn bop() { LL + fn bop() { | +help: consider relaxing the implicit `Sized` restriction + | +LL | type Bar: Default + ?Sized + | ++++++++ error: aborting due to 2 previous errors From 6ed2a76bcc2a963c28080d6ee3ad928ec9367a03 Mon Sep 17 00:00:00 2001 From: "Celina G. Val" Date: Thu, 19 Oct 2023 17:06:53 -0700 Subject: [PATCH 02/13] Add stable Instance::body() and RustcInternal trait The `Instance::body()` returns a monomorphized body. For that, we had to implement visitor that monomorphize types and constants. We are also introducing the RustcInternal trait that will allow us to convert back from Stable to Internal. Note that this trait is not yet visible for our users as it depends on Tables. We should probably add a new trait that can be exposed. --- .../rustc_smir/src/rustc_internal/internal.rs | 61 +++++++++++++++++++ compiler/rustc_smir/src/rustc_internal/mod.rs | 10 +++ compiler/rustc_smir/src/rustc_smir/builder.rs | 55 +++++++++++++++++ compiler/rustc_smir/src/rustc_smir/mod.rs | 22 +++++-- compiler/stable_mir/src/error.rs | 7 +++ compiler/stable_mir/src/lib.rs | 4 ++ compiler/stable_mir/src/mir/body.rs | 27 +++++++- compiler/stable_mir/src/mir/mono.rs | 11 +++- compiler/stable_mir/src/ty.rs | 2 + .../{instance.rs => check_instance.rs} | 26 +++++++- 10 files changed, 218 insertions(+), 7 deletions(-) create mode 100644 compiler/rustc_smir/src/rustc_internal/internal.rs create mode 100644 compiler/rustc_smir/src/rustc_smir/builder.rs rename tests/ui-fulldeps/stable-mir/{instance.rs => check_instance.rs} (73%) diff --git a/compiler/rustc_smir/src/rustc_internal/internal.rs b/compiler/rustc_smir/src/rustc_internal/internal.rs new file mode 100644 index 0000000000000..f42a973932065 --- /dev/null +++ b/compiler/rustc_smir/src/rustc_internal/internal.rs @@ -0,0 +1,61 @@ +//! Module containing the translation from stable mir constructs to the rustc counterpart. +//! +//! This module will only include a few constructs to allow users to invoke internal rustc APIs +//! due to incomplete stable coverage. + +// Prefer importing stable_mir over internal rustc constructs to make this file more readable. +use crate::rustc_smir::{MaybeStable, Tables}; +use rustc_middle::ty::{self as rustc_ty, Ty as InternalTy}; +use stable_mir::ty::{Const, GenericArgKind, GenericArgs, Region, Ty}; +use stable_mir::DefId; + +use super::RustcInternal; + +impl<'tcx> RustcInternal<'tcx> for DefId { + type T = rustc_span::def_id::DefId; + fn internal(&self, tables: &mut Tables<'tcx>) -> Self::T { + tables.def_ids[*self] + } +} + +impl<'tcx> RustcInternal<'tcx> for GenericArgs { + type T = rustc_ty::GenericArgsRef<'tcx>; + fn internal(&self, tables: &mut Tables<'tcx>) -> Self::T { + tables.tcx.mk_args_from_iter(self.0.iter().map(|arg| arg.internal(tables))) + } +} + +impl<'tcx> RustcInternal<'tcx> for GenericArgKind { + type T = rustc_ty::GenericArg<'tcx>; + fn internal(&self, tables: &mut Tables<'tcx>) -> Self::T { + match self { + GenericArgKind::Lifetime(reg) => reg.internal(tables).into(), + GenericArgKind::Type(ty) => ty.internal(tables).into(), + GenericArgKind::Const(cnst) => cnst.internal(tables).into(), + } + } +} + +impl<'tcx> RustcInternal<'tcx> for Region { + type T = rustc_ty::Region<'tcx>; + fn internal(&self, _tables: &mut Tables<'tcx>) -> Self::T { + todo!() + } +} + +impl<'tcx> RustcInternal<'tcx> for Ty { + type T = InternalTy<'tcx>; + fn internal(&self, tables: &mut Tables<'tcx>) -> Self::T { + match tables.types[self.0] { + MaybeStable::Stable(_) => todo!(), + MaybeStable::Rustc(ty) => ty, + } + } +} + +impl<'tcx> RustcInternal<'tcx> for Const { + type T = rustc_ty::Const<'tcx>; + fn internal(&self, _tables: &mut Tables<'tcx>) -> Self::T { + todo!() + } +} diff --git a/compiler/rustc_smir/src/rustc_internal/mod.rs b/compiler/rustc_smir/src/rustc_internal/mod.rs index 5ea805e5739b5..473a59f750a7e 100644 --- a/compiler/rustc_smir/src/rustc_internal/mod.rs +++ b/compiler/rustc_smir/src/rustc_internal/mod.rs @@ -20,6 +20,8 @@ use std::fmt::Debug; use std::hash::Hash; use std::ops::{ControlFlow, Index}; +mod internal; + impl<'tcx> Index for Tables<'tcx> { type Output = DefId; @@ -231,3 +233,11 @@ impl Index { + type T; + fn internal(&self, tables: &mut Tables<'tcx>) -> Self::T; +} diff --git a/compiler/rustc_smir/src/rustc_smir/builder.rs b/compiler/rustc_smir/src/rustc_smir/builder.rs new file mode 100644 index 0000000000000..8ff3958da7bd9 --- /dev/null +++ b/compiler/rustc_smir/src/rustc_smir/builder.rs @@ -0,0 +1,55 @@ +//! Logic required to produce a monomorphic stable body. +//! +//! We first retrieve and monomorphize the rustc body representation, i.e., we generate a +//! monomorphic body using internal representation. +//! After that, we convert the internal representation into a stable one. +use crate::rustc_smir::{Stable, Tables}; +use rustc_middle::mir; +use rustc_middle::mir::visit::MutVisitor; +use rustc_middle::ty::{self, Ty, TyCtxt}; + +/// Builds a monomorphic body for a given instance. +pub struct BodyBuilder<'tcx> { + tcx: TyCtxt<'tcx>, + instance: ty::Instance<'tcx>, +} + +impl<'tcx> BodyBuilder<'tcx> { + pub fn new(tcx: TyCtxt<'tcx>, instance: ty::Instance<'tcx>) -> Self { + BodyBuilder { tcx, instance } + } + + pub fn build(mut self, tables: &mut Tables<'tcx>) -> stable_mir::mir::Body { + let mut body = self.tcx.instance_mir(self.instance.def).clone(); + let generics = self.tcx.generics_of(self.instance.def_id()); + if generics.requires_monomorphization(self.tcx) { + self.visit_body(&mut body); + } + body.stable(tables) + } + + fn monomorphize(&self, value: T) -> T + where + T: ty::TypeFoldable>, + { + self.instance.instantiate_mir_and_normalize_erasing_regions( + self.tcx, + ty::ParamEnv::reveal_all(), + ty::EarlyBinder::bind(value), + ) + } +} + +impl<'tcx> MutVisitor<'tcx> for BodyBuilder<'tcx> { + fn visit_ty_const(&mut self, ct: &mut ty::Const<'tcx>, _location: mir::Location) { + *ct = self.monomorphize(*ct); + } + + fn visit_ty(&mut self, ty: &mut Ty<'tcx>, _: mir::visit::TyContext) { + *ty = self.monomorphize(*ty); + } + + fn tcx(&self) -> TyCtxt<'tcx> { + self.tcx + } +} diff --git a/compiler/rustc_smir/src/rustc_smir/mod.rs b/compiler/rustc_smir/src/rustc_smir/mod.rs index 94dc15b4767c1..604dc3582b53a 100644 --- a/compiler/rustc_smir/src/rustc_smir/mod.rs +++ b/compiler/rustc_smir/src/rustc_smir/mod.rs @@ -7,7 +7,7 @@ //! //! For now, we are developing everything inside `rustc`, thus, we keep this module private. -use crate::rustc_internal::IndexMap; +use crate::rustc_internal::{IndexMap, RustcInternal}; use crate::rustc_smir::hir::def::DefKind; use crate::rustc_smir::stable_mir::ty::{BoundRegion, EarlyBoundRegion, Region}; use rustc_hir as hir; @@ -26,6 +26,7 @@ use stable_mir::{self, opaque, Context, Filename}; use tracing::debug; mod alloc; +mod builder; impl<'tcx> Context for Tables<'tcx> { fn local_crate(&self) -> stable_mir::Crate { @@ -171,8 +172,9 @@ impl<'tcx> Context for Tables<'tcx> { } } - fn instance_body(&mut self, _def: InstanceDef) -> Body { - todo!("Monomorphize the body") + fn instance_body(&mut self, def: InstanceDef) -> Body { + let instance = self.instances[def]; + builder::BodyBuilder::new(self.tcx, instance).build(self) } fn instance_ty(&mut self, def: InstanceDef) -> stable_mir::ty::Ty { @@ -195,9 +197,21 @@ impl<'tcx> Context for Tables<'tcx> { let def_id = self[def_id]; let generics = self.tcx.generics_of(def_id); let result = generics.requires_monomorphization(self.tcx); - println!("req {result}: {def_id:?}"); result } + + fn resolve_instance( + &mut self, + def: stable_mir::ty::FnDef, + args: &stable_mir::ty::GenericArgs, + ) -> Option { + let def_id = def.0.internal(self); + let args_ref = args.internal(self); + match Instance::resolve(self.tcx, ParamEnv::reveal_all(), def_id, args_ref) { + Ok(Some(instance)) => Some(instance.stable(self)), + Ok(None) | Err(_) => None, + } + } } #[derive(Clone)] diff --git a/compiler/stable_mir/src/error.rs b/compiler/stable_mir/src/error.rs index 12ac8f1ca65ab..1991069145628 100644 --- a/compiler/stable_mir/src/error.rs +++ b/compiler/stable_mir/src/error.rs @@ -4,6 +4,7 @@ //! - [CompilerError]: This represents errors that can be raised when invoking the compiler. //! - [Error]: Generic error that represents the reason why a request that could not be fulfilled. +use std::convert::From; use std::fmt::{Debug, Display, Formatter}; use std::{error, fmt}; @@ -31,6 +32,12 @@ impl Error { } } +impl From<&str> for Error { + fn from(value: &str) -> Self { + Self(value.into()) + } +} + impl Display for Error { fn fmt(&self, f: &mut Formatter<'_>) -> fmt::Result { Display::fmt(&self.0, f) diff --git a/compiler/stable_mir/src/lib.rs b/compiler/stable_mir/src/lib.rs index 59af3f64ad342..be5ccac78c7c6 100644 --- a/compiler/stable_mir/src/lib.rs +++ b/compiler/stable_mir/src/lib.rs @@ -39,6 +39,7 @@ pub mod visitor; pub use error::*; use mir::mono::Instance; +use ty::{FnDef, GenericArgs}; /// Use String for now but we should replace it. pub type Symbol = String; @@ -233,6 +234,9 @@ pub trait Context { /// Item requires monomorphization. fn requires_monomorphization(&self, def_id: DefId) -> bool; + + /// Resolve an instance from the given function definition and generic arguments. + fn resolve_instance(&mut self, def: FnDef, args: &GenericArgs) -> Option; } // A thread local variable that stores a pointer to the tables mapping between TyCtxt diff --git a/compiler/stable_mir/src/mir/body.rs b/compiler/stable_mir/src/mir/body.rs index 72f026ee8de09..46fa8f4d922a7 100644 --- a/compiler/stable_mir/src/mir/body.rs +++ b/compiler/stable_mir/src/mir/body.rs @@ -5,9 +5,11 @@ use crate::{ty::Ty, Span}; #[derive(Clone, Debug)] pub struct Body { pub blocks: Vec, - pub locals: Vec, + pub locals: LocalDecls, } +type LocalDecls = Vec; + #[derive(Clone, Debug)] pub struct LocalDecl { pub ty: Ty, @@ -344,6 +346,7 @@ pub enum Operand { #[derive(Clone, Debug)] pub struct Place { pub local: Local, + /// projection out of a place (access a field, deref a pointer, etc) pub projection: String, } @@ -462,3 +465,25 @@ pub enum NullOp { /// Returns the offset of a field. OffsetOf(Vec), } + +impl Operand { + pub fn ty(&self, locals: &LocalDecls) -> Ty { + match self { + Operand::Copy(place) | Operand::Move(place) => place.ty(locals), + Operand::Constant(c) => c.ty(), + } + } +} + +impl Constant { + pub fn ty(&self) -> Ty { + self.literal.ty + } +} + +impl Place { + pub fn ty(&self, locals: &LocalDecls) -> Ty { + let _start_ty = locals[self.local].ty; + todo!("Implement projection") + } +} diff --git a/compiler/stable_mir/src/mir/mono.rs b/compiler/stable_mir/src/mir/mono.rs index d8e8ccb045480..997576fc7cbf0 100644 --- a/compiler/stable_mir/src/mir/mono.rs +++ b/compiler/stable_mir/src/mir/mono.rs @@ -1,5 +1,5 @@ use crate::mir::Body; -use crate::ty::{IndexedVal, Ty}; +use crate::ty::{FnDef, GenericArgs, IndexedVal, Ty}; use crate::{with, CrateItem, DefId, Error, Opaque}; use std::fmt::Debug; @@ -41,6 +41,15 @@ impl Instance { pub fn ty(&self) -> Ty { with(|context| context.instance_ty(self.def)) } + + /// Resolve an instance starting from a function definition and generic arguments. + pub fn resolve(def: FnDef, args: &GenericArgs) -> Result { + with(|context| { + context.resolve_instance(def, args).ok_or_else(|| { + crate::Error::new(format!("Failed to resolve `{def:?}` with `{args:?}`")) + }) + }) + } } /// Try to convert a crate item into an instance. diff --git a/compiler/stable_mir/src/ty.rs b/compiler/stable_mir/src/ty.rs index 003045a4696d5..440c9a1f031c2 100644 --- a/compiler/stable_mir/src/ty.rs +++ b/compiler/stable_mir/src/ty.rs @@ -225,6 +225,8 @@ pub struct ImplDef(pub DefId); #[derive(Clone, PartialEq, Eq, Debug)] pub struct RegionDef(pub DefId); +/// A list of generic arguments. +/// The second field is for internal usage to allow retrieving the internal representation. #[derive(Clone, Debug)] pub struct GenericArgs(pub Vec); diff --git a/tests/ui-fulldeps/stable-mir/instance.rs b/tests/ui-fulldeps/stable-mir/check_instance.rs similarity index 73% rename from tests/ui-fulldeps/stable-mir/instance.rs rename to tests/ui-fulldeps/stable-mir/check_instance.rs index fe06d9b5cc967..288c163a6a3fa 100644 --- a/tests/ui-fulldeps/stable-mir/instance.rs +++ b/tests/ui-fulldeps/stable-mir/check_instance.rs @@ -15,7 +15,8 @@ extern crate rustc_smir; extern crate stable_mir; use rustc_middle::ty::TyCtxt; - +use mir::{mono::Instance, TerminatorKind::*}; +use stable_mir::ty::{TyKind, RigidTy}; use stable_mir::*; use rustc_smir::rustc_internal; use std::io::Write; @@ -43,9 +44,28 @@ fn test_stable_mir(_tcx: TyCtxt<'_>) -> ControlFlow<()> { // For all generic items, try_from should fail. assert!(generic.iter().all(|item| mir::mono::Instance::try_from(*item).is_err())); + for instance in instances { + test_body(instance.body()) + } ControlFlow::Continue(()) } +/// Inspect the instance body +fn test_body(body: mir::Body) { + for term in body.blocks.iter().map(|bb| &bb.terminator) { + match &term.kind { + Call{ func, .. } => { + let TyKind::RigidTy(ty) = func.ty(&body.locals).kind() else { unreachable!() }; + let RigidTy::FnDef(def, args) = ty else { unreachable!() }; + let result = Instance::resolve(def, &args); + assert!(result.is_ok()); + } + Goto {..} | Assert{..} | SwitchInt{..} | Return | Drop {..} => { /* Do nothing */} + _ => { unreachable!("Unexpected terminator {term:?}") } + } + } +} + /// This test will generate and analyze a dummy crate using the stable mir. /// For that, it will first write the dummy crate into a file. @@ -56,6 +76,7 @@ fn main() { generate_input(&path).unwrap(); let args = vec![ "rustc".to_string(), + "-Cpanic=abort".to_string(), "--crate-type=lib".to_string(), "--crate-name".to_string(), CRATE_NAME.to_string(), @@ -78,6 +99,9 @@ fn generate_input(path: &str) -> std::io::Result<()> { }} pub fn monomorphic() {{ + let v = vec![10]; + let dup = ty_param(&v); + assert_eq!(v, dup); }} pub mod foo {{ From 9a963e80260f8fc26c502e30ffca43661e454ad0 Mon Sep 17 00:00:00 2001 From: David CARLIER Date: Sat, 5 Aug 2023 16:15:05 +0100 Subject: [PATCH 03/13] std: freebsd build update. since freebsd 11 had been removed, minimum is now 12. --- library/std/build.rs | 6 ++---- 1 file changed, 2 insertions(+), 4 deletions(-) diff --git a/library/std/build.rs b/library/std/build.rs index 046ac488b1ff1..2521ad8efc06f 100644 --- a/library/std/build.rs +++ b/library/std/build.rs @@ -4,10 +4,8 @@ fn main() { println!("cargo:rerun-if-changed=build.rs"); let target = env::var("TARGET").expect("TARGET was not set"); if target.contains("freebsd") { - if env::var("RUST_STD_FREEBSD_12_ABI").is_ok() { - println!("cargo:rustc-cfg=freebsd12"); - } else if env::var("RUST_STD_FREEBSD_13_ABI").is_ok() { - println!("cargo:rustc-cfg=freebsd12"); + println!("cargo:rustc-cfg=freebsd12"); + if env::var("RUST_STD_FREEBSD_13_ABI").is_ok() { println!("cargo:rustc-cfg=freebsd13"); } } else if target.contains("linux") From 6e643e12bb7b0381052696bfe1f7ecbd47769904 Mon Sep 17 00:00:00 2001 From: "Celina G. Val" Date: Fri, 20 Oct 2023 08:23:16 -0700 Subject: [PATCH 04/13] Remove obsolete comment --- compiler/stable_mir/src/ty.rs | 1 - 1 file changed, 1 deletion(-) diff --git a/compiler/stable_mir/src/ty.rs b/compiler/stable_mir/src/ty.rs index 440c9a1f031c2..d4a9b318cfc49 100644 --- a/compiler/stable_mir/src/ty.rs +++ b/compiler/stable_mir/src/ty.rs @@ -226,7 +226,6 @@ pub struct ImplDef(pub DefId); pub struct RegionDef(pub DefId); /// A list of generic arguments. -/// The second field is for internal usage to allow retrieving the internal representation. #[derive(Clone, Debug)] pub struct GenericArgs(pub Vec); From b0d17f35d98c5cafd43a673c70f8ab5d393c31a3 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Esteban=20K=C3=BCber?= Date: Thu, 19 Oct 2023 22:34:45 +0000 Subject: [PATCH 05/13] Typo suggestion to change bindings with leading underscore When encountering a binding that isn't found but has a typo suggestion for a binding with a leading underscore, suggest changing the binding definition instead of the use place. Fix #60164. --- compiler/rustc_resolve/src/diagnostics.rs | 17 +++++++++++++++-- .../ui/suggestions/silenced-binding-typo.fixed | 5 +++++ tests/ui/suggestions/silenced-binding-typo.rs | 5 +++++ .../ui/suggestions/silenced-binding-typo.stderr | 14 ++++++++++++++ 4 files changed, 39 insertions(+), 2 deletions(-) create mode 100644 tests/ui/suggestions/silenced-binding-typo.fixed create mode 100644 tests/ui/suggestions/silenced-binding-typo.rs create mode 100644 tests/ui/suggestions/silenced-binding-typo.stderr diff --git a/compiler/rustc_resolve/src/diagnostics.rs b/compiler/rustc_resolve/src/diagnostics.rs index 925ee615b095b..4ad838e5aed20 100644 --- a/compiler/rustc_resolve/src/diagnostics.rs +++ b/compiler/rustc_resolve/src/diagnostics.rs @@ -1511,9 +1511,22 @@ impl<'a, 'tcx> Resolver<'a, 'tcx> { ), ); } + + let (span, sugg, post) = if let SuggestionTarget::SimilarlyNamed = suggestion.target + && let Ok(snippet) = self.tcx.sess.source_map().span_to_snippet(span) + && let Some(span) = suggestion.span + && let Some(candidate) = suggestion.candidate.as_str().strip_prefix("_") + && snippet == candidate + { + // When the suggested binding change would be from `x` to `_x`, suggest changing the + // original binding definition instead. (#60164) + (span, snippet, ", consider changing it") + } else { + (span, suggestion.candidate.to_string(), "") + }; let msg = match suggestion.target { SuggestionTarget::SimilarlyNamed => format!( - "{} {} with a similar name exists", + "{} {} with a similar name exists{post}", suggestion.res.article(), suggestion.res.descr() ), @@ -1521,7 +1534,7 @@ impl<'a, 'tcx> Resolver<'a, 'tcx> { format!("maybe you meant this {}", suggestion.res.descr()) } }; - err.span_suggestion(span, msg, suggestion.candidate, Applicability::MaybeIncorrect); + err.span_suggestion(span, msg, sugg, Applicability::MaybeIncorrect); true } diff --git a/tests/ui/suggestions/silenced-binding-typo.fixed b/tests/ui/suggestions/silenced-binding-typo.fixed new file mode 100644 index 0000000000000..e0f9e31bef310 --- /dev/null +++ b/tests/ui/suggestions/silenced-binding-typo.fixed @@ -0,0 +1,5 @@ +// run-rustfix +fn main() { + let x = 42; //~ HELP + let _y = x; //~ ERROR +} diff --git a/tests/ui/suggestions/silenced-binding-typo.rs b/tests/ui/suggestions/silenced-binding-typo.rs new file mode 100644 index 0000000000000..6cadd5a93a752 --- /dev/null +++ b/tests/ui/suggestions/silenced-binding-typo.rs @@ -0,0 +1,5 @@ +// run-rustfix +fn main() { + let _x = 42; //~ HELP + let _y = x; //~ ERROR +} diff --git a/tests/ui/suggestions/silenced-binding-typo.stderr b/tests/ui/suggestions/silenced-binding-typo.stderr new file mode 100644 index 0000000000000..9c0e6e2656904 --- /dev/null +++ b/tests/ui/suggestions/silenced-binding-typo.stderr @@ -0,0 +1,14 @@ +error[E0425]: cannot find value `x` in this scope + --> $DIR/silenced-binding-typo.rs:4:14 + | +LL | let _y = x; + | ^ + | +help: a local variable with a similar name exists, consider changing it + | +LL | let x = 42; + | ~ + +error: aborting due to previous error + +For more information about this error, try `rustc --explain E0425`. From 88bccf454fb488e516e0e408c139f1525e5298e1 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Esteban=20K=C3=BCber?= Date: Fri, 20 Oct 2023 18:50:25 +0000 Subject: [PATCH 06/13] Mention `into_iter` on borrow errors suggestions when appropriate If we encounter a borrow error on `vec![1, 2, 3].iter()`, suggest `into_iter`. Fix #68445. --- .../src/diagnostics/conflict_errors.rs | 22 +++++++++++++++++++ .../lifetimes/borrowck-let-suggestion.stderr | 4 ++++ 2 files changed, 26 insertions(+) diff --git a/compiler/rustc_borrowck/src/diagnostics/conflict_errors.rs b/compiler/rustc_borrowck/src/diagnostics/conflict_errors.rs index 20a4402f6f699..36f3c939d5589 100644 --- a/compiler/rustc_borrowck/src/diagnostics/conflict_errors.rs +++ b/compiler/rustc_borrowck/src/diagnostics/conflict_errors.rs @@ -2263,6 +2263,7 @@ impl<'cx, 'tcx> MirBorrowckCtxt<'cx, 'tcx> { current: usize, found: usize, prop_expr: Option<&'tcx hir::Expr<'tcx>>, + call: Option<&'tcx hir::Expr<'tcx>>, } impl<'tcx> Visitor<'tcx> for NestedStatementVisitor<'tcx> { @@ -2272,6 +2273,11 @@ impl<'cx, 'tcx> MirBorrowckCtxt<'cx, 'tcx> { self.current -= 1; } fn visit_expr(&mut self, expr: &'tcx hir::Expr<'tcx>) { + if let hir::ExprKind::MethodCall(_, rcvr, _, _) = expr.kind { + if self.span == rcvr.span.source_callsite() { + self.call = Some(expr); + } + } if self.span == expr.span.source_callsite() { self.found = self.current; if self.prop_expr.is_none() { @@ -2295,6 +2301,7 @@ impl<'cx, 'tcx> MirBorrowckCtxt<'cx, 'tcx> { current: 0, found: 0, prop_expr: None, + call: None, }; visitor.visit_stmt(stmt); @@ -2316,6 +2323,21 @@ impl<'cx, 'tcx> MirBorrowckCtxt<'cx, 'tcx> { && let Some(p) = sm.span_to_margin(stmt.span) && let Ok(s) = sm.span_to_snippet(proper_span) { + if let Some(call) = visitor.call + && let hir::ExprKind::MethodCall(path, _, [], _) = call.kind + && path.ident.name == sym::iter + && let Some(ty) = expr_ty + { + err.span_suggestion_verbose( + path.ident.span, + format!( + "consider consuming the `{ty}` when turning it into an \ + `Iterator`", + ), + "into_iter".to_string(), + Applicability::MaybeIncorrect, + ); + } if !is_format_arguments_item { let addition = format!("let binding = {};\n{}", s, " ".repeat(p)); err.multipart_suggestion_verbose( diff --git a/tests/ui/lifetimes/borrowck-let-suggestion.stderr b/tests/ui/lifetimes/borrowck-let-suggestion.stderr index da0078698ae3b..621196647644a 100644 --- a/tests/ui/lifetimes/borrowck-let-suggestion.stderr +++ b/tests/ui/lifetimes/borrowck-let-suggestion.stderr @@ -10,6 +10,10 @@ LL | x.use_mut(); | - borrow later used here | = note: this error originates in the macro `vec` (in Nightly builds, run with -Z macro-backtrace for more info) +help: consider consuming the `Vec` when turning it into an `Iterator` + | +LL | let mut x = vec![1].into_iter(); + | ~~~~~~~~~ help: consider using a `let` binding to create a longer lived value | LL ~ let binding = vec![1]; From 939a224ce39fbc422e14d8255616fc587b845b8e Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Esteban=20K=C3=BCber?= Date: Fri, 20 Oct 2023 22:11:01 +0000 Subject: [PATCH 07/13] Point at assoc fn definition on type param divergence When the number of type parameters in the associated function of an impl and its trait differ, we now *always* point at the trait one, even if it comes from a foreign crate. When it is local, we point at the specific params, when it is foreign, we point at the whole associated item. Fix #69944. --- .../src/check/compare_impl_item.rs | 24 ++++--------------- tests/ui/typeck/issue-36708.stderr | 7 +++++- 2 files changed, 11 insertions(+), 20 deletions(-) diff --git a/compiler/rustc_hir_analysis/src/check/compare_impl_item.rs b/compiler/rustc_hir_analysis/src/check/compare_impl_item.rs index a1470cc69c306..74e2b157dd0a4 100644 --- a/compiler/rustc_hir_analysis/src/check/compare_impl_item.rs +++ b/compiler/rustc_hir_analysis/src/check/compare_impl_item.rs @@ -1557,38 +1557,24 @@ fn compare_number_of_generics<'tcx>( DiagnosticId::Error("E0049".into()), ); - let mut suffix = None; - + let msg = + format!("expected {trait_count} {kind} parameter{}", pluralize!(trait_count),); if let Some(spans) = trait_spans { let mut spans = spans.iter(); if let Some(span) = spans.next() { - err.span_label( - *span, - format!( - "expected {} {} parameter{}", - trait_count, - kind, - pluralize!(trait_count), - ), - ); + err.span_label(*span, msg); } for span in spans { err.span_label(*span, ""); } } else { - suffix = Some(format!(", expected {trait_count}")); + err.span_label(tcx.def_span(trait_.def_id), msg); } if let Some(span) = span { err.span_label( span, - format!( - "found {} {} parameter{}{}", - impl_count, - kind, - pluralize!(impl_count), - suffix.unwrap_or_default(), - ), + format!("found {} {} parameter{}", impl_count, kind, pluralize!(impl_count),), ); } diff --git a/tests/ui/typeck/issue-36708.stderr b/tests/ui/typeck/issue-36708.stderr index 140f19f1ff774..f1e0f4719281c 100644 --- a/tests/ui/typeck/issue-36708.stderr +++ b/tests/ui/typeck/issue-36708.stderr @@ -2,7 +2,12 @@ error[E0049]: method `foo` has 1 type parameter but its trait declaration has 0 --> $DIR/issue-36708.rs:8:12 | LL | fn foo() {} - | ^ found 1 type parameter, expected 0 + | ^ found 1 type parameter + | + ::: $DIR/auxiliary/issue-36708.rs:4:5 + | +LL | fn foo(); + | --------- expected 0 type parameters error: aborting due to previous error From f4791420abb907471e693ed7de5e7763f412c6cc Mon Sep 17 00:00:00 2001 From: David Carlier Date: Fri, 20 Oct 2023 15:12:02 +0100 Subject: [PATCH 08/13] changes from feedback --- library/std/build.rs | 8 ++------ library/std/src/os/freebsd/fs.rs | 10 ---------- 2 files changed, 2 insertions(+), 16 deletions(-) diff --git a/library/std/build.rs b/library/std/build.rs index 2521ad8efc06f..ad0a82eab8ca1 100644 --- a/library/std/build.rs +++ b/library/std/build.rs @@ -3,15 +3,11 @@ use std::env; fn main() { println!("cargo:rerun-if-changed=build.rs"); let target = env::var("TARGET").expect("TARGET was not set"); - if target.contains("freebsd") { - println!("cargo:rustc-cfg=freebsd12"); - if env::var("RUST_STD_FREEBSD_13_ABI").is_ok() { - println!("cargo:rustc-cfg=freebsd13"); - } - } else if target.contains("linux") + if target.contains("linux") || target.contains("netbsd") || target.contains("dragonfly") || target.contains("openbsd") + || target.contains("freebsd") || target.contains("solaris") || target.contains("illumos") || target.contains("apple-darwin") diff --git a/library/std/src/os/freebsd/fs.rs b/library/std/src/os/freebsd/fs.rs index 8db3a950c40ff..5689a82e00a34 100644 --- a/library/std/src/os/freebsd/fs.rs +++ b/library/std/src/os/freebsd/fs.rs @@ -76,12 +76,7 @@ impl MetadataExt for Metadata { fn as_raw_stat(&self) -> &raw::stat { // The methods below use libc::stat, so they work fine when libc is built with FreeBSD 12 ABI. // This method would just return nonsense. - #[cfg(freebsd12)] panic!("as_raw_stat not supported with FreeBSD 12 ABI"); - #[cfg(not(freebsd12))] - unsafe { - &*(self.as_inner().as_inner() as *const libc::stat as *const raw::stat) - } } fn st_dev(&self) -> u64 { self.as_inner().as_inner().st_dev as u64 @@ -143,12 +138,7 @@ impl MetadataExt for Metadata { fn st_flags(&self) -> u32 { self.as_inner().as_inner().st_flags as u32 } - #[cfg(freebsd12)] fn st_lspare(&self) -> u32 { panic!("st_lspare not supported with FreeBSD 12 ABI"); } - #[cfg(not(freebsd12))] - fn st_lspare(&self) -> u32 { - self.as_inner().as_inner().st_lspare as u32 - } } From dca42959bc4c71243674efe943e85f91f41aeb6a Mon Sep 17 00:00:00 2001 From: Zalathar Date: Tue, 17 Oct 2023 18:41:10 +1100 Subject: [PATCH 09/13] coverage: Add a test showing the inconsistent handling of function signatures --- tests/coverage-map/fn_sig_into_try.cov-map | 53 +++++++++++++++++++++ tests/coverage-map/fn_sig_into_try.rs | 41 ++++++++++++++++ tests/run-coverage/fn_sig_into_try.coverage | 45 +++++++++++++++++ tests/run-coverage/fn_sig_into_try.rs | 41 ++++++++++++++++ 4 files changed, 180 insertions(+) create mode 100644 tests/coverage-map/fn_sig_into_try.cov-map create mode 100644 tests/coverage-map/fn_sig_into_try.rs create mode 100644 tests/run-coverage/fn_sig_into_try.coverage create mode 100644 tests/run-coverage/fn_sig_into_try.rs diff --git a/tests/coverage-map/fn_sig_into_try.cov-map b/tests/coverage-map/fn_sig_into_try.cov-map new file mode 100644 index 0000000000000..5727ff4ce85ef --- /dev/null +++ b/tests/coverage-map/fn_sig_into_try.cov-map @@ -0,0 +1,53 @@ +Function name: fn_sig_into_try::a +Raw bytes (9): 0x[01, 01, 00, 01, 01, 0a, 01, 04, 02] +Number of files: 1 +- file 0 => global file 1 +Number of expressions: 0 +Number of file 0 mappings: 1 +- Code(Counter(0)) at (prev + 10, 1) to (start + 4, 2) + +Function name: fn_sig_into_try::b +Raw bytes (28): 0x[01, 01, 02, 01, 05, 05, 02, 04, 01, 12, 05, 00, 0f, 00, 00, 0f, 00, 10, 02, 01, 05, 00, 0c, 07, 01, 01, 00, 02] +Number of files: 1 +- file 0 => global file 1 +Number of expressions: 2 +- expression 0 operands: lhs = Counter(0), rhs = Counter(1) +- expression 1 operands: lhs = Counter(1), rhs = Expression(0, Sub) +Number of file 0 mappings: 4 +- Code(Counter(0)) at (prev + 18, 5) to (start + 0, 15) +- Code(Zero) at (prev + 0, 15) to (start + 0, 16) +- Code(Expression(0, Sub)) at (prev + 1, 5) to (start + 0, 12) + = (c0 - c1) +- Code(Expression(1, Add)) at (prev + 1, 1) to (start + 0, 2) + = (c1 + (c0 - c1)) + +Function name: fn_sig_into_try::c +Raw bytes (28): 0x[01, 01, 02, 01, 05, 05, 02, 04, 01, 18, 0d, 00, 17, 00, 00, 17, 00, 18, 02, 01, 05, 00, 0c, 07, 01, 01, 00, 02] +Number of files: 1 +- file 0 => global file 1 +Number of expressions: 2 +- expression 0 operands: lhs = Counter(0), rhs = Counter(1) +- expression 1 operands: lhs = Counter(1), rhs = Expression(0, Sub) +Number of file 0 mappings: 4 +- Code(Counter(0)) at (prev + 24, 13) to (start + 0, 23) +- Code(Zero) at (prev + 0, 23) to (start + 0, 24) +- Code(Expression(0, Sub)) at (prev + 1, 5) to (start + 0, 12) + = (c0 - c1) +- Code(Expression(1, Add)) at (prev + 1, 1) to (start + 0, 2) + = (c1 + (c0 - c1)) + +Function name: fn_sig_into_try::d +Raw bytes (28): 0x[01, 01, 02, 01, 05, 05, 02, 04, 01, 1c, 01, 03, 0f, 00, 03, 0f, 00, 10, 02, 01, 05, 00, 0c, 07, 01, 01, 00, 02] +Number of files: 1 +- file 0 => global file 1 +Number of expressions: 2 +- expression 0 operands: lhs = Counter(0), rhs = Counter(1) +- expression 1 operands: lhs = Counter(1), rhs = Expression(0, Sub) +Number of file 0 mappings: 4 +- Code(Counter(0)) at (prev + 28, 1) to (start + 3, 15) +- Code(Zero) at (prev + 3, 15) to (start + 0, 16) +- Code(Expression(0, Sub)) at (prev + 1, 5) to (start + 0, 12) + = (c0 - c1) +- Code(Expression(1, Add)) at (prev + 1, 1) to (start + 0, 2) + = (c1 + (c0 - c1)) + diff --git a/tests/coverage-map/fn_sig_into_try.rs b/tests/coverage-map/fn_sig_into_try.rs new file mode 100644 index 0000000000000..92850c8a188fc --- /dev/null +++ b/tests/coverage-map/fn_sig_into_try.rs @@ -0,0 +1,41 @@ +#![feature(coverage_attribute)] +// compile-flags: --edition=2021 + +// Regression test for inconsistent handling of function signature spans that +// are followed by code using the `?` operator. +// +// For each of these similar functions, the line containing the function +// signature should be handled in the same way. + +fn a() -> Option +{ + Some(7i32); + Some(0) +} + +fn b() -> Option +{ + Some(7i32)?; + Some(0) +} + +fn c() -> Option +{ + let _ = Some(7i32)?; + Some(0) +} + +fn d() -> Option +{ + let _: () = (); + Some(7i32)?; + Some(0) +} + +#[coverage(off)] +fn main() { + a(); + b(); + c(); + d(); +} diff --git a/tests/run-coverage/fn_sig_into_try.coverage b/tests/run-coverage/fn_sig_into_try.coverage new file mode 100644 index 0000000000000..86defeeb9dae6 --- /dev/null +++ b/tests/run-coverage/fn_sig_into_try.coverage @@ -0,0 +1,45 @@ + LL| |#![feature(coverage_attribute)] + LL| |// compile-flags: --edition=2021 + LL| | + LL| |// Regression test for inconsistent handling of function signature spans that + LL| |// are followed by code using the `?` operator. + LL| |// + LL| |// For each of these similar functions, the line containing the function + LL| |// signature should be handled in the same way. + LL| | + LL| 1|fn a() -> Option + LL| 1|{ + LL| 1| Some(7i32); + LL| 1| Some(0) + LL| 1|} + LL| | + LL| |fn b() -> Option + LL| |{ + LL| 1| Some(7i32)?; + ^0 + LL| 1| Some(0) + LL| 1|} + LL| | + LL| |fn c() -> Option + LL| |{ + LL| 1| let _ = Some(7i32)?; + ^0 + LL| 1| Some(0) + LL| 1|} + LL| | + LL| 1|fn d() -> Option + LL| 1|{ + LL| 1| let _: () = (); + LL| 1| Some(7i32)?; + ^0 + LL| 1| Some(0) + LL| 1|} + LL| | + LL| |#[coverage(off)] + LL| |fn main() { + LL| | a(); + LL| | b(); + LL| | c(); + LL| | d(); + LL| |} + diff --git a/tests/run-coverage/fn_sig_into_try.rs b/tests/run-coverage/fn_sig_into_try.rs new file mode 100644 index 0000000000000..92850c8a188fc --- /dev/null +++ b/tests/run-coverage/fn_sig_into_try.rs @@ -0,0 +1,41 @@ +#![feature(coverage_attribute)] +// compile-flags: --edition=2021 + +// Regression test for inconsistent handling of function signature spans that +// are followed by code using the `?` operator. +// +// For each of these similar functions, the line containing the function +// signature should be handled in the same way. + +fn a() -> Option +{ + Some(7i32); + Some(0) +} + +fn b() -> Option +{ + Some(7i32)?; + Some(0) +} + +fn c() -> Option +{ + let _ = Some(7i32)?; + Some(0) +} + +fn d() -> Option +{ + let _: () = (); + Some(7i32)?; + Some(0) +} + +#[coverage(off)] +fn main() { + a(); + b(); + c(); + d(); +} From a17ff82aaec7a693c1cfe50bfc221dac4b06f8ad Mon Sep 17 00:00:00 2001 From: Zalathar Date: Tue, 17 Oct 2023 18:58:35 +1100 Subject: [PATCH 10/13] coverage: Handle fn signature spans more consistently near `?` --- compiler/rustc_mir_transform/src/coverage/spans.rs | 2 +- tests/coverage-map/fn_sig_into_try.cov-map | 12 ++++++------ tests/coverage-map/status-quo/inline-dead.cov-map | 14 ++++++++------ tests/coverage-map/status-quo/issue-84561.cov-map | 6 +++--- tests/run-coverage/fn_sig_into_try.coverage | 8 ++++---- tests/run-coverage/issue-84561.coverage | 2 +- 6 files changed, 23 insertions(+), 21 deletions(-) diff --git a/compiler/rustc_mir_transform/src/coverage/spans.rs b/compiler/rustc_mir_transform/src/coverage/spans.rs index 3f7ba5725104a..9718ffb3e5bcd 100644 --- a/compiler/rustc_mir_transform/src/coverage/spans.rs +++ b/compiler/rustc_mir_transform/src/coverage/spans.rs @@ -80,7 +80,7 @@ impl CoverageSpan { expn_span: fn_sig_span, current_macro_or_none: Default::default(), bcb: START_BCB, - merged_spans: vec![], + merged_spans: vec![fn_sig_span], is_closure: false, } } diff --git a/tests/coverage-map/fn_sig_into_try.cov-map b/tests/coverage-map/fn_sig_into_try.cov-map index 5727ff4ce85ef..4672e7c1ce90a 100644 --- a/tests/coverage-map/fn_sig_into_try.cov-map +++ b/tests/coverage-map/fn_sig_into_try.cov-map @@ -7,30 +7,30 @@ Number of file 0 mappings: 1 - Code(Counter(0)) at (prev + 10, 1) to (start + 4, 2) Function name: fn_sig_into_try::b -Raw bytes (28): 0x[01, 01, 02, 01, 05, 05, 02, 04, 01, 12, 05, 00, 0f, 00, 00, 0f, 00, 10, 02, 01, 05, 00, 0c, 07, 01, 01, 00, 02] +Raw bytes (28): 0x[01, 01, 02, 01, 05, 05, 02, 04, 01, 10, 01, 02, 0f, 00, 02, 0f, 00, 10, 02, 01, 05, 00, 0c, 07, 01, 01, 00, 02] Number of files: 1 - file 0 => global file 1 Number of expressions: 2 - expression 0 operands: lhs = Counter(0), rhs = Counter(1) - expression 1 operands: lhs = Counter(1), rhs = Expression(0, Sub) Number of file 0 mappings: 4 -- Code(Counter(0)) at (prev + 18, 5) to (start + 0, 15) -- Code(Zero) at (prev + 0, 15) to (start + 0, 16) +- Code(Counter(0)) at (prev + 16, 1) to (start + 2, 15) +- Code(Zero) at (prev + 2, 15) to (start + 0, 16) - Code(Expression(0, Sub)) at (prev + 1, 5) to (start + 0, 12) = (c0 - c1) - Code(Expression(1, Add)) at (prev + 1, 1) to (start + 0, 2) = (c1 + (c0 - c1)) Function name: fn_sig_into_try::c -Raw bytes (28): 0x[01, 01, 02, 01, 05, 05, 02, 04, 01, 18, 0d, 00, 17, 00, 00, 17, 00, 18, 02, 01, 05, 00, 0c, 07, 01, 01, 00, 02] +Raw bytes (28): 0x[01, 01, 02, 01, 05, 05, 02, 04, 01, 16, 01, 02, 17, 00, 02, 17, 00, 18, 02, 01, 05, 00, 0c, 07, 01, 01, 00, 02] Number of files: 1 - file 0 => global file 1 Number of expressions: 2 - expression 0 operands: lhs = Counter(0), rhs = Counter(1) - expression 1 operands: lhs = Counter(1), rhs = Expression(0, Sub) Number of file 0 mappings: 4 -- Code(Counter(0)) at (prev + 24, 13) to (start + 0, 23) -- Code(Zero) at (prev + 0, 23) to (start + 0, 24) +- Code(Counter(0)) at (prev + 22, 1) to (start + 2, 23) +- Code(Zero) at (prev + 2, 23) to (start + 0, 24) - Code(Expression(0, Sub)) at (prev + 1, 5) to (start + 0, 12) = (c0 - c1) - Code(Expression(1, Add)) at (prev + 1, 1) to (start + 0, 2) diff --git a/tests/coverage-map/status-quo/inline-dead.cov-map b/tests/coverage-map/status-quo/inline-dead.cov-map index 483f7ef79c637..06b64da5723bd 100644 --- a/tests/coverage-map/status-quo/inline-dead.cov-map +++ b/tests/coverage-map/status-quo/inline-dead.cov-map @@ -31,13 +31,15 @@ Number of file 0 mappings: 2 - Code(Counter(0)) at (prev + 7, 6) to (start + 2, 2) Function name: inline_dead::main::{closure#0} -Raw bytes (16): 0x[01, 01, 01, 01, 05, 02, 00, 09, 0d, 00, 0e, 03, 02, 05, 00, 06] +Raw bytes (23): 0x[01, 01, 02, 09, 06, 01, 05, 03, 01, 07, 17, 00, 18, 00, 02, 0d, 00, 0e, 03, 02, 05, 00, 06] Number of files: 1 - file 0 => global file 1 -Number of expressions: 1 -- expression 0 operands: lhs = Counter(0), rhs = Counter(1) -Number of file 0 mappings: 2 -- Code(Zero) at (prev + 9, 13) to (start + 0, 14) +Number of expressions: 2 +- expression 0 operands: lhs = Counter(2), rhs = Expression(1, Sub) +- expression 1 operands: lhs = Counter(0), rhs = Counter(1) +Number of file 0 mappings: 3 +- Code(Counter(0)) at (prev + 7, 23) to (start + 0, 24) +- Code(Zero) at (prev + 2, 13) to (start + 0, 14) - Code(Expression(0, Add)) at (prev + 2, 5) to (start + 0, 6) - = (c0 + c1) + = (c2 + (c0 - c1)) diff --git a/tests/coverage-map/status-quo/issue-84561.cov-map b/tests/coverage-map/status-quo/issue-84561.cov-map index 01fa7ec573c59..76340b1a78c77 100644 --- a/tests/coverage-map/status-quo/issue-84561.cov-map +++ b/tests/coverage-map/status-quo/issue-84561.cov-map @@ -7,15 +7,15 @@ Number of file 0 mappings: 1 - Code(Counter(0)) at (prev + 4, 10) to (start + 0, 19) Function name: ::fmt -Raw bytes (29): 0x[01, 01, 02, 01, 05, 05, 02, 04, 01, 89, 01, 09, 00, 25, 05, 00, 25, 00, 26, 02, 01, 09, 00, 0f, 07, 01, 05, 00, 06] +Raw bytes (29): 0x[01, 01, 02, 01, 05, 05, 02, 04, 01, 88, 01, 05, 01, 25, 05, 01, 25, 00, 26, 02, 01, 09, 00, 0f, 07, 01, 05, 00, 06] Number of files: 1 - file 0 => global file 1 Number of expressions: 2 - expression 0 operands: lhs = Counter(0), rhs = Counter(1) - expression 1 operands: lhs = Counter(1), rhs = Expression(0, Sub) Number of file 0 mappings: 4 -- Code(Counter(0)) at (prev + 137, 9) to (start + 0, 37) -- Code(Counter(1)) at (prev + 0, 37) to (start + 0, 38) +- Code(Counter(0)) at (prev + 136, 5) to (start + 1, 37) +- Code(Counter(1)) at (prev + 1, 37) to (start + 0, 38) - Code(Expression(0, Sub)) at (prev + 1, 9) to (start + 0, 15) = (c0 - c1) - Code(Expression(1, Add)) at (prev + 1, 5) to (start + 0, 6) diff --git a/tests/run-coverage/fn_sig_into_try.coverage b/tests/run-coverage/fn_sig_into_try.coverage index 86defeeb9dae6..f1ddb1da78022 100644 --- a/tests/run-coverage/fn_sig_into_try.coverage +++ b/tests/run-coverage/fn_sig_into_try.coverage @@ -13,15 +13,15 @@ LL| 1| Some(0) LL| 1|} LL| | - LL| |fn b() -> Option - LL| |{ + LL| 1|fn b() -> Option + LL| 1|{ LL| 1| Some(7i32)?; ^0 LL| 1| Some(0) LL| 1|} LL| | - LL| |fn c() -> Option - LL| |{ + LL| 1|fn c() -> Option + LL| 1|{ LL| 1| let _ = Some(7i32)?; ^0 LL| 1| Some(0) diff --git a/tests/run-coverage/issue-84561.coverage b/tests/run-coverage/issue-84561.coverage index 222f877d36aad..e693866e27760 100644 --- a/tests/run-coverage/issue-84561.coverage +++ b/tests/run-coverage/issue-84561.coverage @@ -135,7 +135,7 @@ LL| 0|} LL| | LL| |impl std::fmt::Debug for Foo { - LL| | fn fmt(&self, f: &mut std::fmt::Formatter) -> std::fmt::Result { + LL| 7| fn fmt(&self, f: &mut std::fmt::Formatter) -> std::fmt::Result { LL| 7| write!(f, "try and succeed")?; ^0 LL| 7| Ok(()) From e16494469e7f5ad770c40d8c86cca5a2a02ebf01 Mon Sep 17 00:00:00 2001 From: Zalathar Date: Tue, 17 Oct 2023 23:02:22 +1100 Subject: [PATCH 11/13] coverage: Don't create an intermediate vec for each BCB's initial spans --- .../src/coverage/spans/from_mir.rs | 49 +++++++++---------- 1 file changed, 23 insertions(+), 26 deletions(-) diff --git a/compiler/rustc_mir_transform/src/coverage/spans/from_mir.rs b/compiler/rustc_mir_transform/src/coverage/spans/from_mir.rs index 02e2cf6b05e3e..66620b1db2ac4 100644 --- a/compiler/rustc_mir_transform/src/coverage/spans/from_mir.rs +++ b/compiler/rustc_mir_transform/src/coverage/spans/from_mir.rs @@ -1,3 +1,4 @@ +use rustc_data_structures::captures::Captures; use rustc_middle::mir::{ self, FakeReadCause, Statement, StatementKind, Terminator, TerminatorKind, }; @@ -12,7 +13,7 @@ pub(super) fn mir_to_initial_sorted_coverage_spans( body_span: Span, basic_coverage_blocks: &CoverageGraph, ) -> Vec { - let mut initial_spans = Vec::::with_capacity(mir_body.basic_blocks.len() * 2); + let mut initial_spans = Vec::with_capacity(mir_body.basic_blocks.len() * 2); for (bcb, bcb_data) in basic_coverage_blocks.iter_enumerated() { initial_spans.extend(bcb_to_initial_coverage_spans(mir_body, body_span, bcb, bcb_data)); } @@ -50,34 +51,30 @@ pub(super) fn mir_to_initial_sorted_coverage_spans( // for each `Statement` and `Terminator`. (Note that subsequent stages of coverage analysis will // merge some `CoverageSpan`s, at which point a `CoverageSpan` may represent multiple // `Statement`s and/or `Terminator`s.) -fn bcb_to_initial_coverage_spans( - mir_body: &mir::Body<'_>, +fn bcb_to_initial_coverage_spans<'a, 'tcx>( + mir_body: &'a mir::Body<'tcx>, body_span: Span, bcb: BasicCoverageBlock, - bcb_data: &BasicCoverageBlockData, -) -> Vec { - bcb_data - .basic_blocks - .iter() - .flat_map(|&bb| { - let data = &mir_body[bb]; - data.statements - .iter() - .filter_map(move |statement| { - filtered_statement_span(statement).map(|span| { - CoverageSpan::for_statement( - statement, - function_source_span(span, body_span), - span, - bcb, - ) - }) + bcb_data: &'a BasicCoverageBlockData, +) -> impl Iterator + Captures<'a> + Captures<'tcx> { + bcb_data.basic_blocks.iter().flat_map(move |&bb| { + let data = &mir_body[bb]; + data.statements + .iter() + .filter_map(move |statement| { + filtered_statement_span(statement).map(|span| { + CoverageSpan::for_statement( + statement, + function_source_span(span, body_span), + span, + bcb, + ) }) - .chain(filtered_terminator_span(data.terminator()).map(|span| { - CoverageSpan::for_terminator(function_source_span(span, body_span), span, bcb) - })) - }) - .collect() + }) + .chain(filtered_terminator_span(data.terminator()).map(|span| { + CoverageSpan::for_terminator(function_source_span(span, body_span), span, bcb) + })) + }) } /// If the MIR `Statement` has a span contributive to computing coverage spans, From 319693a927f3cc7759586fcc3ae3fd740598c309 Mon Sep 17 00:00:00 2001 From: Zalathar Date: Tue, 17 Oct 2023 21:22:02 +1100 Subject: [PATCH 12/13] coverage: Simplify initial creation of coverage spans --- .../rustc_mir_transform/src/coverage/spans.rs | 33 ++------------ .../src/coverage/spans/from_mir.rs | 44 ++++++++++++------- 2 files changed, 32 insertions(+), 45 deletions(-) diff --git a/compiler/rustc_mir_transform/src/coverage/spans.rs b/compiler/rustc_mir_transform/src/coverage/spans.rs index 9718ffb3e5bcd..f4016fb3fc05c 100644 --- a/compiler/rustc_mir_transform/src/coverage/spans.rs +++ b/compiler/rustc_mir_transform/src/coverage/spans.rs @@ -2,7 +2,7 @@ use std::cell::OnceCell; use rustc_data_structures::graph::WithNumNodes; use rustc_index::IndexVec; -use rustc_middle::mir::{self, AggregateKind, Rvalue, Statement, StatementKind}; +use rustc_middle::mir; use rustc_span::{BytePos, ExpnKind, MacroKind, Span, Symbol, DUMMY_SP}; use super::graph::{BasicCoverageBlock, CoverageGraph, START_BCB}; @@ -75,29 +75,15 @@ struct CoverageSpan { impl CoverageSpan { pub fn for_fn_sig(fn_sig_span: Span) -> Self { - Self { - span: fn_sig_span, - expn_span: fn_sig_span, - current_macro_or_none: Default::default(), - bcb: START_BCB, - merged_spans: vec![fn_sig_span], - is_closure: false, - } + Self::new(fn_sig_span, fn_sig_span, START_BCB, false) } - pub fn for_statement( - statement: &Statement<'_>, + pub(super) fn new( span: Span, expn_span: Span, bcb: BasicCoverageBlock, + is_closure: bool, ) -> Self { - let is_closure = match statement.kind { - StatementKind::Assign(box (_, Rvalue::Aggregate(box ref kind, _))) => { - matches!(kind, AggregateKind::Closure(_, _) | AggregateKind::Coroutine(_, _, _)) - } - _ => false, - }; - Self { span, expn_span, @@ -108,17 +94,6 @@ impl CoverageSpan { } } - pub fn for_terminator(span: Span, expn_span: Span, bcb: BasicCoverageBlock) -> Self { - Self { - span, - expn_span, - current_macro_or_none: Default::default(), - bcb, - merged_spans: vec![span], - is_closure: false, - } - } - pub fn merge_from(&mut self, mut other: CoverageSpan) { debug_assert!(self.is_mergeable(&other)); self.span = self.span.to(other.span); diff --git a/compiler/rustc_mir_transform/src/coverage/spans/from_mir.rs b/compiler/rustc_mir_transform/src/coverage/spans/from_mir.rs index 66620b1db2ac4..6189e5379ea05 100644 --- a/compiler/rustc_mir_transform/src/coverage/spans/from_mir.rs +++ b/compiler/rustc_mir_transform/src/coverage/spans/from_mir.rs @@ -1,6 +1,7 @@ use rustc_data_structures::captures::Captures; use rustc_middle::mir::{ - self, FakeReadCause, Statement, StatementKind, Terminator, TerminatorKind, + self, AggregateKind, FakeReadCause, Rvalue, Statement, StatementKind, Terminator, + TerminatorKind, }; use rustc_span::Span; @@ -59,24 +60,35 @@ fn bcb_to_initial_coverage_spans<'a, 'tcx>( ) -> impl Iterator + Captures<'a> + Captures<'tcx> { bcb_data.basic_blocks.iter().flat_map(move |&bb| { let data = &mir_body[bb]; - data.statements - .iter() - .filter_map(move |statement| { - filtered_statement_span(statement).map(|span| { - CoverageSpan::for_statement( - statement, - function_source_span(span, body_span), - span, - bcb, - ) - }) - }) - .chain(filtered_terminator_span(data.terminator()).map(|span| { - CoverageSpan::for_terminator(function_source_span(span, body_span), span, bcb) - })) + + let statement_spans = data.statements.iter().filter_map(move |statement| { + let expn_span = filtered_statement_span(statement)?; + let span = function_source_span(expn_span, body_span); + + Some(CoverageSpan::new(span, expn_span, bcb, is_closure(statement))) + }); + + let terminator_span = Some(data.terminator()).into_iter().filter_map(move |terminator| { + let expn_span = filtered_terminator_span(terminator)?; + let span = function_source_span(expn_span, body_span); + + Some(CoverageSpan::new(span, expn_span, bcb, false)) + }); + + statement_spans.chain(terminator_span) }) } +fn is_closure(statement: &Statement<'_>) -> bool { + match statement.kind { + StatementKind::Assign(box (_, Rvalue::Aggregate(box ref agg_kind, _))) => match agg_kind { + AggregateKind::Closure(_, _) | AggregateKind::Coroutine(_, _, _) => true, + _ => false, + }, + _ => false, + } +} + /// If the MIR `Statement` has a span contributive to computing coverage spans, /// return it; otherwise return `None`. fn filtered_statement_span(statement: &Statement<'_>) -> Option { From ff02d9200ca36be1b8db857c286312f2a52d40f6 Mon Sep 17 00:00:00 2001 From: Zalathar Date: Fri, 22 Sep 2023 17:36:01 +1000 Subject: [PATCH 13/13] coverage: Simplify the injection of coverage statements --- .../src/coverage/counters.rs | 26 +-- .../rustc_mir_transform/src/coverage/mod.rs | 195 +++++++----------- .../rustc_mir_transform/src/coverage/spans.rs | 9 +- 3 files changed, 87 insertions(+), 143 deletions(-) diff --git a/compiler/rustc_mir_transform/src/coverage/counters.rs b/compiler/rustc_mir_transform/src/coverage/counters.rs index a83ccf8fc3c21..d07f59bc72af5 100644 --- a/compiler/rustc_mir_transform/src/coverage/counters.rs +++ b/compiler/rustc_mir_transform/src/coverage/counters.rs @@ -169,22 +169,22 @@ impl CoverageCounters { self.bcb_counters[bcb].as_ref() } - pub(super) fn take_bcb_counter(&mut self, bcb: BasicCoverageBlock) -> Option { - self.bcb_counters[bcb].take() - } - - pub(super) fn drain_bcb_counters( - &mut self, - ) -> impl Iterator + '_ { + pub(super) fn bcb_node_counters( + &self, + ) -> impl Iterator { self.bcb_counters - .iter_enumerated_mut() - .filter_map(|(bcb, counter)| Some((bcb, counter.take()?))) + .iter_enumerated() + .filter_map(|(bcb, counter_kind)| Some((bcb, counter_kind.as_ref()?))) } - pub(super) fn drain_bcb_edge_counters( - &mut self, - ) -> impl Iterator + '_ { - self.bcb_edge_counters.drain() + /// For each edge in the BCB graph that has an associated counter, yields + /// that edge's *from* and *to* nodes, and its counter. + pub(super) fn bcb_edge_counters( + &self, + ) -> impl Iterator { + self.bcb_edge_counters + .iter() + .map(|(&(from_bcb, to_bcb), counter_kind)| (from_bcb, to_bcb, counter_kind)) } pub(super) fn take_expressions(&mut self) -> IndexVec { diff --git a/compiler/rustc_mir_transform/src/coverage/mod.rs b/compiler/rustc_mir_transform/src/coverage/mod.rs index 6fdaff6b4c021..c9b36ba25ac32 100644 --- a/compiler/rustc_mir_transform/src/coverage/mod.rs +++ b/compiler/rustc_mir_transform/src/coverage/mod.rs @@ -8,7 +8,7 @@ mod spans; mod tests; use self::counters::{BcbCounter, CoverageCounters}; -use self::graph::{BasicCoverageBlock, BasicCoverageBlockData, CoverageGraph}; +use self::graph::CoverageGraph; use self::spans::CoverageSpans; use crate::MirPass; @@ -104,7 +104,6 @@ struct Instrumentor<'a, 'tcx> { function_source_hash: u64, basic_coverage_blocks: CoverageGraph, coverage_counters: CoverageCounters, - mappings: Vec, } impl<'a, 'tcx> Instrumentor<'a, 'tcx> { @@ -145,7 +144,6 @@ impl<'a, 'tcx> Instrumentor<'a, 'tcx> { function_source_hash, basic_coverage_blocks, coverage_counters, - mappings: Vec::new(), } } @@ -168,148 +166,99 @@ impl<'a, 'tcx> Instrumentor<'a, 'tcx> { // and all `Expression` dependencies (operands) are also generated, for any other // `BasicCoverageBlock`s not already associated with a coverage span. let bcb_has_coverage_spans = |bcb| coverage_spans.bcb_has_coverage_spans(bcb); - let result = self - .coverage_counters - .make_bcb_counters(&mut self.basic_coverage_blocks, bcb_has_coverage_spans); - - if let Ok(()) = result { - //////////////////////////////////////////////////// - // Remove the counter or edge counter from of each coverage cpan's associated - // `BasicCoverageBlock`, and inject a `Coverage` statement into the MIR. - // - // `Coverage` statements injected from coverage spans will include the code regions - // (source code start and end positions) to be counted by the associated counter. - // - // These coverage-span-associated counters are removed from their associated - // `BasicCoverageBlock`s so that the only remaining counters in the `CoverageGraph` - // are indirect counters (to be injected next, without associated code regions). - self.inject_coverage_span_counters(&coverage_spans); - - //////////////////////////////////////////////////// - // For any remaining `BasicCoverageBlock` counters (that were not associated with - // any coverage span), inject `Coverage` statements (_without_ code region spans) - // to ensure `BasicCoverageBlock` counters that other `Expression`s may depend on - // are in fact counted, even though they don't directly contribute to counting - // their own independent code region's coverage. - self.inject_indirect_counters(); - }; + self.coverage_counters + .make_bcb_counters(&mut self.basic_coverage_blocks, bcb_has_coverage_spans) + .unwrap_or_else(|e| { + bug!("Error processing: {:?}: {:?}", self.mir_body.source.def_id(), e.message) + }); - if let Err(e) = result { - bug!("Error processing: {:?}: {:?}", self.mir_body.source.def_id(), e.message) - }; + let mappings = self.create_mappings_and_inject_coverage_statements(&coverage_spans); self.mir_body.function_coverage_info = Some(Box::new(FunctionCoverageInfo { function_source_hash: self.function_source_hash, num_counters: self.coverage_counters.num_counters(), expressions: self.coverage_counters.take_expressions(), - mappings: std::mem::take(&mut self.mappings), + mappings, })); } - /// Injects a single [`StatementKind::Coverage`] for each BCB that has one - /// or more coverage spans. - fn inject_coverage_span_counters(&mut self, coverage_spans: &CoverageSpans) { - let tcx = self.tcx; - let source_map = tcx.sess.source_map(); + /// For each [`BcbCounter`] associated with a BCB node or BCB edge, create + /// any corresponding mappings (for BCB nodes only), and inject any necessary + /// coverage statements into MIR. + fn create_mappings_and_inject_coverage_statements( + &mut self, + coverage_spans: &CoverageSpans, + ) -> Vec { + let source_map = self.tcx.sess.source_map(); let body_span = self.body_span; use rustc_session::RemapFileNameExt; let file_name = Symbol::intern(&self.source_file.name.for_codegen(self.tcx.sess).to_string_lossy()); - for (bcb, spans) in coverage_spans.bcbs_with_coverage_spans() { - let counter_kind = self.coverage_counters.take_bcb_counter(bcb).unwrap_or_else(|| { - bug!("Every BasicCoverageBlock should have a Counter or Expression"); - }); - - let term = counter_kind.as_term(); - self.mappings.extend(spans.iter().map(|&span| { - let code_region = make_code_region(source_map, file_name, span, body_span); - Mapping { code_region, term } - })); - - inject_statement( - self.mir_body, - self.make_mir_coverage_kind(&counter_kind), - self.bcb_leader_bb(bcb), - ); - } - } + let mut mappings = Vec::new(); + + // Process the counters and spans associated with BCB nodes. + for (bcb, counter_kind) in self.coverage_counters.bcb_node_counters() { + let spans = coverage_spans.spans_for_bcb(bcb); + let has_mappings = !spans.is_empty(); + + // If this BCB has any coverage spans, add corresponding mappings to + // the mappings table. + if has_mappings { + let term = counter_kind.as_term(); + mappings.extend(spans.iter().map(|&span| { + let code_region = make_code_region(source_map, file_name, span, body_span); + Mapping { code_region, term } + })); + } - /// At this point, any BCB with coverage counters has already had its counter injected - /// into MIR, and had its counter removed from `coverage_counters` (via `take_counter()`). - /// - /// Any other counter associated with a `BasicCoverageBlock`, or its incoming edge, but not - /// associated with a coverage span, should only exist if the counter is an `Expression` - /// dependency (one of the expression operands). Collect them, and inject the additional - /// counters into the MIR, without a reportable coverage span. - fn inject_indirect_counters(&mut self) { - let mut bcb_counters_without_direct_coverage_spans = Vec::new(); - for (target_bcb, counter_kind) in self.coverage_counters.drain_bcb_counters() { - bcb_counters_without_direct_coverage_spans.push((None, target_bcb, counter_kind)); - } - for ((from_bcb, target_bcb), counter_kind) in - self.coverage_counters.drain_bcb_edge_counters() - { - bcb_counters_without_direct_coverage_spans.push(( - Some(from_bcb), - target_bcb, - counter_kind, - )); + let do_inject = match counter_kind { + // Counter-increment statements always need to be injected. + BcbCounter::Counter { .. } => true, + // The only purpose of expression-used statements is to detect + // when a mapping is unreachable, so we only inject them for + // expressions with one or more mappings. + BcbCounter::Expression { .. } => has_mappings, + }; + if do_inject { + inject_statement( + self.mir_body, + self.make_mir_coverage_kind(counter_kind), + self.basic_coverage_blocks[bcb].leader_bb(), + ); + } } - for (edge_from_bcb, target_bcb, counter_kind) in bcb_counters_without_direct_coverage_spans - { - match counter_kind { - BcbCounter::Counter { .. } => { - let inject_to_bb = if let Some(from_bcb) = edge_from_bcb { - // The MIR edge starts `from_bb` (the outgoing / last BasicBlock in - // `from_bcb`) and ends at `to_bb` (the incoming / first BasicBlock in the - // `target_bcb`; also called the `leader_bb`). - let from_bb = self.bcb_last_bb(from_bcb); - let to_bb = self.bcb_leader_bb(target_bcb); - - let new_bb = inject_edge_counter_basic_block(self.mir_body, from_bb, to_bb); - debug!( - "Edge {:?} (last {:?}) -> {:?} (leader {:?}) requires a new MIR \ - BasicBlock {:?}, for unclaimed edge counter {:?}", - edge_from_bcb, from_bb, target_bcb, to_bb, new_bb, counter_kind, - ); - new_bb - } else { - let target_bb = self.bcb_last_bb(target_bcb); - debug!( - "{:?} ({:?}) gets a new Coverage statement for unclaimed counter {:?}", - target_bcb, target_bb, counter_kind, - ); - target_bb - }; - - inject_statement( - self.mir_body, - self.make_mir_coverage_kind(&counter_kind), - inject_to_bb, - ); - } - // Experessions with no associated spans don't need to inject a statement. - BcbCounter::Expression { .. } => {} + // Process the counters associated with BCB edges. + for (from_bcb, to_bcb, counter_kind) in self.coverage_counters.bcb_edge_counters() { + let do_inject = match counter_kind { + // Counter-increment statements always need to be injected. + BcbCounter::Counter { .. } => true, + // BCB-edge expressions never have mappings, so they never need + // a corresponding statement. + BcbCounter::Expression { .. } => false, + }; + if !do_inject { + continue; } - } - } - #[inline] - fn bcb_leader_bb(&self, bcb: BasicCoverageBlock) -> BasicBlock { - self.bcb_data(bcb).leader_bb() - } + // We need to inject a coverage statement into a new BB between the + // last BB of `from_bcb` and the first BB of `to_bcb`. + let from_bb = self.basic_coverage_blocks[from_bcb].last_bb(); + let to_bb = self.basic_coverage_blocks[to_bcb].leader_bb(); - #[inline] - fn bcb_last_bb(&self, bcb: BasicCoverageBlock) -> BasicBlock { - self.bcb_data(bcb).last_bb() - } + let new_bb = inject_edge_counter_basic_block(self.mir_body, from_bb, to_bb); + debug!( + "Edge {from_bcb:?} (last {from_bb:?}) -> {to_bcb:?} (leader {to_bb:?}) \ + requires a new MIR BasicBlock {new_bb:?} for edge counter {counter_kind:?}", + ); + + // Inject a counter into the newly-created BB. + inject_statement(self.mir_body, self.make_mir_coverage_kind(&counter_kind), new_bb); + } - #[inline] - fn bcb_data(&self, bcb: BasicCoverageBlock) -> &BasicCoverageBlockData { - &self.basic_coverage_blocks[bcb] + mappings } fn make_mir_coverage_kind(&self, counter_kind: &BcbCounter) -> CoverageKind { diff --git a/compiler/rustc_mir_transform/src/coverage/spans.rs b/compiler/rustc_mir_transform/src/coverage/spans.rs index 3f7ba5725104a..dde16cbd782e3 100644 --- a/compiler/rustc_mir_transform/src/coverage/spans.rs +++ b/compiler/rustc_mir_transform/src/coverage/spans.rs @@ -41,13 +41,8 @@ impl CoverageSpans { !self.bcb_to_spans[bcb].is_empty() } - pub(super) fn bcbs_with_coverage_spans( - &self, - ) -> impl Iterator { - self.bcb_to_spans.iter_enumerated().filter_map(|(bcb, spans)| { - // Only yield BCBs that have at least one coverage span. - (!spans.is_empty()).then_some((bcb, spans.as_slice())) - }) + pub(super) fn spans_for_bcb(&self, bcb: BasicCoverageBlock) -> &[Span] { + &self.bcb_to_spans[bcb] } }