Auto merge of #114331 - matthiaskrgr:rollup-rnrmwcx, r=matthiaskrgr

Rollup of 7 pull requests

Successful merges:

 - #100455 (Implement RefUnwindSafe for Backtrace)
 - #113428 (coverage: Replace `ExpressionOperandId` with enum `Operand`)
 - #114283 (Use parking lot's rwlock even without parallel-rustc)
 - #114288 (Improve diagnostic for wrong borrow on binary operations)
 - #114296 (interpret: fix alignment handling for Repeat expressions)
 - #114306 ([rustc_data_structures][perf] Simplify base_n::push_str.)
 - #114320 (Cover statements for stable_mir)

r? `@ghost`
`@rustbot` modify labels: rollup
This commit is contained in:
bors 2023-08-01 16:09:13 +00:00
commit 4896daa398
30 changed files with 816 additions and 327 deletions

View File

@ -1,4 +1,4 @@
use rustc_middle::mir::coverage::{CounterValueReference, MappedExpressionIndex};
use rustc_middle::mir::coverage::{CounterId, MappedExpressionIndex};
/// Must match the layout of `LLVMRustCounterKind`.
#[derive(Copy, Clone, Debug)]
@ -36,11 +36,9 @@ impl Counter {
Self { kind: CounterKind::Zero, id: 0 }
}
/// Constructs a new `Counter` of kind `CounterValueReference`, and converts
/// the given 1-based counter_id to the required 0-based equivalent for
/// the `Counter` encoding.
pub fn counter_value_reference(counter_id: CounterValueReference) -> Self {
Self { kind: CounterKind::CounterValueReference, id: counter_id.zero_based_index() }
/// Constructs a new `Counter` of kind `CounterValueReference`.
pub fn counter_value_reference(counter_id: CounterId) -> Self {
Self { kind: CounterKind::CounterValueReference, id: counter_id.as_u32() }
}
/// Constructs a new `Counter` of kind `Expression`.

View File

@ -3,24 +3,22 @@ pub use super::ffi::*;
use rustc_index::{IndexSlice, IndexVec};
use rustc_middle::bug;
use rustc_middle::mir::coverage::{
CodeRegion, CounterValueReference, ExpressionOperandId, InjectedExpressionId,
InjectedExpressionIndex, MappedExpressionIndex, Op,
CodeRegion, CounterId, ExpressionId, MappedExpressionIndex, Op, Operand,
};
use rustc_middle::ty::Instance;
use rustc_middle::ty::TyCtxt;
#[derive(Clone, Debug, PartialEq)]
pub struct Expression {
lhs: ExpressionOperandId,
lhs: Operand,
op: Op,
rhs: ExpressionOperandId,
rhs: Operand,
region: Option<CodeRegion>,
}
/// Collects all of the coverage regions associated with (a) injected counters, (b) counter
/// expressions (additions or subtraction), and (c) unreachable regions (always counted as zero),
/// for a given Function. Counters and counter expressions have non-overlapping `id`s because they
/// can both be operands in an expression. This struct also stores the `function_source_hash`,
/// for a given Function. This struct also stores the `function_source_hash`,
/// computed during instrumentation, and forwarded with counters.
///
/// Note, it may be important to understand LLVM's definitions of `unreachable` regions versus "gap
@ -34,8 +32,8 @@ pub struct FunctionCoverage<'tcx> {
instance: Instance<'tcx>,
source_hash: u64,
is_used: bool,
counters: IndexVec<CounterValueReference, Option<CodeRegion>>,
expressions: IndexVec<InjectedExpressionIndex, Option<Expression>>,
counters: IndexVec<CounterId, Option<CodeRegion>>,
expressions: IndexVec<ExpressionId, Option<Expression>>,
unreachable_regions: Vec<CodeRegion>,
}
@ -82,48 +80,36 @@ impl<'tcx> FunctionCoverage<'tcx> {
}
/// Adds a code region to be counted by an injected counter intrinsic.
pub fn add_counter(&mut self, id: CounterValueReference, region: CodeRegion) {
pub fn add_counter(&mut self, id: CounterId, region: CodeRegion) {
if let Some(previous_region) = self.counters[id].replace(region.clone()) {
assert_eq!(previous_region, region, "add_counter: code region for id changed");
}
}
/// Both counters and "counter expressions" (or simply, "expressions") can be operands in other
/// expressions. Expression IDs start from `u32::MAX` and go down, so the range of expression
/// IDs will not overlap with the range of counter IDs. Counters and expressions can be added in
/// any order, and expressions can still be assigned contiguous (though descending) IDs, without
/// knowing what the last counter ID will be.
///
/// When storing the expression data in the `expressions` vector in the `FunctionCoverage`
/// struct, its vector index is computed, from the given expression ID, by subtracting from
/// `u32::MAX`.
///
/// Since the expression operands (`lhs` and `rhs`) can reference either counters or
/// expressions, an operand that references an expression also uses its original ID, descending
/// from `u32::MAX`. Theses operands are translated only during code generation, after all
/// counters and expressions have been added.
/// expressions. These are tracked as separate variants of `Operand`, so there is no ambiguity
/// between operands that are counter IDs and operands that are expression IDs.
pub fn add_counter_expression(
&mut self,
expression_id: InjectedExpressionId,
lhs: ExpressionOperandId,
expression_id: ExpressionId,
lhs: Operand,
op: Op,
rhs: ExpressionOperandId,
rhs: Operand,
region: Option<CodeRegion>,
) {
debug!(
"add_counter_expression({:?}, lhs={:?}, op={:?}, rhs={:?} at {:?}",
expression_id, lhs, op, rhs, region
);
let expression_index = self.expression_index(u32::from(expression_id));
debug_assert!(
expression_index.as_usize() < self.expressions.len(),
"expression_index {} is out of range for expressions.len() = {}
expression_id.as_usize() < self.expressions.len(),
"expression_id {} is out of range for expressions.len() = {}
for {:?}",
expression_index.as_usize(),
expression_id.as_usize(),
self.expressions.len(),
self,
);
if let Some(previous_expression) = self.expressions[expression_index].replace(Expression {
if let Some(previous_expression) = self.expressions[expression_id].replace(Expression {
lhs,
op,
rhs,
@ -186,14 +172,11 @@ impl<'tcx> FunctionCoverage<'tcx> {
// This closure converts any `Expression` operand (`lhs` or `rhs` of the `Op::Add` or
// `Op::Subtract` operation) into its native `llvm::coverage::Counter::CounterKind` type
// and value. Operand ID value `0` maps to `CounterKind::Zero`; values in the known range
// of injected LLVM counters map to `CounterKind::CounterValueReference` (and the value
// matches the injected counter index); and any other value is converted into a
// `CounterKind::Expression` with the expression's `new_index`.
// and value.
//
// Expressions will be returned from this function in a sequential vector (array) of
// `CounterExpression`, so the expression IDs must be mapped from their original,
// potentially sparse set of indexes, originally in reverse order from `u32::MAX`.
// potentially sparse set of indexes.
//
// An `Expression` as an operand will have already been encountered as an `Expression` with
// operands, so its new_index will already have been generated (as a 1-up index value).
@ -206,34 +189,19 @@ impl<'tcx> FunctionCoverage<'tcx> {
// `expression_index`s lower than the referencing `Expression`. Therefore, it is
// reasonable to look up the new index of an expression operand while the `new_indexes`
// vector is only complete up to the current `ExpressionIndex`.
let id_to_counter = |new_indexes: &IndexSlice<
InjectedExpressionIndex,
Option<MappedExpressionIndex>,
>,
id: ExpressionOperandId| {
if id == ExpressionOperandId::ZERO {
Some(Counter::zero())
} else if id.index() < self.counters.len() {
debug_assert!(
id.index() > 0,
"ExpressionOperandId indexes for counters are 1-based, but this id={}",
id.index()
);
// Note: Some codegen-injected Counters may be only referenced by `Expression`s,
// and may not have their own `CodeRegion`s,
let index = CounterValueReference::from(id.index());
// Note, the conversion to LLVM `Counter` adjusts the index to be zero-based.
Some(Counter::counter_value_reference(index))
} else {
let index = self.expression_index(u32::from(id));
type NewIndexes = IndexSlice<ExpressionId, Option<MappedExpressionIndex>>;
let id_to_counter = |new_indexes: &NewIndexes, operand: Operand| match operand {
Operand::Zero => Some(Counter::zero()),
Operand::Counter(id) => Some(Counter::counter_value_reference(id)),
Operand::Expression(id) => {
self.expressions
.get(index)
.get(id)
.expect("expression id is out of range")
.as_ref()
// If an expression was optimized out, assume it would have produced a count
// of zero. This ensures that expressions dependent on optimized-out
// expressions are still valid.
.map_or(Some(Counter::zero()), |_| new_indexes[index].map(Counter::expression))
.map_or(Some(Counter::zero()), |_| new_indexes[id].map(Counter::expression))
}
};
@ -340,9 +308,4 @@ impl<'tcx> FunctionCoverage<'tcx> {
fn unreachable_regions(&self) -> impl Iterator<Item = (Counter, &CodeRegion)> {
self.unreachable_regions.iter().map(|region| (Counter::zero(), region))
}
fn expression_index(&self, id_descending_from_max: u32) -> InjectedExpressionIndex {
debug_assert!(id_descending_from_max >= self.counters.len() as u32);
InjectedExpressionIndex::from(u32::MAX - id_descending_from_max)
}
}

View File

@ -16,9 +16,7 @@ use rustc_hir as hir;
use rustc_hir::def_id::DefId;
use rustc_llvm::RustString;
use rustc_middle::bug;
use rustc_middle::mir::coverage::{
CodeRegion, CounterValueReference, CoverageKind, ExpressionOperandId, InjectedExpressionId, Op,
};
use rustc_middle::mir::coverage::{CodeRegion, CounterId, CoverageKind, ExpressionId, Op, Operand};
use rustc_middle::mir::Coverage;
use rustc_middle::ty;
use rustc_middle::ty::layout::{FnAbiOf, HasTyCtxt};
@ -33,7 +31,7 @@ mod ffi;
pub(crate) mod map_data;
pub mod mapgen;
const UNUSED_FUNCTION_COUNTER_ID: CounterValueReference = CounterValueReference::START;
const UNUSED_FUNCTION_COUNTER_ID: CounterId = CounterId::START;
const VAR_ALIGN_BYTES: usize = 8;
@ -125,7 +123,7 @@ impl<'tcx> CoverageInfoBuilderMethods<'tcx> for Builder<'_, '_, 'tcx> {
let fn_name = bx.get_pgo_func_name_var(instance);
let hash = bx.const_u64(function_source_hash);
let num_counters = bx.const_u32(coverageinfo.num_counters);
let index = bx.const_u32(id.zero_based_index());
let index = bx.const_u32(id.as_u32());
debug!(
"codegen intrinsic instrprof.increment(fn_name={:?}, hash={:?}, num_counters={:?}, index={:?})",
fn_name, hash, num_counters, index,
@ -178,7 +176,7 @@ impl<'tcx> Builder<'_, '_, 'tcx> {
fn add_coverage_counter(
&mut self,
instance: Instance<'tcx>,
id: CounterValueReference,
id: CounterId,
region: CodeRegion,
) -> bool {
if let Some(coverage_context) = self.coverage_context() {
@ -202,10 +200,10 @@ impl<'tcx> Builder<'_, '_, 'tcx> {
fn add_coverage_counter_expression(
&mut self,
instance: Instance<'tcx>,
id: InjectedExpressionId,
lhs: ExpressionOperandId,
id: ExpressionId,
lhs: Operand,
op: Op,
rhs: ExpressionOperandId,
rhs: Operand,
region: Option<CodeRegion>,
) -> bool {
if let Some(coverage_context) = self.coverage_context() {

View File

@ -208,13 +208,13 @@ impl<'mir, 'tcx: 'mir, M: Machine<'mir, 'tcx>> InterpCx<'mir, 'tcx, M> {
let rest_ptr = first_ptr.offset(elem_size, self)?;
// For the alignment of `rest_ptr`, we crucially do *not* use `first.align` as
// that place might be more aligned than its type mandates (a `u8` array could
// be 4-aligned if it sits at the right spot in a struct). Instead we use
// `first.layout.align`, i.e., the alignment given by the type.
// be 4-aligned if it sits at the right spot in a struct). We have to also factor
// in element size.
self.mem_copy_repeatedly(
first_ptr,
first.align,
dest.align,
rest_ptr,
first.layout.align.abi,
dest.align.restrict_for_offset(elem_size),
elem_size,
length - 1,
/*nonoverlapping:*/ true,

View File

@ -16,22 +16,21 @@ const BASE_64: &[u8; MAX_BASE] =
pub fn push_str(mut n: u128, base: usize, output: &mut String) {
debug_assert!(base >= 2 && base <= MAX_BASE);
let mut s = [0u8; 128];
let mut index = 0;
let mut index = s.len();
let base = base as u128;
loop {
index -= 1;
s[index] = BASE_64[(n % base) as usize];
index += 1;
n /= base;
if n == 0 {
break;
}
}
s[0..index].reverse();
output.push_str(str::from_utf8(&s[0..index]).unwrap());
output.push_str(str::from_utf8(&s[index..]).unwrap());
}
#[inline]

View File

@ -43,37 +43,23 @@ impl<I: Idx, T: Copy> AppendOnlyIndexVec<I, T> {
#[derive(Default)]
pub struct AppendOnlyVec<T: Copy> {
#[cfg(not(parallel_compiler))]
vec: elsa::vec::FrozenVec<T>,
#[cfg(parallel_compiler)]
vec: elsa::sync::LockFreeFrozenVec<T>,
vec: parking_lot::RwLock<Vec<T>>,
}
impl<T: Copy> AppendOnlyVec<T> {
pub fn new() -> Self {
Self {
#[cfg(not(parallel_compiler))]
vec: elsa::vec::FrozenVec::new(),
#[cfg(parallel_compiler)]
vec: elsa::sync::LockFreeFrozenVec::new(),
}
Self { vec: Default::default() }
}
pub fn push(&self, val: T) -> usize {
#[cfg(not(parallel_compiler))]
let i = self.vec.len();
#[cfg(not(parallel_compiler))]
self.vec.push(val);
#[cfg(parallel_compiler)]
let i = self.vec.push(val);
i
let mut v = self.vec.write();
let n = v.len();
v.push(val);
n
}
pub fn get(&self, i: usize) -> Option<T> {
#[cfg(not(parallel_compiler))]
return self.vec.get_copy(i);
#[cfg(parallel_compiler)]
return self.vec.get(i);
self.vec.read().get(i).copied()
}
pub fn iter_enumerated(&self) -> impl Iterator<Item = (usize, T)> + '_ {

View File

@ -4,7 +4,7 @@ use super::method::MethodCallee;
use super::{has_expected_num_generic_args, FnCtxt};
use crate::Expectation;
use rustc_ast as ast;
use rustc_errors::{self, struct_span_err, Applicability, Diagnostic};
use rustc_errors::{self, struct_span_err, Applicability, Diagnostic, DiagnosticBuilder};
use rustc_hir as hir;
use rustc_infer::infer::type_variable::{TypeVariableOrigin, TypeVariableOriginKind};
use rustc_infer::traits::ObligationCauseCode;
@ -380,33 +380,93 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
}
};
let mut suggest_deref_binop = |lhs_deref_ty: Ty<'tcx>| {
if self
.lookup_op_method(
lhs_deref_ty,
Some((rhs_expr, rhs_ty)),
Op::Binary(op, is_assign),
expected,
)
.is_ok()
{
let msg = format!(
"`{}{}` can be used on `{}` if you dereference the left-hand side",
op.node.as_str(),
match is_assign {
IsAssign::Yes => "=",
IsAssign::No => "",
},
lhs_deref_ty,
);
err.span_suggestion_verbose(
lhs_expr.span.shrink_to_lo(),
msg,
"*",
rustc_errors::Applicability::MachineApplicable,
);
}
};
let suggest_deref_binop =
|err: &mut DiagnosticBuilder<'_, _>, lhs_deref_ty: Ty<'tcx>| {
if self
.lookup_op_method(
lhs_deref_ty,
Some((rhs_expr, rhs_ty)),
Op::Binary(op, is_assign),
expected,
)
.is_ok()
{
let msg = format!(
"`{}{}` can be used on `{}` if you dereference the left-hand side",
op.node.as_str(),
match is_assign {
IsAssign::Yes => "=",
IsAssign::No => "",
},
lhs_deref_ty,
);
err.span_suggestion_verbose(
lhs_expr.span.shrink_to_lo(),
msg,
"*",
rustc_errors::Applicability::MachineApplicable,
);
}
};
let suggest_different_borrow =
|err: &mut DiagnosticBuilder<'_, _>,
lhs_adjusted_ty,
lhs_new_mutbl: Option<ast::Mutability>,
rhs_adjusted_ty,
rhs_new_mutbl: Option<ast::Mutability>| {
if self
.lookup_op_method(
lhs_adjusted_ty,
Some((rhs_expr, rhs_adjusted_ty)),
Op::Binary(op, is_assign),
expected,
)
.is_ok()
{
let op_str = op.node.as_str();
err.note(format!("an implementation for `{lhs_adjusted_ty} {op_str} {rhs_adjusted_ty}` exists"));
if let Some(lhs_new_mutbl) = lhs_new_mutbl
&& let Some(rhs_new_mutbl) = rhs_new_mutbl
&& lhs_new_mutbl.is_not()
&& rhs_new_mutbl.is_not() {
err.multipart_suggestion_verbose(
"consider reborrowing both sides",
vec![
(lhs_expr.span.shrink_to_lo(), "&*".to_string()),
(rhs_expr.span.shrink_to_lo(), "&*".to_string())
],
rustc_errors::Applicability::MachineApplicable,
);
} else {
let mut suggest_new_borrow = |new_mutbl: ast::Mutability, sp: Span| {
// Can reborrow (&mut -> &)
if new_mutbl.is_not() {
err.span_suggestion_verbose(
sp.shrink_to_lo(),
"consider reborrowing this side",
"&*",
rustc_errors::Applicability::MachineApplicable,
);
// Works on &mut but have &
} else {
err.span_help(
sp,
"consider making this expression a mutable borrow",
);
}
};
if let Some(lhs_new_mutbl) = lhs_new_mutbl {
suggest_new_borrow(lhs_new_mutbl, lhs_expr.span);
}
if let Some(rhs_new_mutbl) = rhs_new_mutbl {
suggest_new_borrow(rhs_new_mutbl, rhs_expr.span);
}
}
}
};
let is_compatible_after_call = |lhs_ty, rhs_ty| {
self.lookup_op_method(
@ -429,15 +489,60 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
} else if is_assign == IsAssign::Yes
&& let Some(lhs_deref_ty) = self.deref_once_mutably_for_diagnostic(lhs_ty)
{
suggest_deref_binop(lhs_deref_ty);
suggest_deref_binop(&mut err, lhs_deref_ty);
} else if is_assign == IsAssign::No
&& let Ref(_, lhs_deref_ty, _) = lhs_ty.kind()
&& let Ref(region, lhs_deref_ty, mutbl) = lhs_ty.kind()
{
if self.type_is_copy_modulo_regions(
self.param_env,
*lhs_deref_ty,
) {
suggest_deref_binop(*lhs_deref_ty);
suggest_deref_binop(&mut err, *lhs_deref_ty);
} else {
let lhs_inv_mutbl = mutbl.invert();
let lhs_inv_mutbl_ty = Ty::new_ref(
self.tcx,
*region,
ty::TypeAndMut {
ty: *lhs_deref_ty,
mutbl: lhs_inv_mutbl,
},
);
suggest_different_borrow(
&mut err,
lhs_inv_mutbl_ty,
Some(lhs_inv_mutbl),
rhs_ty,
None,
);
if let Ref(region, rhs_deref_ty, mutbl) = rhs_ty.kind() {
let rhs_inv_mutbl = mutbl.invert();
let rhs_inv_mutbl_ty = Ty::new_ref(
self.tcx,
*region,
ty::TypeAndMut {
ty: *rhs_deref_ty,
mutbl: rhs_inv_mutbl,
},
);
suggest_different_borrow(
&mut err,
lhs_ty,
None,
rhs_inv_mutbl_ty,
Some(rhs_inv_mutbl),
);
suggest_different_borrow(
&mut err,
lhs_inv_mutbl_ty,
Some(lhs_inv_mutbl),
rhs_inv_mutbl_ty,
Some(rhs_inv_mutbl),
);
}
}
} else if self.suggest_fn_call(&mut err, lhs_expr, lhs_ty, |lhs_ty| {
is_compatible_after_call(lhs_ty, rhs_ty)

View File

@ -6,69 +6,43 @@ use rustc_span::Symbol;
use std::fmt::{self, Debug, Formatter};
rustc_index::newtype_index! {
/// An ExpressionOperandId value is assigned directly from either a
/// CounterValueReference.as_u32() (which ascend from 1) or an ExpressionOperandId.as_u32()
/// (which _*descend*_ from u32::MAX). Id value `0` (zero) represents a virtual counter with a
/// constant value of `0`.
/// ID of a coverage counter. Values ascend from 0.
///
/// Note that LLVM handles counter IDs as `uint32_t`, so there is no need
/// to use a larger representation on the Rust side.
#[derive(HashStable)]
#[max = 0xFFFF_FFFF]
#[debug_format = "ExpressionOperandId({})"]
pub struct ExpressionOperandId {
}
#[debug_format = "CounterId({})"]
pub struct CounterId {}
}
impl ExpressionOperandId {
/// An expression operand for a "zero counter", as described in the following references:
///
/// * <https://github.com/rust-lang/llvm-project/blob/rustc/13.0-2021-09-30/llvm/docs/CoverageMappingFormat.rst#counter>
/// * <https://github.com/rust-lang/llvm-project/blob/rustc/13.0-2021-09-30/llvm/docs/CoverageMappingFormat.rst#tag>
/// * <https://github.com/rust-lang/llvm-project/blob/rustc/13.0-2021-09-30/llvm/docs/CoverageMappingFormat.rst#counter-expressions>
///
/// This operand can be used to count two or more separate code regions with a single counter,
/// if they run sequentially with no branches, by injecting the `Counter` in a `BasicBlock` for
/// one of the code regions, and inserting `CounterExpression`s ("add ZERO to the counter") in
/// the coverage map for the other code regions.
pub const ZERO: Self = Self::from_u32(0);
}
impl CounterId {
pub const START: Self = Self::from_u32(0);
rustc_index::newtype_index! {
#[derive(HashStable)]
#[max = 0xFFFF_FFFF]
#[debug_format = "CounterValueReference({})"]
pub struct CounterValueReference {}
}
impl CounterValueReference {
/// Counters start at 1 to reserve 0 for ExpressionOperandId::ZERO.
pub const START: Self = Self::from_u32(1);
/// Returns explicitly-requested zero-based version of the counter id, used
/// during codegen. LLVM expects zero-based indexes.
pub fn zero_based_index(self) -> u32 {
let one_based_index = self.as_u32();
debug_assert!(one_based_index > 0);
one_based_index - 1
#[inline(always)]
pub fn next_id(self) -> Self {
Self::from_u32(self.as_u32() + 1)
}
}
rustc_index::newtype_index! {
/// InjectedExpressionId.as_u32() converts to ExpressionOperandId.as_u32()
/// ID of a coverage-counter expression. Values ascend from 0.
///
/// Values descend from u32::MAX.
/// Note that LLVM handles expression IDs as `uint32_t`, so there is no need
/// to use a larger representation on the Rust side.
#[derive(HashStable)]
#[max = 0xFFFF_FFFF]
#[debug_format = "InjectedExpressionId({})"]
pub struct InjectedExpressionId {}
#[debug_format = "ExpressionId({})"]
pub struct ExpressionId {}
}
rustc_index::newtype_index! {
/// InjectedExpressionIndex.as_u32() translates to u32::MAX - ExpressionOperandId.as_u32()
///
/// Values ascend from 0.
#[derive(HashStable)]
#[max = 0xFFFF_FFFF]
#[debug_format = "InjectedExpressionIndex({})"]
pub struct InjectedExpressionIndex {}
impl ExpressionId {
pub const START: Self = Self::from_u32(0);
#[inline(always)]
pub fn next_id(self) -> Self {
Self::from_u32(self.as_u32() + 1)
}
}
rustc_index::newtype_index! {
@ -81,17 +55,25 @@ rustc_index::newtype_index! {
pub struct MappedExpressionIndex {}
}
impl From<CounterValueReference> for ExpressionOperandId {
#[inline]
fn from(v: CounterValueReference) -> ExpressionOperandId {
ExpressionOperandId::from(v.as_u32())
}
/// Operand of a coverage-counter expression.
///
/// Operands can be a constant zero value, an actual coverage counter, or another
/// expression. Counter/expression operands are referred to by ID.
#[derive(Copy, Clone, PartialEq, Eq)]
#[derive(TyEncodable, TyDecodable, Hash, HashStable, TypeFoldable, TypeVisitable)]
pub enum Operand {
Zero,
Counter(CounterId),
Expression(ExpressionId),
}
impl From<InjectedExpressionId> for ExpressionOperandId {
#[inline]
fn from(v: InjectedExpressionId) -> ExpressionOperandId {
ExpressionOperandId::from(v.as_u32())
impl Debug for Operand {
fn fmt(&self, f: &mut Formatter<'_>) -> fmt::Result {
match self {
Self::Zero => write!(f, "Zero"),
Self::Counter(id) => f.debug_tuple("Counter").field(&id.as_u32()).finish(),
Self::Expression(id) => f.debug_tuple("Expression").field(&id.as_u32()).finish(),
}
}
}
@ -99,23 +81,27 @@ impl From<InjectedExpressionId> for ExpressionOperandId {
pub enum CoverageKind {
Counter {
function_source_hash: u64,
id: CounterValueReference,
/// ID of this counter within its enclosing function.
/// Expressions in the same function can refer to it as an operand.
id: CounterId,
},
Expression {
id: InjectedExpressionId,
lhs: ExpressionOperandId,
/// ID of this coverage-counter expression within its enclosing function.
/// Other expressions in the same function can refer to it as an operand.
id: ExpressionId,
lhs: Operand,
op: Op,
rhs: ExpressionOperandId,
rhs: Operand,
},
Unreachable,
}
impl CoverageKind {
pub fn as_operand_id(&self) -> ExpressionOperandId {
pub fn as_operand(&self) -> Operand {
use CoverageKind::*;
match *self {
Counter { id, .. } => ExpressionOperandId::from(id),
Expression { id, .. } => ExpressionOperandId::from(id),
Counter { id, .. } => Operand::Counter(id),
Expression { id, .. } => Operand::Expression(id),
Unreachable => bug!("Unreachable coverage cannot be part of an expression"),
}
}
@ -132,14 +118,14 @@ impl Debug for CoverageKind {
Counter { id, .. } => write!(fmt, "Counter({:?})", id.index()),
Expression { id, lhs, op, rhs } => write!(
fmt,
"Expression({:?}) = {} {} {}",
"Expression({:?}) = {:?} {} {:?}",
id.index(),
lhs.index(),
lhs,
match op {
Op::Add => "+",
Op::Subtract => "-",
},
rhs.index(),
rhs,
),
Unreachable => write!(fmt, "Unreachable"),
}

View File

@ -470,10 +470,8 @@ TrivialTypeTraversalAndLiftImpls! {
::rustc_hir::Unsafety,
::rustc_target::asm::InlineAsmRegOrRegClass,
::rustc_target::spec::abi::Abi,
crate::mir::coverage::ExpressionOperandId,
crate::mir::coverage::CounterValueReference,
crate::mir::coverage::InjectedExpressionId,
crate::mir::coverage::InjectedExpressionIndex,
crate::mir::coverage::CounterId,
crate::mir::coverage::ExpressionId,
crate::mir::coverage::MappedExpressionIndex,
crate::mir::Local,
crate::mir::Promoted,

View File

@ -16,8 +16,8 @@ use rustc_middle::mir::coverage::*;
/// `Coverage` statements.
pub(super) struct CoverageCounters {
function_source_hash: u64,
next_counter_id: u32,
num_expressions: u32,
next_counter_id: CounterId,
next_expression_id: ExpressionId,
pub debug_counters: DebugCounters,
}
@ -25,8 +25,8 @@ impl CoverageCounters {
pub fn new(function_source_hash: u64) -> Self {
Self {
function_source_hash,
next_counter_id: CounterValueReference::START.as_u32(),
num_expressions: 0,
next_counter_id: CounterId::START,
next_expression_id: ExpressionId::START,
debug_counters: DebugCounters::new(),
}
}
@ -65,9 +65,9 @@ impl CoverageCounters {
fn make_expression<F>(
&mut self,
lhs: ExpressionOperandId,
lhs: Operand,
op: Op,
rhs: ExpressionOperandId,
rhs: Operand,
debug_block_label_fn: F,
) -> CoverageKind
where
@ -81,33 +81,30 @@ impl CoverageCounters {
expression
}
pub fn make_identity_counter(&mut self, counter_operand: ExpressionOperandId) -> CoverageKind {
pub fn make_identity_counter(&mut self, counter_operand: Operand) -> CoverageKind {
let some_debug_block_label = if self.debug_counters.is_enabled() {
self.debug_counters.some_block_label(counter_operand).cloned()
} else {
None
};
self.make_expression(counter_operand, Op::Add, ExpressionOperandId::ZERO, || {
self.make_expression(counter_operand, Op::Add, Operand::Zero, || {
some_debug_block_label.clone()
})
}
/// Counter IDs start from one and go up.
fn next_counter(&mut self) -> CounterValueReference {
assert!(self.next_counter_id < u32::MAX - self.num_expressions);
fn next_counter(&mut self) -> CounterId {
let next = self.next_counter_id;
self.next_counter_id += 1;
CounterValueReference::from(next)
self.next_counter_id = next.next_id();
next
}
/// Expression IDs start from u32::MAX and go down because an Expression can reference
/// (add or subtract counts) of both Counter regions and Expression regions. The counter
/// expression operand IDs must be unique across both types.
fn next_expression(&mut self) -> InjectedExpressionId {
assert!(self.next_counter_id < u32::MAX - self.num_expressions);
let next = u32::MAX - self.num_expressions;
self.num_expressions += 1;
InjectedExpressionId::from(next)
/// Expression IDs start from 0 and go up.
/// (Counter IDs and Expression IDs are distinguished by the `Operand` enum.)
fn next_expression(&mut self) -> ExpressionId {
let next = self.next_expression_id;
self.next_expression_id = next.next_id();
next
}
}
@ -199,7 +196,7 @@ impl<'a> BcbCounters<'a> {
&mut self,
traversal: &mut TraverseCoverageGraphWithLoops,
branching_bcb: BasicCoverageBlock,
branching_counter_operand: ExpressionOperandId,
branching_counter_operand: Operand,
collect_intermediate_expressions: &mut Vec<CoverageKind>,
) -> Result<(), Error> {
let branches = self.bcb_branches(branching_bcb);
@ -261,7 +258,7 @@ impl<'a> BcbCounters<'a> {
" [new intermediate expression: {}]",
self.format_counter(&intermediate_expression)
);
let intermediate_expression_operand = intermediate_expression.as_operand_id();
let intermediate_expression_operand = intermediate_expression.as_operand();
collect_intermediate_expressions.push(intermediate_expression);
some_sumup_counter_operand.replace(intermediate_expression_operand);
}
@ -298,7 +295,7 @@ impl<'a> BcbCounters<'a> {
&mut self,
bcb: BasicCoverageBlock,
collect_intermediate_expressions: &mut Vec<CoverageKind>,
) -> Result<ExpressionOperandId, Error> {
) -> Result<Operand, Error> {
self.recursive_get_or_make_counter_operand(bcb, collect_intermediate_expressions, 1)
}
@ -307,7 +304,7 @@ impl<'a> BcbCounters<'a> {
bcb: BasicCoverageBlock,
collect_intermediate_expressions: &mut Vec<CoverageKind>,
debug_indent_level: usize,
) -> Result<ExpressionOperandId, Error> {
) -> Result<Operand, Error> {
// If the BCB already has a counter, return it.
if let Some(counter_kind) = self.basic_coverage_blocks[bcb].counter() {
debug!(
@ -316,7 +313,7 @@ impl<'a> BcbCounters<'a> {
bcb,
self.format_counter(counter_kind),
);
return Ok(counter_kind.as_operand_id());
return Ok(counter_kind.as_operand());
}
// A BCB with only one incoming edge gets a simple `Counter` (via `make_counter()`).
@ -383,7 +380,7 @@ impl<'a> BcbCounters<'a> {
NESTED_INDENT.repeat(debug_indent_level),
self.format_counter(&intermediate_expression)
);
let intermediate_expression_operand = intermediate_expression.as_operand_id();
let intermediate_expression_operand = intermediate_expression.as_operand();
collect_intermediate_expressions.push(intermediate_expression);
some_sumup_edge_counter_operand.replace(intermediate_expression_operand);
}
@ -408,7 +405,7 @@ impl<'a> BcbCounters<'a> {
from_bcb: BasicCoverageBlock,
to_bcb: BasicCoverageBlock,
collect_intermediate_expressions: &mut Vec<CoverageKind>,
) -> Result<ExpressionOperandId, Error> {
) -> Result<Operand, Error> {
self.recursive_get_or_make_edge_counter_operand(
from_bcb,
to_bcb,
@ -423,7 +420,7 @@ impl<'a> BcbCounters<'a> {
to_bcb: BasicCoverageBlock,
collect_intermediate_expressions: &mut Vec<CoverageKind>,
debug_indent_level: usize,
) -> Result<ExpressionOperandId, Error> {
) -> Result<Operand, Error> {
// 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();
@ -444,7 +441,7 @@ impl<'a> BcbCounters<'a> {
to_bcb,
self.format_counter(counter_kind)
);
return Ok(counter_kind.as_operand_id());
return Ok(counter_kind.as_operand());
}
// Make a new counter to count this edge.

View File

@ -246,7 +246,7 @@ impl Default for ExpressionFormat {
}
}
/// If enabled, this struct maintains a map from `CoverageKind` IDs (as `ExpressionOperandId`) to
/// If enabled, this struct maintains a map from `CoverageKind` IDs (as `Operand`) to
/// the `CoverageKind` data and optional label (normally, the counter's associated
/// `BasicCoverageBlock` format string, if any).
///
@ -258,7 +258,7 @@ impl Default for ExpressionFormat {
/// `DebugCounters` supports a recursive rendering of `Expression` counters, so they can be
/// presented as nested expressions such as `(bcb3 - (bcb0 + bcb1))`.
pub(super) struct DebugCounters {
some_counters: Option<FxHashMap<ExpressionOperandId, DebugCounter>>,
some_counters: Option<FxHashMap<Operand, DebugCounter>>,
}
impl DebugCounters {
@ -277,14 +277,14 @@ impl DebugCounters {
pub fn add_counter(&mut self, counter_kind: &CoverageKind, some_block_label: Option<String>) {
if let Some(counters) = &mut self.some_counters {
let id = counter_kind.as_operand_id();
let id = counter_kind.as_operand();
counters
.try_insert(id, DebugCounter::new(counter_kind.clone(), some_block_label))
.expect("attempt to add the same counter_kind to DebugCounters more than once");
}
}
pub fn some_block_label(&self, operand: ExpressionOperandId) -> Option<&String> {
pub fn some_block_label(&self, operand: Operand) -> Option<&String> {
self.some_counters.as_ref().and_then(|counters| {
counters.get(&operand).and_then(|debug_counter| debug_counter.some_block_label.as_ref())
})
@ -323,24 +323,24 @@ impl DebugCounters {
}
}
let id = counter_kind.as_operand_id();
let id = counter_kind.as_operand();
if self.some_counters.is_some() && (counter_format.block || !counter_format.id) {
let counters = self.some_counters.as_ref().unwrap();
if let Some(DebugCounter { some_block_label: Some(block_label), .. }) =
counters.get(&id)
{
return if counter_format.id {
format!("{}#{}", block_label, id.index())
format!("{}#{:?}", block_label, id)
} else {
block_label.to_string()
};
}
}
format!("#{}", id.index())
format!("#{:?}", id)
}
fn format_operand(&self, operand: ExpressionOperandId) -> String {
if operand.index() == 0 {
fn format_operand(&self, operand: Operand) -> String {
if matches!(operand, Operand::Zero) {
return String::from("0");
}
if let Some(counters) = &self.some_counters {
@ -358,7 +358,7 @@ impl DebugCounters {
return self.format_counter_kind(counter_kind);
}
}
format!("#{}", operand.index())
format!("#{:?}", operand)
}
}
@ -485,8 +485,7 @@ impl GraphvizData {
/// _not_ used are retained in the `unused_expressions` Vec, to be included in debug output (logs
/// and/or a `CoverageGraph` graphviz output).
pub(super) struct UsedExpressions {
some_used_expression_operands:
Option<FxHashMap<ExpressionOperandId, Vec<InjectedExpressionId>>>,
some_used_expression_operands: Option<FxHashMap<Operand, Vec<ExpressionId>>>,
some_unused_expressions:
Option<Vec<(CoverageKind, Option<BasicCoverageBlock>, BasicCoverageBlock)>>,
}
@ -517,7 +516,7 @@ impl UsedExpressions {
pub fn expression_is_used(&self, expression: &CoverageKind) -> bool {
if let Some(used_expression_operands) = self.some_used_expression_operands.as_ref() {
used_expression_operands.contains_key(&expression.as_operand_id())
used_expression_operands.contains_key(&expression.as_operand())
} else {
false
}
@ -530,7 +529,7 @@ impl UsedExpressions {
target_bcb: BasicCoverageBlock,
) {
if let Some(used_expression_operands) = self.some_used_expression_operands.as_ref() {
if !used_expression_operands.contains_key(&expression.as_operand_id()) {
if !used_expression_operands.contains_key(&expression.as_operand()) {
self.some_unused_expressions.as_mut().unwrap().push((
expression.clone(),
edge_from_bcb,

View File

@ -345,10 +345,7 @@ impl BasicCoverageBlockData {
&mir_body[self.last_bb()].terminator()
}
pub fn set_counter(
&mut self,
counter_kind: CoverageKind,
) -> Result<ExpressionOperandId, Error> {
pub fn set_counter(&mut self, counter_kind: CoverageKind) -> Result<Operand, Error> {
debug_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
@ -356,7 +353,7 @@ impl BasicCoverageBlockData {
self.edge_from_bcbs.is_none() || counter_kind.is_expression(),
"attempt to add a `Counter` to a BCB target with existing incoming edge counters"
);
let operand = counter_kind.as_operand_id();
let operand = counter_kind.as_operand();
if let Some(replaced) = self.counter_kind.replace(counter_kind) {
Error::from_string(format!(
"attempt to set a BasicCoverageBlock coverage counter more than once; \
@ -381,7 +378,7 @@ impl BasicCoverageBlockData {
&mut self,
from_bcb: BasicCoverageBlock,
counter_kind: CoverageKind,
) -> Result<ExpressionOperandId, Error> {
) -> Result<Operand, 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
@ -393,7 +390,7 @@ impl BasicCoverageBlockData {
));
}
}
let operand = counter_kind.as_operand_id();
let operand = counter_kind.as_operand();
if let Some(replaced) =
self.edge_from_bcbs.get_or_insert_default().insert(from_bcb, counter_kind)
{

View File

@ -304,7 +304,7 @@ impl<'a, 'tcx> Instrumentor<'a, 'tcx> {
let counter_kind = if let Some(&counter_operand) = bcb_counters[bcb].as_ref() {
self.coverage_counters.make_identity_counter(counter_operand)
} else if let Some(counter_kind) = self.bcb_data_mut(bcb).take_counter() {
bcb_counters[bcb] = Some(counter_kind.as_operand_id());
bcb_counters[bcb] = Some(counter_kind.as_operand());
debug_used_expressions.add_expression_operands(&counter_kind);
counter_kind
} else {

View File

@ -43,43 +43,25 @@ struct CoverageVisitor {
}
impl CoverageVisitor {
/// Updates `num_counters` to the maximum encountered zero-based counter_id plus 1. Note the
/// final computed number of counters should be the number of all `CoverageKind::Counter`
/// statements in the MIR *plus one* for the implicit `ZERO` counter.
/// Updates `num_counters` to the maximum encountered counter ID plus 1.
#[inline(always)]
fn update_num_counters(&mut self, counter_id: u32) {
fn update_num_counters(&mut self, counter_id: CounterId) {
let counter_id = counter_id.as_u32();
self.info.num_counters = std::cmp::max(self.info.num_counters, counter_id + 1);
}
/// Computes an expression index for each expression ID, and updates `num_expressions` to the
/// maximum encountered index plus 1.
/// Updates `num_expressions` to the maximum encountered expression ID plus 1.
#[inline(always)]
fn update_num_expressions(&mut self, expression_id: u32) {
let expression_index = u32::MAX - expression_id;
self.info.num_expressions = std::cmp::max(self.info.num_expressions, expression_index + 1);
fn update_num_expressions(&mut self, expression_id: ExpressionId) {
let expression_id = expression_id.as_u32();
self.info.num_expressions = std::cmp::max(self.info.num_expressions, expression_id + 1);
}
fn update_from_expression_operand(&mut self, operand_id: u32) {
if operand_id >= self.info.num_counters {
let operand_as_expression_index = u32::MAX - operand_id;
if operand_as_expression_index >= self.info.num_expressions {
// The operand ID is outside the known range of counter IDs and also outside the
// known range of expression IDs. In either case, the result of a missing operand
// (if and when used in an expression) will be zero, so from a computation
// perspective, it doesn't matter whether it is interpreted as a counter or an
// expression.
//
// However, the `num_counters` and `num_expressions` query results are used to
// allocate arrays when generating the coverage map (during codegen), so choose
// the type that grows either `num_counters` or `num_expressions` the least.
if operand_id - self.info.num_counters
< operand_as_expression_index - self.info.num_expressions
{
self.update_num_counters(operand_id)
} else {
self.update_num_expressions(operand_id)
}
}
fn update_from_expression_operand(&mut self, operand: Operand) {
match operand {
Operand::Counter(id) => self.update_num_counters(id),
Operand::Expression(id) => self.update_num_expressions(id),
Operand::Zero => {}
}
}
@ -100,19 +82,15 @@ impl CoverageVisitor {
if self.add_missing_operands {
match coverage.kind {
CoverageKind::Expression { lhs, rhs, .. } => {
self.update_from_expression_operand(u32::from(lhs));
self.update_from_expression_operand(u32::from(rhs));
self.update_from_expression_operand(lhs);
self.update_from_expression_operand(rhs);
}
_ => {}
}
} else {
match coverage.kind {
CoverageKind::Counter { id, .. } => {
self.update_num_counters(u32::from(id));
}
CoverageKind::Expression { id, .. } => {
self.update_num_expressions(u32::from(id));
}
CoverageKind::Counter { id, .. } => self.update_num_counters(id),
CoverageKind::Expression { id, .. } => self.update_num_expressions(id),
_ => {}
}
}
@ -123,8 +101,7 @@ fn coverageinfo<'tcx>(tcx: TyCtxt<'tcx>, instance_def: ty::InstanceDef<'tcx>) ->
let mir_body = tcx.instance_mir(instance_def);
let mut coverage_visitor = CoverageVisitor {
// num_counters always has at least the `ZERO` counter.
info: CoverageInfo { num_counters: 1, num_expressions: 0 },
info: CoverageInfo { num_counters: 0, num_expressions: 0 },
add_missing_operands: false,
};

View File

@ -683,7 +683,7 @@ fn test_make_bcb_counters() {
let_bcb!(1);
assert_eq!(
1, // coincidentally, bcb1 has a `Counter` with id = 1
0, // bcb1 has a `Counter` with id = 0
match basic_coverage_blocks[bcb1].counter().expect("should have a counter") {
CoverageKind::Counter { id, .. } => id,
_ => panic!("expected a Counter"),
@ -693,7 +693,7 @@ fn test_make_bcb_counters() {
let_bcb!(2);
assert_eq!(
2, // coincidentally, bcb2 has a `Counter` with id = 2
1, // bcb2 has a `Counter` with id = 1
match basic_coverage_blocks[bcb2].counter().expect("should have a counter") {
CoverageKind::Counter { id, .. } => id,
_ => panic!("expected a Counter"),

View File

@ -8,11 +8,13 @@
//! For now, we are developing everything inside `rustc`, thus, we keep this module private.
use crate::rustc_internal::{self, opaque};
use crate::stable_mir::mir::{CopyNonOverlapping, UserTypeProjection, VariantIdx};
use crate::stable_mir::ty::{FloatTy, IntTy, Movability, RigidTy, TyKind, UintTy};
use crate::stable_mir::{self, Context};
use rustc_hir as hir;
use rustc_middle::mir;
use rustc_middle::ty::{self, Ty, TyCtxt};
use rustc_middle::mir::coverage::CodeRegion;
use rustc_middle::mir::{self};
use rustc_middle::ty::{self, Ty, TyCtxt, Variance};
use rustc_span::def_id::{CrateNum, DefId, LOCAL_CRATE};
use rustc_target::abi::FieldIdx;
use tracing::debug;
@ -110,17 +112,38 @@ impl<'tcx> Stable<'tcx> for mir::Statement<'tcx> {
Assign(assign) => {
stable_mir::mir::Statement::Assign(assign.0.stable(tables), assign.1.stable(tables))
}
FakeRead(_) => todo!(),
SetDiscriminant { .. } => todo!(),
Deinit(_) => todo!(),
StorageLive(_) => todo!(),
StorageDead(_) => todo!(),
Retag(_, _) => todo!(),
PlaceMention(_) => todo!(),
AscribeUserType(_, _) => todo!(),
Coverage(_) => todo!(),
Intrinsic(_) => todo!(),
ConstEvalCounter => todo!(),
FakeRead(fake_read_place) => stable_mir::mir::Statement::FakeRead(
fake_read_place.0.stable(tables),
fake_read_place.1.stable(tables),
),
SetDiscriminant { place: plc, variant_index: idx } => {
stable_mir::mir::Statement::SetDiscriminant {
place: plc.as_ref().stable(tables),
variant_index: idx.stable(tables),
}
}
Deinit(place) => stable_mir::mir::Statement::Deinit(place.stable(tables)),
StorageLive(place) => stable_mir::mir::Statement::StorageLive(place.stable(tables)),
StorageDead(place) => stable_mir::mir::Statement::StorageDead(place.stable(tables)),
Retag(retag, place) => {
stable_mir::mir::Statement::Retag(retag.stable(tables), place.stable(tables))
}
PlaceMention(place) => stable_mir::mir::Statement::PlaceMention(place.stable(tables)),
AscribeUserType(place_projection, variance) => {
stable_mir::mir::Statement::AscribeUserType {
place: place_projection.as_ref().0.stable(tables),
projections: place_projection.as_ref().1.stable(tables),
variance: variance.stable(tables),
}
}
Coverage(coverage) => stable_mir::mir::Statement::Coverage(stable_mir::mir::Coverage {
kind: coverage.kind.stable(tables),
code_region: coverage.code_region.as_ref().map(|reg| reg.stable(tables)),
}),
Intrinsic(intrinstic) => {
stable_mir::mir::Statement::Intrinsic(intrinstic.stable(tables))
}
ConstEvalCounter => stable_mir::mir::Statement::ConstEvalCounter,
Nop => stable_mir::mir::Statement::Nop,
}
}
@ -364,6 +387,22 @@ impl<'tcx> Stable<'tcx> for rustc_hir::Unsafety {
}
}
impl<'tcx> Stable<'tcx> for mir::FakeReadCause {
type T = stable_mir::mir::FakeReadCause;
fn stable(&self, _: &mut Tables<'tcx>) -> Self::T {
use mir::FakeReadCause::*;
match self {
ForMatchGuard => stable_mir::mir::FakeReadCause::ForMatchGuard,
ForMatchedPlace(local_def_id) => {
stable_mir::mir::FakeReadCause::ForMatchedPlace(opaque(local_def_id))
}
ForGuardBinding => stable_mir::mir::FakeReadCause::ForGuardBinding,
ForLet(local_def_id) => stable_mir::mir::FakeReadCause::ForLet(opaque(local_def_id)),
ForIndex => stable_mir::mir::FakeReadCause::ForIndex,
}
}
}
impl<'tcx> Stable<'tcx> for FieldIdx {
type T = usize;
fn stable(&self, _: &mut Tables<'tcx>) -> Self::T {
@ -393,6 +432,110 @@ impl<'tcx> Stable<'tcx> for mir::Place<'tcx> {
}
}
impl<'tcx> Stable<'tcx> for mir::coverage::CoverageKind {
type T = stable_mir::mir::CoverageKind;
fn stable(&self, tables: &mut Tables<'tcx>) -> Self::T {
use rustc_middle::mir::coverage::CoverageKind;
match self {
CoverageKind::Counter { function_source_hash, id } => {
stable_mir::mir::CoverageKind::Counter {
function_source_hash: *function_source_hash as usize,
id: opaque(id),
}
}
CoverageKind::Expression { id, lhs, op, rhs } => {
stable_mir::mir::CoverageKind::Expression {
id: opaque(id),
lhs: opaque(lhs),
op: op.stable(tables),
rhs: opaque(rhs),
}
}
CoverageKind::Unreachable => stable_mir::mir::CoverageKind::Unreachable,
}
}
}
impl<'tcx> Stable<'tcx> for mir::UserTypeProjection {
type T = stable_mir::mir::UserTypeProjection;
fn stable(&self, _: &mut Tables<'tcx>) -> Self::T {
UserTypeProjection { base: self.base.as_usize(), projection: format!("{:?}", self.projs) }
}
}
impl<'tcx> Stable<'tcx> for mir::coverage::Op {
type T = stable_mir::mir::Op;
fn stable(&self, _: &mut Tables<'tcx>) -> Self::T {
use rustc_middle::mir::coverage::Op::*;
match self {
Subtract => stable_mir::mir::Op::Subtract,
Add => stable_mir::mir::Op::Add,
}
}
}
impl<'tcx> Stable<'tcx> for mir::Local {
type T = stable_mir::mir::Local;
fn stable(&self, _: &mut Tables<'tcx>) -> Self::T {
self.as_usize()
}
}
impl<'tcx> Stable<'tcx> for rustc_target::abi::VariantIdx {
type T = VariantIdx;
fn stable(&self, _: &mut Tables<'tcx>) -> Self::T {
self.as_usize()
}
}
impl<'tcx> Stable<'tcx> for Variance {
type T = stable_mir::mir::Variance;
fn stable(&self, _: &mut Tables<'tcx>) -> Self::T {
match self {
Variance::Bivariant => stable_mir::mir::Variance::Bivariant,
Variance::Contravariant => stable_mir::mir::Variance::Contravariant,
Variance::Covariant => stable_mir::mir::Variance::Covariant,
Variance::Invariant => stable_mir::mir::Variance::Invariant,
}
}
}
impl<'tcx> Stable<'tcx> for mir::RetagKind {
type T = stable_mir::mir::RetagKind;
fn stable(&self, _: &mut Tables<'tcx>) -> Self::T {
use rustc_middle::mir::RetagKind;
match self {
RetagKind::FnEntry => stable_mir::mir::RetagKind::FnEntry,
RetagKind::TwoPhase => stable_mir::mir::RetagKind::TwoPhase,
RetagKind::Raw => stable_mir::mir::RetagKind::Raw,
RetagKind::Default => stable_mir::mir::RetagKind::Default,
}
}
}
impl<'tcx> Stable<'tcx> for rustc_middle::ty::UserTypeAnnotationIndex {
type T = usize;
fn stable(&self, _: &mut Tables<'tcx>) -> Self::T {
self.as_usize()
}
}
impl<'tcx> Stable<'tcx> for CodeRegion {
type T = stable_mir::mir::CodeRegion;
fn stable(&self, _: &mut Tables<'tcx>) -> Self::T {
stable_mir::mir::CodeRegion {
file_name: self.file_name.as_str().to_string(),
start_line: self.start_line as usize,
start_col: self.start_col as usize,
end_line: self.end_line as usize,
end_col: self.end_col as usize,
}
}
}
impl<'tcx> Stable<'tcx> for mir::UnwindAction {
type T = stable_mir::mir::UnwindAction;
fn stable(&self, _: &mut Tables<'tcx>) -> Self::T {
@ -406,6 +549,26 @@ impl<'tcx> Stable<'tcx> for mir::UnwindAction {
}
}
impl<'tcx> Stable<'tcx> for mir::NonDivergingIntrinsic<'tcx> {
type T = stable_mir::mir::NonDivergingIntrinsic;
fn stable(&self, tables: &mut Tables<'tcx>) -> Self::T {
use rustc_middle::mir::NonDivergingIntrinsic;
match self {
NonDivergingIntrinsic::Assume(op) => {
stable_mir::mir::NonDivergingIntrinsic::Assume(op.stable(tables))
}
NonDivergingIntrinsic::CopyNonOverlapping(copy_non_overlapping) => {
stable_mir::mir::NonDivergingIntrinsic::CopyNonOverlapping(CopyNonOverlapping {
src: copy_non_overlapping.src.stable(tables),
dst: copy_non_overlapping.dst.stable(tables),
count: copy_non_overlapping.count.stable(tables),
})
}
}
}
}
impl<'tcx> Stable<'tcx> for mir::AssertMessage<'tcx> {
type T = stable_mir::mir::AssertMessage;
fn stable(&self, tables: &mut Tables<'tcx>) -> Self::T {

View File

@ -1,3 +1,4 @@
use crate::rustc_internal::Opaque;
use crate::stable_mir::ty::{
AdtDef, ClosureDef, Const, GeneratorDef, GenericArgs, Movability, Region,
};
@ -133,9 +134,101 @@ pub enum AsyncGeneratorKind {
Fn,
}
pub(crate) type LocalDefId = Opaque;
pub(crate) type CounterValueReference = Opaque;
pub(crate) type InjectedExpressionId = Opaque;
pub(crate) type ExpressionOperandId = Opaque;
/// The FakeReadCause describes the type of pattern why a FakeRead statement exists.
#[derive(Clone, Debug)]
pub enum FakeReadCause {
ForMatchGuard,
ForMatchedPlace(LocalDefId),
ForGuardBinding,
ForLet(LocalDefId),
ForIndex,
}
/// Describes what kind of retag is to be performed
#[derive(Clone, Debug)]
pub enum RetagKind {
FnEntry,
TwoPhase,
Raw,
Default,
}
#[derive(Clone, Debug)]
pub enum Variance {
Covariant,
Invariant,
Contravariant,
Bivariant,
}
#[derive(Clone, Debug)]
pub enum Op {
Subtract,
Add,
}
#[derive(Clone, Debug)]
pub enum CoverageKind {
Counter {
function_source_hash: usize,
id: CounterValueReference,
},
Expression {
id: InjectedExpressionId,
lhs: ExpressionOperandId,
op: Op,
rhs: ExpressionOperandId,
},
Unreachable,
}
#[derive(Clone, Debug)]
pub struct CodeRegion {
pub file_name: String,
pub start_line: usize,
pub start_col: usize,
pub end_line: usize,
pub end_col: usize,
}
#[derive(Clone, Debug)]
pub struct Coverage {
pub kind: CoverageKind,
pub code_region: Option<CodeRegion>,
}
#[derive(Clone, Debug)]
pub struct CopyNonOverlapping {
pub src: Operand,
pub dst: Operand,
pub count: Operand,
}
#[derive(Clone, Debug)]
pub enum NonDivergingIntrinsic {
Assume(Operand),
CopyNonOverlapping(CopyNonOverlapping),
}
#[derive(Clone, Debug)]
pub enum Statement {
Assign(Place, Rvalue),
FakeRead(FakeReadCause, Place),
SetDiscriminant { place: Place, variant_index: VariantIdx },
Deinit(Place),
StorageLive(Local),
StorageDead(Local),
Retag(RetagKind, Place),
PlaceMention(Place),
AscribeUserType { place: Place, projections: UserTypeProjection, variance: Variance },
Coverage(Coverage),
Intrinsic(NonDivergingIntrinsic),
ConstEvalCounter,
Nop,
}
@ -271,14 +364,22 @@ pub enum Operand {
#[derive(Clone, Debug)]
pub struct Place {
pub local: usize,
pub local: Local,
pub projection: String,
}
#[derive(Clone, Debug)]
pub struct UserTypeProjection {
pub base: UserTypeAnnotationIndex,
pub projection: String,
}
pub type Local = usize;
type FieldIdx = usize;
/// The source-order index of a variant in a type.
type VariantIdx = usize;
pub type VariantIdx = usize;
type UserTypeAnnotationIndex = usize;

View File

@ -92,6 +92,7 @@ use crate::backtrace_rs::{self, BytesOrWideString};
use crate::env;
use crate::ffi::c_void;
use crate::fmt;
use crate::panic::UnwindSafe;
use crate::sync::atomic::{AtomicUsize, Ordering::Relaxed};
use crate::sync::LazyLock;
use crate::sys_common::backtrace::{lock, output_filename};
@ -427,7 +428,7 @@ impl fmt::Display for Backtrace {
}
}
type LazyResolve = impl (FnOnce() -> Capture) + Send + Sync;
type LazyResolve = impl (FnOnce() -> Capture) + Send + Sync + UnwindSafe;
fn lazy_resolve(mut capture: Capture) -> LazyResolve {
move || {

View File

@ -1,4 +1,5 @@
use super::*;
use crate::panic::{RefUnwindSafe, UnwindSafe};
fn generate_fake_frames() -> Vec<BacktraceFrame> {
vec![
@ -91,3 +92,9 @@ fn test_frames() {
assert!(iter.all(|(f, e)| format!("{f:#?}") == *e));
}
#[test]
fn backtrace_unwind_safe() {
fn assert_unwind_safe<T: UnwindSafe + RefUnwindSafe>() {}
assert_unwind_safe::<Backtrace>();
}

View File

@ -0,0 +1,22 @@
#![feature(custom_mir, core_intrinsics)]
use std::intrinsics::mir::*;
#[repr(packed)]
struct S { field: [u32; 2] }
#[custom_mir(dialect = "runtime", phase = "optimized")]
fn test() { mir! {
let s: S;
{
// Store a repeat expression directly into a field of a packed struct.
s.field = [0; 2];
Return()
}
} }
fn main() {
// Run this a bunch of time to make sure it doesn't pass by chance.
for _ in 0..20 {
test();
}
}

View File

@ -4,6 +4,8 @@ use std::mem::size_of;
fn main() {
let mut a = Params::new();
// The array itself here happens to be quite well-aligned, but not all its elements have that
// large alignment and we better make sure that is still accepted by Miri.
a.key_block = [0; BLOCKBYTES];
}

View File

@ -2,5 +2,5 @@ digraph Cov_0_4 {
graph [fontname="Courier, monospace"];
node [fontname="Courier, monospace"];
edge [fontname="Courier, monospace"];
bcb0__Cov_0_4 [shape="none", label=<<table border="0" cellborder="1" cellspacing="0"><tr><td bgcolor="gray" align="center" colspan="1">bcb0</td></tr><tr><td align="left" balign="left"></td></tr><tr><td align="left" balign="left">Counter(bcb0) at 18:1-20:2<br align="left"/> 19:5-19:9: @0[0]: Coverage::Counter(1) for $DIR/coverage_graphviz.rs:18:1 - 20:2<br align="left"/> 20:2-20:2: @0.Return: return</td></tr><tr><td align="left" balign="left">bb0: Return</td></tr></table>>];
bcb0__Cov_0_4 [shape="none", label=<<table border="0" cellborder="1" cellspacing="0"><tr><td bgcolor="gray" align="center" colspan="1">bcb0</td></tr><tr><td align="left" balign="left"></td></tr><tr><td align="left" balign="left">Counter(bcb0) at 18:1-20:2<br align="left"/> 19:5-19:9: @0[0]: Coverage::Counter(0) for $DIR/coverage_graphviz.rs:18:1 - 20:2<br align="left"/> 20:2-20:2: @0.Return: return</td></tr><tr><td align="left" balign="left">bb0: Return</td></tr></table>>];
}

View File

@ -2,8 +2,8 @@ digraph Cov_0_3 {
graph [fontname="Courier, monospace"];
node [fontname="Courier, monospace"];
edge [fontname="Courier, monospace"];
bcb3__Cov_0_3 [shape="none", label=<<table border="0" cellborder="1" cellspacing="0"><tr><td bgcolor="gray" align="center" colspan="1">bcb3</td></tr><tr><td align="left" balign="left">Counter(bcb3) at 13:10-13:10<br align="left"/> 13:10-13:10: @5[0]: Coverage::Counter(2) for $DIR/coverage_graphviz.rs:13:10 - 13:11</td></tr><tr><td align="left" balign="left">bb5: Goto</td></tr></table>>];
bcb2__Cov_0_3 [shape="none", label=<<table border="0" cellborder="1" cellspacing="0"><tr><td bgcolor="gray" align="center" colspan="1">bcb2</td></tr><tr><td align="left" balign="left">Expression(bcb1:(bcb0 + bcb3) - bcb3) at 12:13-12:18<br align="left"/> 12:13-12:18: @4[0]: Coverage::Expression(4294967293) = 4294967294 + 0 for $DIR/coverage_graphviz.rs:15:1 - 15:2<br align="left"/>Expression(bcb2:(bcb1:(bcb0 + bcb3) - bcb3) + 0) at 15:2-15:2<br align="left"/> 15:2-15:2: @4.Return: return</td></tr><tr><td align="left" balign="left">bb4: Return</td></tr></table>>];
bcb3__Cov_0_3 [shape="none", label=<<table border="0" cellborder="1" cellspacing="0"><tr><td bgcolor="gray" align="center" colspan="1">bcb3</td></tr><tr><td align="left" balign="left">Counter(bcb3) at 13:10-13:10<br align="left"/> 13:10-13:10: @5[0]: Coverage::Counter(1) for $DIR/coverage_graphviz.rs:13:10 - 13:11</td></tr><tr><td align="left" balign="left">bb5: Goto</td></tr></table>>];
bcb2__Cov_0_3 [shape="none", label=<<table border="0" cellborder="1" cellspacing="0"><tr><td bgcolor="gray" align="center" colspan="1">bcb2</td></tr><tr><td align="left" balign="left">Expression(bcb1:(bcb0 + bcb3) - bcb3) at 12:13-12:18<br align="left"/> 12:13-12:18: @4[0]: Coverage::Expression(2) = Expression(1) + Zero for $DIR/coverage_graphviz.rs:15:1 - 15:2<br align="left"/>Expression(bcb2:(bcb1:(bcb0 + bcb3) - bcb3) + 0) at 15:2-15:2<br align="left"/> 15:2-15:2: @4.Return: return</td></tr><tr><td align="left" balign="left">bb4: Return</td></tr></table>>];
bcb1__Cov_0_3 [shape="none", label=<<table border="0" cellborder="1" cellspacing="0"><tr><td bgcolor="gray" align="center" colspan="1">bcb1</td></tr><tr><td align="left" balign="left">Expression(bcb0 + bcb3) at 10:5-11:17<br align="left"/> 11:12-11:17: @2.Call: _2 = bar() -&gt; [return: bb3, unwind: bb6]</td></tr><tr><td align="left" balign="left">bb1: FalseUnwind<br align="left"/>bb2: Call</td></tr><tr><td align="left" balign="left">bb3: SwitchInt</td></tr></table>>];
bcb0__Cov_0_3 [shape="none", label=<<table border="0" cellborder="1" cellspacing="0"><tr><td bgcolor="gray" align="center" colspan="1">bcb0</td></tr><tr><td align="left" balign="left"></td></tr><tr><td align="left" balign="left">Counter(bcb0) at 9:1-9:11<br align="left"/> </td></tr><tr><td align="left" balign="left">bb0: Goto</td></tr></table>>];
bcb3__Cov_0_3 -> bcb1__Cov_0_3 [label=<>];

View File

@ -5,7 +5,7 @@
let mut _0: bool;
bb0: {
+ Coverage::Counter(1) for /the/src/instrument_coverage.rs:20:1 - 22:2;
+ Coverage::Counter(0) for /the/src/instrument_coverage.rs:20:1 - 22:2;
_0 = const true;
return;
}

View File

@ -8,12 +8,12 @@
let mut _3: !;
bb0: {
+ Coverage::Counter(1) for /the/src/instrument_coverage.rs:11:1 - 11:11;
+ Coverage::Counter(0) for /the/src/instrument_coverage.rs:11:1 - 11:11;
goto -> bb1;
}
bb1: {
+ Coverage::Expression(4294967295) = 1 + 2 for /the/src/instrument_coverage.rs:12:5 - 13:17;
+ Coverage::Expression(0) = Counter(0) + Counter(1) for /the/src/instrument_coverage.rs:12:5 - 13:17;
falseUnwind -> [real: bb2, unwind: bb6];
}
@ -27,15 +27,15 @@
}
bb4: {
+ Coverage::Expression(4294967293) = 4294967294 + 0 for /the/src/instrument_coverage.rs:17:1 - 17:2;
+ Coverage::Expression(4294967294) = 4294967295 - 2 for /the/src/instrument_coverage.rs:14:13 - 14:18;
+ Coverage::Expression(2) = Expression(1) + Zero for /the/src/instrument_coverage.rs:17:1 - 17:2;
+ Coverage::Expression(1) = Expression(0) - Counter(1) for /the/src/instrument_coverage.rs:14:13 - 14:18;
_0 = const ();
StorageDead(_2);
return;
}
bb5: {
+ Coverage::Counter(2) for /the/src/instrument_coverage.rs:15:10 - 15:11;
+ Coverage::Counter(1) for /the/src/instrument_coverage.rs:15:10 - 15:11;
_1 = const ();
StorageDead(_2);
goto -> bb1;

View File

@ -0,0 +1,27 @@
struct Bar;
impl std::ops::Mul for &mut Bar {
type Output = Bar;
fn mul(self, _rhs: Self) -> Self::Output {
unimplemented!()
}
}
fn main() {
let ref_mut_bar: &mut Bar = &mut Bar;
let ref_bar: &Bar = &Bar;
let owned_bar: Bar = Bar;
let _ = ref_mut_bar * ref_mut_bar;
// FIXME: we should be able to suggest borrowing both side
let _ = owned_bar * owned_bar;
//~^ ERROR cannot multiply
let _ = ref_bar * ref_bar;
//~^ ERROR cannot multiply
let _ = ref_bar * ref_mut_bar;
//~^ ERROR cannot multiply
let _ = ref_mut_bar * ref_bar;
//~^ ERROR mismatched types
}

View File

@ -0,0 +1,64 @@
error[E0369]: cannot multiply `Bar` by `Bar`
--> $DIR/borrow-suggestion-109352-2.rs:19:23
|
LL | let _ = owned_bar * owned_bar;
| --------- ^ --------- Bar
| |
| Bar
|
note: an implementation of `Mul` might be missing for `Bar`
--> $DIR/borrow-suggestion-109352-2.rs:1:1
|
LL | struct Bar;
| ^^^^^^^^^^ must implement `Mul`
note: the trait `Mul` must be implemented
--> $SRC_DIR/core/src/ops/arith.rs:LL:COL
error[E0369]: cannot multiply `&Bar` by `&Bar`
--> $DIR/borrow-suggestion-109352-2.rs:21:21
|
LL | let _ = ref_bar * ref_bar;
| ------- ^ ------- &Bar
| |
| &Bar
|
= note: an implementation for `&mut Bar * &mut Bar` exists
help: consider making this expression a mutable borrow
--> $DIR/borrow-suggestion-109352-2.rs:21:13
|
LL | let _ = ref_bar * ref_bar;
| ^^^^^^^
help: consider making this expression a mutable borrow
--> $DIR/borrow-suggestion-109352-2.rs:21:23
|
LL | let _ = ref_bar * ref_bar;
| ^^^^^^^
error[E0369]: cannot multiply `&Bar` by `&mut Bar`
--> $DIR/borrow-suggestion-109352-2.rs:23:21
|
LL | let _ = ref_bar * ref_mut_bar;
| ------- ^ ----------- &mut Bar
| |
| &Bar
|
= note: an implementation for `&mut Bar * &mut Bar` exists
help: consider making this expression a mutable borrow
--> $DIR/borrow-suggestion-109352-2.rs:23:13
|
LL | let _ = ref_bar * ref_mut_bar;
| ^^^^^^^
error[E0308]: mismatched types
--> $DIR/borrow-suggestion-109352-2.rs:25:27
|
LL | let _ = ref_mut_bar * ref_bar;
| ^^^^^^^ types differ in mutability
|
= note: expected mutable reference `&mut Bar`
found reference `&Bar`
error: aborting due to 4 previous errors
Some errors have detailed explanations: E0308, E0369.
For more information about an error, try `rustc --explain E0308`.

View File

@ -0,0 +1,27 @@
// run-rustfix
struct Foo;
impl std::ops::Mul for &Foo {
type Output = Foo;
fn mul(self, _rhs: Self) -> Self::Output {
unimplemented!()
}
}
fn main() {
let ref_mut_foo: &mut Foo = &mut Foo;
let ref_foo: &Foo = &Foo;
let owned_foo: Foo = Foo;
let _ = ref_foo * ref_foo;
let _ = ref_foo * ref_mut_foo;
let _ = &*ref_mut_foo * ref_foo;
//~^ ERROR cannot multiply
let _ = &*ref_mut_foo * &*ref_mut_foo;
//~^ ERROR cannot multiply
let _ = &*ref_mut_foo * &owned_foo;
//~^ ERROR cannot multiply
}

View File

@ -0,0 +1,27 @@
// run-rustfix
struct Foo;
impl std::ops::Mul for &Foo {
type Output = Foo;
fn mul(self, _rhs: Self) -> Self::Output {
unimplemented!()
}
}
fn main() {
let ref_mut_foo: &mut Foo = &mut Foo;
let ref_foo: &Foo = &Foo;
let owned_foo: Foo = Foo;
let _ = ref_foo * ref_foo;
let _ = ref_foo * ref_mut_foo;
let _ = ref_mut_foo * ref_foo;
//~^ ERROR cannot multiply
let _ = ref_mut_foo * ref_mut_foo;
//~^ ERROR cannot multiply
let _ = ref_mut_foo * &owned_foo;
//~^ ERROR cannot multiply
}

View File

@ -0,0 +1,45 @@
error[E0369]: cannot multiply `&mut Foo` by `&Foo`
--> $DIR/borrow-suggestion-109352.rs:21:25
|
LL | let _ = ref_mut_foo * ref_foo;
| ----------- ^ ------- &Foo
| |
| &mut Foo
|
= note: an implementation for `&Foo * &Foo` exists
help: consider reborrowing this side
|
LL | let _ = &*ref_mut_foo * ref_foo;
| ++
error[E0369]: cannot multiply `&mut Foo` by `&mut Foo`
--> $DIR/borrow-suggestion-109352.rs:23:25
|
LL | let _ = ref_mut_foo * ref_mut_foo;
| ----------- ^ ----------- &mut Foo
| |
| &mut Foo
|
= note: an implementation for `&Foo * &Foo` exists
help: consider reborrowing both sides
|
LL | let _ = &*ref_mut_foo * &*ref_mut_foo;
| ++ ++
error[E0369]: cannot multiply `&mut Foo` by `&Foo`
--> $DIR/borrow-suggestion-109352.rs:25:25
|
LL | let _ = ref_mut_foo * &owned_foo;
| ----------- ^ ---------- &Foo
| |
| &mut Foo
|
= note: an implementation for `&Foo * &Foo` exists
help: consider reborrowing this side
|
LL | let _ = &*ref_mut_foo * &owned_foo;
| ++
error: aborting due to 3 previous errors
For more information about this error, try `rustc --explain E0369`.