Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Rollup of 4 pull requests #117442

Closed
wants to merge 9 commits into from
14 changes: 11 additions & 3 deletions compiler/rustc_hir_analysis/src/collect/type_of/opaque.rs
Original file line number Diff line number Diff line change
Expand Up @@ -183,9 +183,17 @@ impl TaitConstraintLocator<'_> {
};

// Use borrowck to get the type with unerased regions.
let concrete_opaque_types = &self.tcx.mir_borrowck(item_def_id).concrete_opaque_types;
debug!(?concrete_opaque_types);
if let Some(&concrete_type) = concrete_opaque_types.get(&self.def_id) {
let borrowck_results = &self.tcx.mir_borrowck(item_def_id);

// If the body was tainted, then assume the opaque may have been constrained and just set it to error.
if let Some(guar) = borrowck_results.tainted_by_errors {
self.found =
Some(ty::OpaqueHiddenType { span: DUMMY_SP, ty: Ty::new_error(self.tcx, guar) });
return;
}

debug!(?borrowck_results.concrete_opaque_types);
if let Some(&concrete_type) = borrowck_results.concrete_opaque_types.get(&self.def_id) {
debug!(?concrete_type, "found constraint");
if let Some(prev) = &mut self.found {
if concrete_type.ty != prev.ty && !(concrete_type, prev.ty).references_error() {
Expand Down
6 changes: 4 additions & 2 deletions compiler/rustc_middle/src/mir/consts.rs
Original file line number Diff line number Diff line change
Expand Up @@ -520,11 +520,13 @@ impl<'tcx> Const<'tcx> {
// types are fine though.
ty::ConstKind::Value(_) => c.ty().is_primitive(),
ty::ConstKind::Unevaluated(..) | ty::ConstKind::Expr(..) => false,
// This can happen if evaluation of a constant failed. The result does not matter
// much since compilation is doomed.
ty::ConstKind::Error(..) => false,
// Should not appear in runtime MIR.
ty::ConstKind::Infer(..)
| ty::ConstKind::Bound(..)
| ty::ConstKind::Placeholder(..)
| ty::ConstKind::Error(..) => bug!(),
| ty::ConstKind::Placeholder(..) => bug!(),
},
Const::Unevaluated(..) => false,
// If the same slice appears twice in the MIR, we cannot guarantee that we will
Expand Down
88 changes: 59 additions & 29 deletions compiler/rustc_mir_build/src/build/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -620,29 +620,63 @@ fn construct_const<'a, 'tcx>(
///
/// This is required because we may still want to run MIR passes on an item
/// with type errors, but normal MIR construction can't handle that in general.
fn construct_error(tcx: TyCtxt<'_>, def: LocalDefId, err: ErrorGuaranteed) -> Body<'_> {
let span = tcx.def_span(def);
let hir_id = tcx.hir().local_def_id_to_hir_id(def);
let coroutine_kind = tcx.coroutine_kind(def);
let body_owner_kind = tcx.hir().body_owner_kind(def);

let ty = Ty::new_error(tcx, err);
let num_params = match body_owner_kind {
hir::BodyOwnerKind::Fn => tcx.fn_sig(def).skip_binder().inputs().skip_binder().len(),
hir::BodyOwnerKind::Closure => {
let ty = tcx.type_of(def).instantiate_identity();
match ty.kind() {
ty::Closure(_, args) => 1 + args.as_closure().sig().inputs().skip_binder().len(),
ty::Coroutine(..) => 2,
_ => bug!("expected closure or coroutine, found {ty:?}"),
}
fn construct_error(tcx: TyCtxt<'_>, def_id: LocalDefId, guar: ErrorGuaranteed) -> Body<'_> {
let span = tcx.def_span(def_id);
let hir_id = tcx.hir().local_def_id_to_hir_id(def_id);
let coroutine_kind = tcx.coroutine_kind(def_id);

let (inputs, output, yield_ty) = match tcx.def_kind(def_id) {
DefKind::Const
| DefKind::AssocConst
| DefKind::AnonConst
| DefKind::InlineConst
| DefKind::Static(_) => (vec![], tcx.type_of(def_id).instantiate_identity(), None),
DefKind::Ctor(..) | DefKind::Fn | DefKind::AssocFn => {
let sig = tcx.liberate_late_bound_regions(
def_id.to_def_id(),
tcx.fn_sig(def_id).instantiate_identity(),
);
(sig.inputs().to_vec(), sig.output(), None)
}
DefKind::Closure => {
let closure_ty = tcx.type_of(def_id).instantiate_identity();
let ty::Closure(_, args) = closure_ty.kind() else { bug!() };
let args = args.as_closure();
let sig = tcx.liberate_late_bound_regions(def_id.to_def_id(), args.sig());
let self_ty = match args.kind() {
ty::ClosureKind::Fn => Ty::new_imm_ref(tcx, tcx.lifetimes.re_erased, closure_ty),
ty::ClosureKind::FnMut => Ty::new_mut_ref(tcx, tcx.lifetimes.re_erased, closure_ty),
ty::ClosureKind::FnOnce => closure_ty,
};
([self_ty].into_iter().chain(sig.inputs().to_vec()).collect(), sig.output(), None)
}
DefKind::Coroutine => {
let coroutine_ty = tcx.type_of(def_id).instantiate_identity();
let ty::Coroutine(_, args, _) = coroutine_ty.kind() else { bug!() };
let args = args.as_coroutine();
let yield_ty = args.yield_ty();
let return_ty = args.return_ty();
let self_ty = Ty::new_adt(
tcx,
tcx.adt_def(tcx.lang_items().pin_type().unwrap()),
tcx.mk_args(&[Ty::new_mut_ref(tcx, tcx.lifetimes.re_erased, coroutine_ty).into()]),
);
let coroutine_state = Ty::new_adt(
tcx,
tcx.adt_def(tcx.lang_items().gen_state().unwrap()),
tcx.mk_args(&[yield_ty.into(), return_ty.into()]),
);
(vec![self_ty, args.resume_ty()], coroutine_state, Some(yield_ty))
}
hir::BodyOwnerKind::Const { .. } => 0,
hir::BodyOwnerKind::Static(_) => 0,
dk => bug!("{:?} is not a body: {:?}", def_id, dk),
};

let source_info = SourceInfo { span, scope: OUTERMOST_SOURCE_SCOPE };
let local_decls = IndexVec::from_iter(
[output].iter().chain(&inputs).map(|ty| LocalDecl::with_source_info(*ty, source_info)),
);
let mut cfg = CFG { basic_blocks: IndexVec::new() };
let mut source_scopes = IndexVec::new();
let mut local_decls = IndexVec::from_elem_n(LocalDecl::new(ty, span), 1);

cfg.start_new_block();
source_scopes.push(SourceScopeData {
Expand All @@ -655,28 +689,24 @@ fn construct_error(tcx: TyCtxt<'_>, def: LocalDefId, err: ErrorGuaranteed) -> Bo
safety: Safety::Safe,
}),
});
let source_info = SourceInfo { span, scope: OUTERMOST_SOURCE_SCOPE };

// Some MIR passes will expect the number of parameters to match the
// function declaration.
for _ in 0..num_params {
local_decls.push(LocalDecl::with_source_info(ty, source_info));
}
cfg.terminate(START_BLOCK, source_info, TerminatorKind::Unreachable);

let mut body = Body::new(
MirSource::item(def.to_def_id()),
MirSource::item(def_id.to_def_id()),
cfg.basic_blocks,
source_scopes,
local_decls,
IndexVec::new(),
num_params,
inputs.len(),
vec![],
span,
coroutine_kind,
Some(err),
Some(guar),
);
body.coroutine.as_mut().map(|gen| gen.yield_ty = Some(ty));

body.coroutine.as_mut().map(|gen| gen.yield_ty = yield_ty);

body
}

Expand Down
97 changes: 40 additions & 57 deletions compiler/rustc_mir_transform/src/coverage/counters.rs
Original file line number Diff line number Diff line change
@@ -1,5 +1,3 @@
use super::Error;

use super::graph;

use graph::{BasicCoverageBlock, BcbBranch, CoverageGraph, TraverseCoverageGraphWithLoops};
Expand Down Expand Up @@ -53,7 +51,7 @@ pub(super) struct CoverageCounters {
/// edge between two BCBs.
bcb_edge_counters: FxHashMap<(BasicCoverageBlock, BasicCoverageBlock), BcbCounter>,
/// Tracks which BCBs have a counter associated with some incoming edge.
/// Only used by debug assertions, to verify that BCBs with incoming edge
/// Only used by assertions, to verify that BCBs with incoming edge
/// counters do not have their own physical counters (expressions are allowed).
bcb_has_incoming_edge_counters: BitSet<BasicCoverageBlock>,
/// Table of expression data, associating each expression ID with its
Expand Down Expand Up @@ -81,7 +79,7 @@ impl CoverageCounters {
&mut self,
basic_coverage_blocks: &CoverageGraph,
bcb_has_coverage_spans: impl Fn(BasicCoverageBlock) -> bool,
) -> Result<(), Error> {
) {
MakeBcbCounters::new(self, basic_coverage_blocks).make_bcb_counters(bcb_has_coverage_spans)
}

Expand Down Expand Up @@ -111,26 +109,23 @@ impl CoverageCounters {
self.expressions.len()
}

fn set_bcb_counter(
&mut self,
bcb: BasicCoverageBlock,
counter_kind: BcbCounter,
) -> Result<CovTerm, Error> {
debug_assert!(
fn set_bcb_counter(&mut self, bcb: BasicCoverageBlock, counter_kind: BcbCounter) -> CovTerm {
assert!(
// If the BCB has an edge counter (to be injected into a new `BasicBlock`), it can also
// have an expression (to be injected into an existing `BasicBlock` represented by this
// `BasicCoverageBlock`).
counter_kind.is_expression() || !self.bcb_has_incoming_edge_counters.contains(bcb),
"attempt to add a `Counter` to a BCB target with existing incoming edge counters"
);

let term = counter_kind.as_term();
if let Some(replaced) = self.bcb_counters[bcb].replace(counter_kind) {
Error::from_string(format!(
bug!(
"attempt to set a BasicCoverageBlock coverage counter more than once; \
{bcb:?} already had counter {replaced:?}",
))
);
} else {
Ok(term)
term
}
}

Expand All @@ -139,27 +134,26 @@ impl CoverageCounters {
from_bcb: BasicCoverageBlock,
to_bcb: BasicCoverageBlock,
counter_kind: BcbCounter,
) -> Result<CovTerm, Error> {
if level_enabled!(tracing::Level::DEBUG) {
// If the BCB has an edge counter (to be injected into a new `BasicBlock`), it can also
// have an expression (to be injected into an existing `BasicBlock` represented by this
// `BasicCoverageBlock`).
if self.bcb_counter(to_bcb).is_some_and(|c| !c.is_expression()) {
return Error::from_string(format!(
"attempt to add an incoming edge counter from {from_bcb:?} when the target BCB already \
has a `Counter`"
));
}
) -> CovTerm {
// If the BCB has an edge counter (to be injected into a new `BasicBlock`), it can also
// have an expression (to be injected into an existing `BasicBlock` represented by this
// `BasicCoverageBlock`).
if let Some(node_counter) = self.bcb_counter(to_bcb) && !node_counter.is_expression() {
bug!(
"attempt to add an incoming edge counter from {from_bcb:?} \
when the target BCB already has {node_counter:?}"
);
}

self.bcb_has_incoming_edge_counters.insert(to_bcb);
let term = counter_kind.as_term();
if let Some(replaced) = self.bcb_edge_counters.insert((from_bcb, to_bcb), counter_kind) {
Error::from_string(format!(
bug!(
"attempt to set an edge counter more than once; from_bcb: \
{from_bcb:?} already had counter {replaced:?}",
))
);
} else {
Ok(term)
term
}
}

Expand Down Expand Up @@ -213,14 +207,7 @@ impl<'a> MakeBcbCounters<'a> {
/// One way to predict which branch executes the least is by considering loops. A loop is exited
/// at a branch, so the branch that jumps to a `BasicCoverageBlock` outside the loop is almost
/// always executed less than the branch that does not exit the loop.
///
/// Returns any non-code-span expressions created to represent intermediate values (such as to
/// add two counters so the result can be subtracted from another counter), or an Error with
/// message for subsequent debugging.
fn make_bcb_counters(
&mut self,
bcb_has_coverage_spans: impl Fn(BasicCoverageBlock) -> bool,
) -> Result<(), Error> {
fn make_bcb_counters(&mut self, bcb_has_coverage_spans: impl Fn(BasicCoverageBlock) -> bool) {
debug!("make_bcb_counters(): adding a counter or expression to each BasicCoverageBlock");

// Walk the `CoverageGraph`. For each `BasicCoverageBlock` node with an associated
Expand All @@ -237,10 +224,10 @@ impl<'a> MakeBcbCounters<'a> {
while let Some(bcb) = traversal.next() {
if bcb_has_coverage_spans(bcb) {
debug!("{:?} has at least one coverage span. Get or make its counter", bcb);
let branching_counter_operand = self.get_or_make_counter_operand(bcb)?;
let branching_counter_operand = self.get_or_make_counter_operand(bcb);

if self.bcb_needs_branch_counters(bcb) {
self.make_branch_counters(&traversal, bcb, branching_counter_operand)?;
self.make_branch_counters(&traversal, bcb, branching_counter_operand);
}
} else {
debug!(
Expand All @@ -251,22 +238,19 @@ impl<'a> MakeBcbCounters<'a> {
}
}

if traversal.is_complete() {
Ok(())
} else {
Error::from_string(format!(
"`TraverseCoverageGraphWithLoops` missed some `BasicCoverageBlock`s: {:?}",
traversal.unvisited(),
))
}
assert!(
traversal.is_complete(),
"`TraverseCoverageGraphWithLoops` missed some `BasicCoverageBlock`s: {:?}",
traversal.unvisited(),
);
}

fn make_branch_counters(
&mut self,
traversal: &TraverseCoverageGraphWithLoops<'_>,
branching_bcb: BasicCoverageBlock,
branching_counter_operand: CovTerm,
) -> Result<(), Error> {
) {
let branches = self.bcb_branches(branching_bcb);
debug!(
"{:?} has some branch(es) without counters:\n {}",
Expand Down Expand Up @@ -299,10 +283,10 @@ impl<'a> MakeBcbCounters<'a> {
counter",
branch, branching_bcb
);
self.get_or_make_counter_operand(branch.target_bcb)?
self.get_or_make_counter_operand(branch.target_bcb)
} else {
debug!(" {:?} has multiple incoming edges, so adding an edge counter", branch);
self.get_or_make_edge_counter_operand(branching_bcb, branch.target_bcb)?
self.get_or_make_edge_counter_operand(branching_bcb, branch.target_bcb)
};
if let Some(sumup_counter_operand) =
some_sumup_counter_operand.replace(branch_counter_operand)
Expand Down Expand Up @@ -337,19 +321,18 @@ impl<'a> MakeBcbCounters<'a> {
debug!("{:?} gets an expression: {:?}", expression_branch, expression);
let bcb = expression_branch.target_bcb;
if expression_branch.is_only_path_to_target() {
self.coverage_counters.set_bcb_counter(bcb, expression)?;
self.coverage_counters.set_bcb_counter(bcb, expression);
} else {
self.coverage_counters.set_bcb_edge_counter(branching_bcb, bcb, expression)?;
self.coverage_counters.set_bcb_edge_counter(branching_bcb, bcb, expression);
}
Ok(())
}

#[instrument(level = "debug", skip(self))]
fn get_or_make_counter_operand(&mut self, bcb: BasicCoverageBlock) -> Result<CovTerm, Error> {
fn get_or_make_counter_operand(&mut self, bcb: BasicCoverageBlock) -> CovTerm {
// If the BCB already has a counter, return it.
if let Some(counter_kind) = &self.coverage_counters.bcb_counters[bcb] {
debug!("{bcb:?} already has a counter: {counter_kind:?}");
return Ok(counter_kind.as_term());
return counter_kind.as_term();
}

// A BCB with only one incoming edge gets a simple `Counter` (via `make_counter()`).
Expand Down Expand Up @@ -378,10 +361,10 @@ impl<'a> MakeBcbCounters<'a> {

let mut predecessors = self.bcb_predecessors(bcb).to_owned().into_iter();
let first_edge_counter_operand =
self.get_or_make_edge_counter_operand(predecessors.next().unwrap(), bcb)?;
self.get_or_make_edge_counter_operand(predecessors.next().unwrap(), bcb);
let mut some_sumup_edge_counter_operand = None;
for predecessor in predecessors {
let edge_counter_operand = self.get_or_make_edge_counter_operand(predecessor, bcb)?;
let edge_counter_operand = self.get_or_make_edge_counter_operand(predecessor, bcb);
if let Some(sumup_edge_counter_operand) =
some_sumup_edge_counter_operand.replace(edge_counter_operand)
{
Expand Down Expand Up @@ -411,7 +394,7 @@ impl<'a> MakeBcbCounters<'a> {
&mut self,
from_bcb: BasicCoverageBlock,
to_bcb: BasicCoverageBlock,
) -> Result<CovTerm, Error> {
) -> CovTerm {
// If the source BCB has only one successor (assumed to be the given target), an edge
// counter is unnecessary. Just get or make a counter for the source BCB.
let successors = self.bcb_successors(from_bcb).iter();
Expand All @@ -424,7 +407,7 @@ impl<'a> MakeBcbCounters<'a> {
self.coverage_counters.bcb_edge_counters.get(&(from_bcb, to_bcb))
{
debug!("Edge {from_bcb:?}->{to_bcb:?} already has a counter: {counter_kind:?}");
return Ok(counter_kind.as_term());
return counter_kind.as_term();
}

// Make a new counter to count this edge.
Expand Down
Loading
Loading