Auto merge of #124271 - GuillaumeGomez:rollup-7st9wd7, r=GuillaumeGomez
Rollup of 7 pull requests Successful merges: - #115913 (checked_ilog: improve performance) - #124178 ([cleanup] [llvm backend] Prevent creating the same `Instance::mono` multiple times) - #124183 (Stop taking `ParamTy`/`ParamConst`/`EarlyParamRegion`/`AliasTy` by ref) - #124217 (coverage: Prepare for improved branch coverage) - #124230 (Stabilize generic `NonZero`.) - #124252 (Improve ICE message for forbidden dep-graph reads.) - #124268 (Update books) r? `@ghost` `@rustbot` modify labels: rollup
This commit is contained in:
commit
9cf10bcf5b
@ -7,7 +7,6 @@
|
||||
#![allow(internal_features)]
|
||||
#![feature(rustdoc_internals)]
|
||||
#![doc(rust_logo)]
|
||||
#![feature(generic_nonzero)]
|
||||
#![feature(let_chains)]
|
||||
|
||||
#[macro_use]
|
||||
|
@ -1320,7 +1320,7 @@ impl<'cx, 'tcx> MirBorrowckCtxt<'cx, 'tcx> {
|
||||
.into_iter()
|
||||
.map(|err| match err.obligation.predicate.kind().skip_binder() {
|
||||
PredicateKind::Clause(ty::ClauseKind::Trait(predicate)) => {
|
||||
match predicate.self_ty().kind() {
|
||||
match *predicate.self_ty().kind() {
|
||||
ty::Param(param_ty) => Ok((
|
||||
generics.type_param(param_ty, tcx),
|
||||
predicate.trait_ref.print_only_trait_path().to_string(),
|
||||
|
@ -1070,7 +1070,7 @@ impl<'cx, 'tcx> MirBorrowckCtxt<'cx, 'tcx> {
|
||||
// LL | blk();
|
||||
// | ----- this value implements `FnOnce`, which causes it to be moved when called
|
||||
// ```
|
||||
if let ty::Param(param_ty) = self_ty.kind()
|
||||
if let ty::Param(param_ty) = *self_ty.kind()
|
||||
&& let generics = self.infcx.tcx.generics_of(self.mir_def_id())
|
||||
&& let param = generics.type_param(param_ty, self.infcx.tcx)
|
||||
&& let Some(hir_generics) = self
|
||||
|
@ -260,7 +260,8 @@ impl<'ll> CodegenCx<'ll, '_> {
|
||||
|
||||
#[instrument(level = "debug", skip(self, llty))]
|
||||
pub(crate) fn get_static_inner(&self, def_id: DefId, llty: &'ll Type) -> &'ll Value {
|
||||
if let Some(&g) = self.instances.borrow().get(&Instance::mono(self.tcx, def_id)) {
|
||||
let instance = Instance::mono(self.tcx, def_id);
|
||||
if let Some(&g) = self.instances.borrow().get(&instance) {
|
||||
trace!("used cached value");
|
||||
return g;
|
||||
}
|
||||
@ -273,7 +274,7 @@ impl<'ll> CodegenCx<'ll, '_> {
|
||||
statics defined in the same CGU, but did not for `{def_id:?}`"
|
||||
);
|
||||
|
||||
let sym = self.tcx.symbol_name(Instance::mono(self.tcx, def_id)).name;
|
||||
let sym = self.tcx.symbol_name(instance).name;
|
||||
let fn_attrs = self.tcx.codegen_fn_attrs(def_id);
|
||||
|
||||
debug!(?sym, ?fn_attrs);
|
||||
@ -363,7 +364,7 @@ impl<'ll> CodegenCx<'ll, '_> {
|
||||
}
|
||||
}
|
||||
|
||||
self.instances.borrow_mut().insert(Instance::mono(self.tcx, def_id), g);
|
||||
self.instances.borrow_mut().insert(instance, g);
|
||||
g
|
||||
}
|
||||
|
||||
|
@ -11,7 +11,6 @@ Rust MIR: a lowered representation of Rust.
|
||||
#![feature(assert_matches)]
|
||||
#![feature(box_patterns)]
|
||||
#![feature(decl_macro)]
|
||||
#![feature(generic_nonzero)]
|
||||
#![feature(let_chains)]
|
||||
#![feature(slice_ptr_get)]
|
||||
#![feature(strict_provenance)]
|
||||
|
@ -20,7 +20,6 @@
|
||||
#![feature(cfg_match)]
|
||||
#![feature(core_intrinsics)]
|
||||
#![feature(extend_one)]
|
||||
#![feature(generic_nonzero)]
|
||||
#![feature(hash_raw_entry)]
|
||||
#![feature(hasher_prefixfree_extras)]
|
||||
#![feature(lazy_cell)]
|
||||
|
@ -15,7 +15,6 @@
|
||||
#![feature(box_patterns)]
|
||||
#![feature(error_reporter)]
|
||||
#![feature(extract_if)]
|
||||
#![feature(generic_nonzero)]
|
||||
#![feature(let_chains)]
|
||||
#![feature(negative_impls)]
|
||||
#![feature(never_type)]
|
||||
|
@ -12,7 +12,6 @@
|
||||
//! symbol to the `accepted` or `removed` modules respectively.
|
||||
|
||||
#![allow(internal_features)]
|
||||
#![feature(generic_nonzero)]
|
||||
#![feature(rustdoc_internals)]
|
||||
#![doc(rust_logo)]
|
||||
#![feature(lazy_cell)]
|
||||
|
@ -63,7 +63,6 @@ This API is completely unstable and subject to change.
|
||||
#![feature(rustdoc_internals)]
|
||||
#![allow(internal_features)]
|
||||
#![feature(control_flow_enum)]
|
||||
#![feature(generic_nonzero)]
|
||||
#![feature(if_let_guard)]
|
||||
#![feature(is_sorted)]
|
||||
#![feature(iter_intersperse)]
|
||||
|
@ -2697,7 +2697,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
|
||||
|
||||
fn point_at_param_definition(&self, err: &mut Diag<'_>, param: ty::ParamTy) {
|
||||
let generics = self.tcx.generics_of(self.body_id);
|
||||
let generic_param = generics.type_param(¶m, self.tcx);
|
||||
let generic_param = generics.type_param(param, self.tcx);
|
||||
if let ty::GenericParamDefKind::Type { synthetic: true, .. } = generic_param.kind {
|
||||
return;
|
||||
}
|
||||
|
@ -2144,7 +2144,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
|
||||
let callee_ty = callee_ty.peel_refs();
|
||||
match *callee_ty.kind() {
|
||||
ty::Param(param) => {
|
||||
let param = self.tcx.generics_of(self.body_id).type_param(¶m, self.tcx);
|
||||
let param = self.tcx.generics_of(self.body_id).type_param(param, self.tcx);
|
||||
if param.kind.is_synthetic() {
|
||||
// if it's `impl Fn() -> ..` then just fall down to the def-id based logic
|
||||
def_id = param.def_id;
|
||||
|
@ -125,11 +125,11 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
|
||||
let Some(arg_ty) = args[0].as_type() else {
|
||||
return false;
|
||||
};
|
||||
let ty::Param(param) = arg_ty.kind() else {
|
||||
let ty::Param(param) = *arg_ty.kind() else {
|
||||
return false;
|
||||
};
|
||||
// Is `generic_param` the same as the arg for this trait predicate?
|
||||
generic_param.index == generics.type_param(¶m, tcx).index
|
||||
generic_param.index == generics.type_param(param, tcx).index
|
||||
} else {
|
||||
false
|
||||
}
|
||||
@ -156,10 +156,10 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
|
||||
return false;
|
||||
}
|
||||
|
||||
match ty.peel_refs().kind() {
|
||||
match *ty.peel_refs().kind() {
|
||||
ty::Param(param) => {
|
||||
let generics = self.tcx.generics_of(self.body_id);
|
||||
let generic_param = generics.type_param(¶m, self.tcx);
|
||||
let generic_param = generics.type_param(param, self.tcx);
|
||||
for unsatisfied in unsatisfied_predicates.iter() {
|
||||
// The parameter implements `IntoIterator`
|
||||
// but it has called a method that requires it to implement `Iterator`
|
||||
@ -3232,9 +3232,9 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
|
||||
.sort_by_key(|&info| (!info.def_id.is_local(), self.tcx.def_path_str(info.def_id)));
|
||||
candidates.dedup();
|
||||
|
||||
let param_type = match rcvr_ty.kind() {
|
||||
let param_type = match *rcvr_ty.kind() {
|
||||
ty::Param(param) => Some(param),
|
||||
ty::Ref(_, ty, _) => match ty.kind() {
|
||||
ty::Ref(_, ty, _) => match *ty.kind() {
|
||||
ty::Param(param) => Some(param),
|
||||
_ => None,
|
||||
},
|
||||
@ -3429,7 +3429,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
|
||||
} else {
|
||||
param_type.map_or_else(
|
||||
|| "implement".to_string(), // FIXME: it might only need to be imported into scope, not implemented.
|
||||
ToString::to_string,
|
||||
|p| p.to_string(),
|
||||
)
|
||||
},
|
||||
},
|
||||
|
@ -2371,7 +2371,7 @@ impl<'tcx> TypeErrCtxt<'_, 'tcx> {
|
||||
|
||||
// type_param_sugg_span is (span, has_bounds)
|
||||
let (type_scope, type_param_sugg_span) = match bound_kind {
|
||||
GenericKind::Param(ref param) => {
|
||||
GenericKind::Param(param) => {
|
||||
let generics = self.tcx.generics_of(generic_param_scope);
|
||||
let def_id = generics.type_param(param, self.tcx).def_id.expect_local();
|
||||
let scope = self.tcx.local_def_id_to_hir_id(def_id).owner.def_id;
|
||||
|
@ -28,7 +28,7 @@ impl<'tcx> TypeErrCtxt<'_, 'tcx> {
|
||||
|
||||
match err {
|
||||
ArgumentSorts(values, _) | Sorts(values) => {
|
||||
match (values.expected.kind(), values.found.kind()) {
|
||||
match (*values.expected.kind(), *values.found.kind()) {
|
||||
(ty::Closure(..), ty::Closure(..)) => {
|
||||
diag.note("no two closures, even if identical, have the same type");
|
||||
diag.help("consider boxing your closure and/or using it as a trait object");
|
||||
@ -452,7 +452,7 @@ impl<T> Trait<T> for X {
|
||||
}
|
||||
(ty::FnPtr(sig), ty::FnDef(def_id, _))
|
||||
| (ty::FnDef(def_id, _), ty::FnPtr(sig)) => {
|
||||
if tcx.fn_sig(*def_id).skip_binder().unsafety() < sig.unsafety() {
|
||||
if tcx.fn_sig(def_id).skip_binder().unsafety() < sig.unsafety() {
|
||||
diag.note(
|
||||
"unsafe functions cannot be coerced into safe function pointers",
|
||||
);
|
||||
@ -527,7 +527,7 @@ impl<T> Trait<T> for X {
|
||||
diag: &mut Diag<'_>,
|
||||
msg: impl Fn() -> String,
|
||||
body_owner_def_id: DefId,
|
||||
proj_ty: &ty::AliasTy<'tcx>,
|
||||
proj_ty: ty::AliasTy<'tcx>,
|
||||
ty: Ty<'tcx>,
|
||||
) -> bool {
|
||||
let tcx = self.tcx;
|
||||
@ -541,7 +541,7 @@ impl<T> Trait<T> for X {
|
||||
};
|
||||
// Get the `DefId` for the type parameter corresponding to `A` in `<A as T>::Foo`.
|
||||
// This will also work for `impl Trait`.
|
||||
let ty::Param(param_ty) = proj_ty.self_ty().kind() else {
|
||||
let ty::Param(param_ty) = *proj_ty.self_ty().kind() else {
|
||||
return false;
|
||||
};
|
||||
let generics = tcx.generics_of(body_owner_def_id);
|
||||
@ -598,7 +598,7 @@ impl<T> Trait<T> for X {
|
||||
fn expected_projection(
|
||||
&self,
|
||||
diag: &mut Diag<'_>,
|
||||
proj_ty: &ty::AliasTy<'tcx>,
|
||||
proj_ty: ty::AliasTy<'tcx>,
|
||||
values: ExpectedFound<Ty<'tcx>>,
|
||||
body_owner_def_id: DefId,
|
||||
cause_code: &ObligationCauseCode<'_>,
|
||||
@ -709,7 +709,7 @@ fn foo(&self) -> Self::T { String::new() }
|
||||
&self,
|
||||
diag: &mut Diag<'_>,
|
||||
msg: impl Fn() -> String,
|
||||
proj_ty: &ty::AliasTy<'tcx>,
|
||||
proj_ty: ty::AliasTy<'tcx>,
|
||||
ty: Ty<'tcx>,
|
||||
) -> bool {
|
||||
let tcx = self.tcx;
|
||||
|
@ -1,5 +1,4 @@
|
||||
#![feature(decl_macro)]
|
||||
#![feature(generic_nonzero)]
|
||||
#![feature(lazy_cell)]
|
||||
#![feature(let_chains)]
|
||||
#![feature(thread_spawn_unchecked)]
|
||||
|
@ -32,7 +32,6 @@
|
||||
#![feature(box_patterns)]
|
||||
#![feature(control_flow_enum)]
|
||||
#![feature(extract_if)]
|
||||
#![feature(generic_nonzero)]
|
||||
#![feature(if_let_guard)]
|
||||
#![feature(iter_order_by)]
|
||||
#![feature(let_chains)]
|
||||
|
@ -6,7 +6,6 @@
|
||||
#![feature(error_iter)]
|
||||
#![feature(extract_if)]
|
||||
#![feature(coroutines)]
|
||||
#![feature(generic_nonzero)]
|
||||
#![feature(iter_from_coroutine)]
|
||||
#![feature(let_chains)]
|
||||
#![feature(if_let_guard)]
|
||||
|
@ -35,7 +35,6 @@
|
||||
#![feature(const_type_name)]
|
||||
#![feature(discriminant_kind)]
|
||||
#![feature(coroutines)]
|
||||
#![feature(generic_nonzero)]
|
||||
#![feature(if_let_guard)]
|
||||
#![feature(inline_const)]
|
||||
#![feature(iter_from_coroutine)]
|
||||
|
@ -314,7 +314,9 @@ impl Default for ConditionInfo {
|
||||
#[derive(TyEncodable, TyDecodable, Hash, HashStable, TypeFoldable, TypeVisitable)]
|
||||
pub struct MCDCBranchSpan {
|
||||
pub span: Span,
|
||||
pub condition_info: ConditionInfo,
|
||||
/// If `None`, this actually represents a normal branch span inserted for
|
||||
/// code that was too complex for MC/DC.
|
||||
pub condition_info: Option<ConditionInfo>,
|
||||
pub true_marker: BlockMarkerId,
|
||||
pub false_marker: BlockMarkerId,
|
||||
}
|
||||
|
@ -491,7 +491,7 @@ fn write_coverage_branch_info(
|
||||
writeln!(
|
||||
w,
|
||||
"{INDENT}coverage mcdc branch {{ condition_id: {:?}, true: {true_marker:?}, false: {false_marker:?} }} => {span:?}",
|
||||
condition_info.condition_id
|
||||
condition_info.map(|info| info.condition_id)
|
||||
)?;
|
||||
}
|
||||
|
||||
|
@ -263,7 +263,7 @@ impl<'tcx> Generics {
|
||||
/// Returns the `GenericParamDef` associated with this `EarlyParamRegion`.
|
||||
pub fn region_param(
|
||||
&'tcx self,
|
||||
param: &ty::EarlyParamRegion,
|
||||
param: ty::EarlyParamRegion,
|
||||
tcx: TyCtxt<'tcx>,
|
||||
) -> &'tcx GenericParamDef {
|
||||
let param = self.param_at(param.index as usize, tcx);
|
||||
@ -274,7 +274,7 @@ impl<'tcx> Generics {
|
||||
}
|
||||
|
||||
/// Returns the `GenericParamDef` associated with this `ParamTy`.
|
||||
pub fn type_param(&'tcx self, param: &ParamTy, tcx: TyCtxt<'tcx>) -> &'tcx GenericParamDef {
|
||||
pub fn type_param(&'tcx self, param: ParamTy, tcx: TyCtxt<'tcx>) -> &'tcx GenericParamDef {
|
||||
let param = self.param_at(param.index as usize, tcx);
|
||||
match param.kind {
|
||||
GenericParamDefKind::Type { .. } => param,
|
||||
@ -286,7 +286,7 @@ impl<'tcx> Generics {
|
||||
/// `Generics`.
|
||||
pub fn opt_type_param(
|
||||
&'tcx self,
|
||||
param: &ParamTy,
|
||||
param: ParamTy,
|
||||
tcx: TyCtxt<'tcx>,
|
||||
) -> Option<&'tcx GenericParamDef> {
|
||||
let param = self.opt_param_at(param.index as usize, tcx)?;
|
||||
@ -297,7 +297,7 @@ impl<'tcx> Generics {
|
||||
}
|
||||
|
||||
/// Returns the `GenericParamDef` associated with this `ParamConst`.
|
||||
pub fn const_param(&'tcx self, param: &ParamConst, tcx: TyCtxt<'tcx>) -> &GenericParamDef {
|
||||
pub fn const_param(&'tcx self, param: ParamConst, tcx: TyCtxt<'tcx>) -> &GenericParamDef {
|
||||
let param = self.param_at(param.index as usize, tcx);
|
||||
match param.kind {
|
||||
GenericParamDefKind::Const { .. } => param,
|
||||
|
@ -1276,7 +1276,7 @@ pub trait PrettyPrinter<'tcx>: Printer<'tcx> + fmt::Write {
|
||||
|
||||
fn pretty_print_inherent_projection(
|
||||
&mut self,
|
||||
alias_ty: &ty::AliasTy<'tcx>,
|
||||
alias_ty: ty::AliasTy<'tcx>,
|
||||
) -> Result<(), PrintError> {
|
||||
let def_key = self.tcx().def_key(alias_ty.def_id);
|
||||
self.path_generic_args(
|
||||
@ -3204,7 +3204,7 @@ define_print_and_forward_display! {
|
||||
|
||||
ty::AliasTy<'tcx> {
|
||||
if let DefKind::Impl { of_trait: false } = cx.tcx().def_kind(cx.tcx().parent(self.def_id)) {
|
||||
p!(pretty_print_inherent_projection(self))
|
||||
p!(pretty_print_inherent_projection(*self))
|
||||
} else {
|
||||
// If we're printing verbosely, or don't want to invoke queries
|
||||
// (`is_impl_trait_in_trait`), then fall back to printing the def path.
|
||||
|
@ -1379,7 +1379,7 @@ impl<'tcx> ParamTy {
|
||||
Ty::new_param(tcx, self.index, self.name)
|
||||
}
|
||||
|
||||
pub fn span_from_generics(&self, tcx: TyCtxt<'tcx>, item_with_generics: DefId) -> Span {
|
||||
pub fn span_from_generics(self, tcx: TyCtxt<'tcx>, item_with_generics: DefId) -> Span {
|
||||
let generics = tcx.generics_of(item_with_generics);
|
||||
let type_param = generics.type_param(self, tcx);
|
||||
tcx.def_span(type_param.def_id)
|
||||
|
@ -432,19 +432,19 @@ impl<'tcx> TyCtxt<'tcx> {
|
||||
.filter(|&(_, k)| {
|
||||
match k.unpack() {
|
||||
GenericArgKind::Lifetime(region) => match region.kind() {
|
||||
ty::ReEarlyParam(ref ebr) => {
|
||||
ty::ReEarlyParam(ebr) => {
|
||||
!impl_generics.region_param(ebr, self).pure_wrt_drop
|
||||
}
|
||||
// Error: not a region param
|
||||
_ => false,
|
||||
},
|
||||
GenericArgKind::Type(ty) => match ty.kind() {
|
||||
ty::Param(ref pt) => !impl_generics.type_param(pt, self).pure_wrt_drop,
|
||||
GenericArgKind::Type(ty) => match *ty.kind() {
|
||||
ty::Param(pt) => !impl_generics.type_param(pt, self).pure_wrt_drop,
|
||||
// Error: not a type param
|
||||
_ => false,
|
||||
},
|
||||
GenericArgKind::Const(ct) => match ct.kind() {
|
||||
ty::ConstKind::Param(ref pc) => {
|
||||
ty::ConstKind::Param(pc) => {
|
||||
!impl_generics.const_param(pc, self).pure_wrt_drop
|
||||
}
|
||||
// Error: not a const param
|
||||
|
@ -7,13 +7,13 @@ use rustc_middle::mir::coverage::{
|
||||
BlockMarkerId, BranchSpan, ConditionId, ConditionInfo, CoverageKind, MCDCBranchSpan,
|
||||
MCDCDecisionSpan,
|
||||
};
|
||||
use rustc_middle::mir::{self, BasicBlock, UnOp};
|
||||
use rustc_middle::mir::{self, BasicBlock, SourceInfo, UnOp};
|
||||
use rustc_middle::thir::{ExprId, ExprKind, LogicalOp, Thir};
|
||||
use rustc_middle::ty::TyCtxt;
|
||||
use rustc_span::def_id::LocalDefId;
|
||||
use rustc_span::Span;
|
||||
|
||||
use crate::build::Builder;
|
||||
use crate::build::{Builder, CFG};
|
||||
use crate::errors::MCDCExceedsConditionNumLimit;
|
||||
|
||||
pub(crate) struct BranchInfoBuilder {
|
||||
@ -22,6 +22,7 @@ pub(crate) struct BranchInfoBuilder {
|
||||
|
||||
num_block_markers: usize,
|
||||
branch_spans: Vec<BranchSpan>,
|
||||
|
||||
mcdc_branch_spans: Vec<MCDCBranchSpan>,
|
||||
mcdc_decision_spans: Vec<MCDCDecisionSpan>,
|
||||
mcdc_state: Option<MCDCState>,
|
||||
@ -95,13 +96,7 @@ impl BranchInfoBuilder {
|
||||
}
|
||||
}
|
||||
|
||||
fn record_conditions_operation(&mut self, logical_op: LogicalOp, span: Span) {
|
||||
if let Some(mcdc_state) = self.mcdc_state.as_mut() {
|
||||
mcdc_state.record_conditions(logical_op, span);
|
||||
}
|
||||
}
|
||||
|
||||
fn fetch_condition_info(
|
||||
fn fetch_mcdc_condition_info(
|
||||
&mut self,
|
||||
tcx: TyCtxt<'_>,
|
||||
true_marker: BlockMarkerId,
|
||||
@ -121,14 +116,9 @@ impl BranchInfoBuilder {
|
||||
_ => {
|
||||
// Do not generate mcdc mappings and statements for decisions with too many conditions.
|
||||
let rebase_idx = self.mcdc_branch_spans.len() - decision.conditions_num + 1;
|
||||
let to_normal_branches = self.mcdc_branch_spans.split_off(rebase_idx);
|
||||
self.branch_spans.extend(to_normal_branches.into_iter().map(
|
||||
|MCDCBranchSpan { span, true_marker, false_marker, .. }| BranchSpan {
|
||||
span,
|
||||
true_marker,
|
||||
false_marker,
|
||||
},
|
||||
));
|
||||
for branch in &mut self.mcdc_branch_spans[rebase_idx..] {
|
||||
branch.condition_info = None;
|
||||
}
|
||||
|
||||
// ConditionInfo of this branch shall also be reset.
|
||||
condition_info = None;
|
||||
@ -144,12 +134,42 @@ impl BranchInfoBuilder {
|
||||
condition_info
|
||||
}
|
||||
|
||||
fn add_two_way_branch<'tcx>(
|
||||
&mut self,
|
||||
cfg: &mut CFG<'tcx>,
|
||||
source_info: SourceInfo,
|
||||
true_block: BasicBlock,
|
||||
false_block: BasicBlock,
|
||||
) {
|
||||
let true_marker = self.inject_block_marker(cfg, source_info, true_block);
|
||||
let false_marker = self.inject_block_marker(cfg, source_info, false_block);
|
||||
|
||||
self.branch_spans.push(BranchSpan { span: source_info.span, true_marker, false_marker });
|
||||
}
|
||||
|
||||
fn next_block_marker_id(&mut self) -> BlockMarkerId {
|
||||
let id = BlockMarkerId::from_usize(self.num_block_markers);
|
||||
self.num_block_markers += 1;
|
||||
id
|
||||
}
|
||||
|
||||
fn inject_block_marker(
|
||||
&mut self,
|
||||
cfg: &mut CFG<'_>,
|
||||
source_info: SourceInfo,
|
||||
block: BasicBlock,
|
||||
) -> BlockMarkerId {
|
||||
let id = self.next_block_marker_id();
|
||||
|
||||
let marker_statement = mir::Statement {
|
||||
source_info,
|
||||
kind: mir::StatementKind::Coverage(CoverageKind::BlockMarker { id }),
|
||||
};
|
||||
cfg.push(block, marker_statement);
|
||||
|
||||
id
|
||||
}
|
||||
|
||||
pub(crate) fn into_done(self) -> Option<Box<mir::coverage::BranchInfo>> {
|
||||
let Self {
|
||||
nots: _,
|
||||
@ -157,7 +177,7 @@ impl BranchInfoBuilder {
|
||||
branch_spans,
|
||||
mcdc_branch_spans,
|
||||
mcdc_decision_spans,
|
||||
..
|
||||
mcdc_state: _,
|
||||
} = self;
|
||||
|
||||
if num_block_markers == 0 {
|
||||
@ -325,7 +345,7 @@ impl Builder<'_, '_> {
|
||||
mut else_block: BasicBlock,
|
||||
) {
|
||||
// Bail out if branch coverage is not enabled for this function.
|
||||
let Some(branch_info) = self.coverage_branch_info.as_ref() else { return };
|
||||
let Some(branch_info) = self.coverage_branch_info.as_mut() else { return };
|
||||
|
||||
// If this condition expression is nested within one or more `!` expressions,
|
||||
// replace it with the enclosing `!` collected by `visit_unary_not`.
|
||||
@ -335,47 +355,34 @@ impl Builder<'_, '_> {
|
||||
std::mem::swap(&mut then_block, &mut else_block);
|
||||
}
|
||||
}
|
||||
let source_info = self.source_info(self.thir[expr_id].span);
|
||||
|
||||
// Now that we have `source_info`, we can upgrade to a &mut reference.
|
||||
let branch_info = self.coverage_branch_info.as_mut().expect("upgrading & to &mut");
|
||||
let source_info = SourceInfo { span: self.thir[expr_id].span, scope: self.source_scope };
|
||||
|
||||
let mut inject_branch_marker = |block: BasicBlock| {
|
||||
let id = branch_info.next_block_marker_id();
|
||||
|
||||
let marker_statement = mir::Statement {
|
||||
source_info,
|
||||
kind: mir::StatementKind::Coverage(CoverageKind::BlockMarker { id }),
|
||||
};
|
||||
self.cfg.push(block, marker_statement);
|
||||
|
||||
id
|
||||
};
|
||||
|
||||
let true_marker = inject_branch_marker(then_block);
|
||||
let false_marker = inject_branch_marker(else_block);
|
||||
|
||||
if let Some(condition_info) =
|
||||
branch_info.fetch_condition_info(self.tcx, true_marker, false_marker)
|
||||
{
|
||||
// Separate path for handling branches when MC/DC is enabled.
|
||||
if branch_info.mcdc_state.is_some() {
|
||||
let mut inject_block_marker =
|
||||
|block| branch_info.inject_block_marker(&mut self.cfg, source_info, block);
|
||||
let true_marker = inject_block_marker(then_block);
|
||||
let false_marker = inject_block_marker(else_block);
|
||||
let condition_info =
|
||||
branch_info.fetch_mcdc_condition_info(self.tcx, true_marker, false_marker);
|
||||
branch_info.mcdc_branch_spans.push(MCDCBranchSpan {
|
||||
span: source_info.span,
|
||||
condition_info,
|
||||
true_marker,
|
||||
false_marker,
|
||||
});
|
||||
} else {
|
||||
branch_info.branch_spans.push(BranchSpan {
|
||||
span: source_info.span,
|
||||
true_marker,
|
||||
false_marker,
|
||||
});
|
||||
return;
|
||||
}
|
||||
|
||||
branch_info.add_two_way_branch(&mut self.cfg, source_info, then_block, else_block);
|
||||
}
|
||||
|
||||
pub(crate) fn visit_coverage_branch_operation(&mut self, logical_op: LogicalOp, span: Span) {
|
||||
if let Some(branch_info) = self.coverage_branch_info.as_mut() {
|
||||
branch_info.record_conditions_operation(logical_op, span);
|
||||
if let Some(branch_info) = self.coverage_branch_info.as_mut()
|
||||
&& let Some(mcdc_state) = branch_info.mcdc_state.as_mut()
|
||||
{
|
||||
mcdc_state.record_conditions(logical_op, span);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -9,7 +9,7 @@ mod tests;
|
||||
|
||||
use self::counters::{CounterIncrementSite, CoverageCounters};
|
||||
use self::graph::{BasicCoverageBlock, CoverageGraph};
|
||||
use self::spans::{BcbMapping, BcbMappingKind, CoverageSpans};
|
||||
use self::spans::{BcbBranchPair, BcbMapping, BcbMappingKind, CoverageSpans};
|
||||
|
||||
use crate::MirPass;
|
||||
|
||||
@ -141,21 +141,25 @@ fn create_mappings<'tcx>(
|
||||
|
||||
let mut mappings = Vec::new();
|
||||
|
||||
mappings.extend(coverage_spans.all_bcb_mappings().filter_map(
|
||||
mappings.extend(coverage_spans.mappings.iter().filter_map(
|
||||
|BcbMapping { kind: bcb_mapping_kind, span }| {
|
||||
let kind = match *bcb_mapping_kind {
|
||||
BcbMappingKind::Code(bcb) => MappingKind::Code(term_for_bcb(bcb)),
|
||||
BcbMappingKind::Branch { true_bcb, false_bcb } => MappingKind::Branch {
|
||||
true_term: term_for_bcb(true_bcb),
|
||||
false_term: term_for_bcb(false_bcb),
|
||||
},
|
||||
BcbMappingKind::MCDCBranch { true_bcb, false_bcb, condition_info } => {
|
||||
MappingKind::MCDCBranch {
|
||||
BcbMappingKind::MCDCBranch { true_bcb, false_bcb, condition_info: None } => {
|
||||
MappingKind::Branch {
|
||||
true_term: term_for_bcb(true_bcb),
|
||||
false_term: term_for_bcb(false_bcb),
|
||||
mcdc_params: condition_info,
|
||||
}
|
||||
}
|
||||
BcbMappingKind::MCDCBranch {
|
||||
true_bcb,
|
||||
false_bcb,
|
||||
condition_info: Some(mcdc_params),
|
||||
} => MappingKind::MCDCBranch {
|
||||
true_term: term_for_bcb(true_bcb),
|
||||
false_term: term_for_bcb(false_bcb),
|
||||
mcdc_params,
|
||||
},
|
||||
BcbMappingKind::MCDCDecision { bitmap_idx, conditions_num, .. } => {
|
||||
MappingKind::MCDCDecision(DecisionInfo { bitmap_idx, conditions_num })
|
||||
}
|
||||
@ -165,6 +169,16 @@ fn create_mappings<'tcx>(
|
||||
},
|
||||
));
|
||||
|
||||
mappings.extend(coverage_spans.branch_pairs.iter().filter_map(
|
||||
|&BcbBranchPair { span, true_bcb, false_bcb }| {
|
||||
let true_term = term_for_bcb(true_bcb);
|
||||
let false_term = term_for_bcb(false_bcb);
|
||||
let kind = MappingKind::Branch { true_term, false_term };
|
||||
let code_region = make_code_region(source_map, file_name, span, body_span)?;
|
||||
Some(Mapping { kind, code_region })
|
||||
},
|
||||
));
|
||||
|
||||
mappings
|
||||
}
|
||||
|
||||
@ -233,7 +247,7 @@ fn inject_mcdc_statements<'tcx>(
|
||||
|
||||
// Inject test vector update first because `inject_statement` always insert new statement at head.
|
||||
for (end_bcbs, bitmap_idx) in
|
||||
coverage_spans.all_bcb_mappings().filter_map(|mapping| match &mapping.kind {
|
||||
coverage_spans.mappings.iter().filter_map(|mapping| match &mapping.kind {
|
||||
BcbMappingKind::MCDCDecision { end_bcbs, bitmap_idx, .. } => {
|
||||
Some((end_bcbs, *bitmap_idx))
|
||||
}
|
||||
@ -247,9 +261,9 @@ fn inject_mcdc_statements<'tcx>(
|
||||
}
|
||||
|
||||
for (true_bcb, false_bcb, condition_id) in
|
||||
coverage_spans.all_bcb_mappings().filter_map(|mapping| match mapping.kind {
|
||||
coverage_spans.mappings.iter().filter_map(|mapping| match mapping.kind {
|
||||
BcbMappingKind::MCDCBranch { true_bcb, false_bcb, condition_info } => {
|
||||
Some((true_bcb, false_bcb, condition_info.condition_id))
|
||||
Some((true_bcb, false_bcb, condition_info?.condition_id))
|
||||
}
|
||||
_ => None,
|
||||
})
|
||||
|
@ -15,13 +15,17 @@ mod from_mir;
|
||||
pub(super) enum BcbMappingKind {
|
||||
/// Associates an ordinary executable code span with its corresponding BCB.
|
||||
Code(BasicCoverageBlock),
|
||||
/// Associates a branch span with BCBs for its true and false arms.
|
||||
Branch { true_bcb: BasicCoverageBlock, false_bcb: BasicCoverageBlock },
|
||||
|
||||
// Ordinary branch mappings are stored separately, so they don't have a
|
||||
// variant in this enum.
|
||||
//
|
||||
/// Associates a mcdc branch span with condition info besides fields for normal branch.
|
||||
MCDCBranch {
|
||||
true_bcb: BasicCoverageBlock,
|
||||
false_bcb: BasicCoverageBlock,
|
||||
condition_info: ConditionInfo,
|
||||
/// If `None`, this actually represents a normal branch mapping inserted
|
||||
/// for code that was too complex for MC/DC.
|
||||
condition_info: Option<ConditionInfo>,
|
||||
},
|
||||
/// Associates a mcdc decision with its join BCB.
|
||||
MCDCDecision { end_bcbs: BTreeSet<BasicCoverageBlock>, bitmap_idx: u32, conditions_num: u16 },
|
||||
@ -33,9 +37,20 @@ pub(super) struct BcbMapping {
|
||||
pub(super) span: Span,
|
||||
}
|
||||
|
||||
/// This is separate from [`BcbMappingKind`] to help prepare for larger changes
|
||||
/// that will be needed for improved branch coverage in the future.
|
||||
/// (See <https://github.com/rust-lang/rust/pull/124217>.)
|
||||
#[derive(Debug)]
|
||||
pub(super) struct BcbBranchPair {
|
||||
pub(super) span: Span,
|
||||
pub(super) true_bcb: BasicCoverageBlock,
|
||||
pub(super) false_bcb: BasicCoverageBlock,
|
||||
}
|
||||
|
||||
pub(super) struct CoverageSpans {
|
||||
bcb_has_mappings: BitSet<BasicCoverageBlock>,
|
||||
mappings: Vec<BcbMapping>,
|
||||
pub(super) mappings: Vec<BcbMapping>,
|
||||
pub(super) branch_pairs: Vec<BcbBranchPair>,
|
||||
test_vector_bitmap_bytes: u32,
|
||||
}
|
||||
|
||||
@ -44,10 +59,6 @@ impl CoverageSpans {
|
||||
self.bcb_has_mappings.contains(bcb)
|
||||
}
|
||||
|
||||
pub(super) fn all_bcb_mappings(&self) -> impl Iterator<Item = &BcbMapping> {
|
||||
self.mappings.iter()
|
||||
}
|
||||
|
||||
pub(super) fn test_vector_bitmap_bytes(&self) -> u32 {
|
||||
self.test_vector_bitmap_bytes
|
||||
}
|
||||
@ -63,6 +74,7 @@ pub(super) fn generate_coverage_spans(
|
||||
basic_coverage_blocks: &CoverageGraph,
|
||||
) -> Option<CoverageSpans> {
|
||||
let mut mappings = vec![];
|
||||
let mut branch_pairs = vec![];
|
||||
|
||||
if hir_info.is_async_fn {
|
||||
// An async function desugars into a function that returns a future,
|
||||
@ -84,14 +96,20 @@ pub(super) fn generate_coverage_spans(
|
||||
BcbMapping { kind: BcbMappingKind::Code(bcb), span }
|
||||
}));
|
||||
|
||||
mappings.extend(from_mir::extract_branch_mappings(
|
||||
branch_pairs.extend(from_mir::extract_branch_pairs(
|
||||
mir_body,
|
||||
hir_info,
|
||||
basic_coverage_blocks,
|
||||
));
|
||||
|
||||
mappings.extend(from_mir::extract_mcdc_mappings(
|
||||
mir_body,
|
||||
hir_info.body_span,
|
||||
basic_coverage_blocks,
|
||||
));
|
||||
}
|
||||
|
||||
if mappings.is_empty() {
|
||||
if mappings.is_empty() && branch_pairs.is_empty() {
|
||||
return None;
|
||||
}
|
||||
|
||||
@ -104,8 +122,7 @@ pub(super) fn generate_coverage_spans(
|
||||
for BcbMapping { kind, span: _ } in &mappings {
|
||||
match *kind {
|
||||
BcbMappingKind::Code(bcb) => insert(bcb),
|
||||
BcbMappingKind::Branch { true_bcb, false_bcb }
|
||||
| BcbMappingKind::MCDCBranch { true_bcb, false_bcb, .. } => {
|
||||
BcbMappingKind::MCDCBranch { true_bcb, false_bcb, .. } => {
|
||||
insert(true_bcb);
|
||||
insert(false_bcb);
|
||||
}
|
||||
@ -118,8 +135,12 @@ pub(super) fn generate_coverage_spans(
|
||||
}
|
||||
}
|
||||
}
|
||||
for &BcbBranchPair { true_bcb, false_bcb, .. } in &branch_pairs {
|
||||
insert(true_bcb);
|
||||
insert(false_bcb);
|
||||
}
|
||||
|
||||
Some(CoverageSpans { bcb_has_mappings, mappings, test_vector_bitmap_bytes })
|
||||
Some(CoverageSpans { bcb_has_mappings, mappings, branch_pairs, test_vector_bitmap_bytes })
|
||||
}
|
||||
|
||||
#[derive(Debug)]
|
||||
|
@ -13,7 +13,7 @@ use rustc_span::{ExpnKind, MacroKind, Span, Symbol};
|
||||
use crate::coverage::graph::{
|
||||
BasicCoverageBlock, BasicCoverageBlockData, CoverageGraph, START_BCB,
|
||||
};
|
||||
use crate::coverage::spans::{BcbMapping, BcbMappingKind};
|
||||
use crate::coverage::spans::{BcbBranchPair, BcbMapping, BcbMappingKind};
|
||||
use crate::coverage::ExtractedHirInfo;
|
||||
|
||||
/// Traverses the MIR body to produce an initial collection of coverage-relevant
|
||||
@ -366,15 +366,10 @@ impl SpanFromMir {
|
||||
}
|
||||
}
|
||||
|
||||
pub(super) fn extract_branch_mappings(
|
||||
fn resolve_block_markers(
|
||||
branch_info: &mir::coverage::BranchInfo,
|
||||
mir_body: &mir::Body<'_>,
|
||||
body_span: Span,
|
||||
basic_coverage_blocks: &CoverageGraph,
|
||||
) -> Vec<BcbMapping> {
|
||||
let Some(branch_info) = mir_body.coverage_branch_info.as_deref() else {
|
||||
return vec![];
|
||||
};
|
||||
|
||||
) -> IndexVec<BlockMarkerId, Option<BasicBlock>> {
|
||||
let mut block_markers = IndexVec::<BlockMarkerId, Option<BasicBlock>>::from_elem_n(
|
||||
None,
|
||||
branch_info.num_block_markers,
|
||||
@ -389,6 +384,58 @@ pub(super) fn extract_branch_mappings(
|
||||
}
|
||||
}
|
||||
|
||||
block_markers
|
||||
}
|
||||
|
||||
// FIXME: There is currently a lot of redundancy between
|
||||
// `extract_branch_pairs` and `extract_mcdc_mappings`. This is needed so
|
||||
// that they can each be modified without interfering with the other, but in
|
||||
// the long term we should try to bring them together again when branch coverage
|
||||
// and MC/DC coverage support are more mature.
|
||||
|
||||
pub(super) fn extract_branch_pairs(
|
||||
mir_body: &mir::Body<'_>,
|
||||
hir_info: &ExtractedHirInfo,
|
||||
basic_coverage_blocks: &CoverageGraph,
|
||||
) -> Vec<BcbBranchPair> {
|
||||
let Some(branch_info) = mir_body.coverage_branch_info.as_deref() else { return vec![] };
|
||||
|
||||
let block_markers = resolve_block_markers(branch_info, mir_body);
|
||||
|
||||
branch_info
|
||||
.branch_spans
|
||||
.iter()
|
||||
.filter_map(|&BranchSpan { span: raw_span, true_marker, false_marker }| {
|
||||
// For now, ignore any branch span that was introduced by
|
||||
// expansion. This makes things like assert macros less noisy.
|
||||
if !raw_span.ctxt().outer_expn_data().is_root() {
|
||||
return None;
|
||||
}
|
||||
let (span, _) =
|
||||
unexpand_into_body_span_with_visible_macro(raw_span, hir_info.body_span)?;
|
||||
|
||||
let bcb_from_marker =
|
||||
|marker: BlockMarkerId| basic_coverage_blocks.bcb_from_bb(block_markers[marker]?);
|
||||
|
||||
let true_bcb = bcb_from_marker(true_marker)?;
|
||||
let false_bcb = bcb_from_marker(false_marker)?;
|
||||
|
||||
Some(BcbBranchPair { span, true_bcb, false_bcb })
|
||||
})
|
||||
.collect::<Vec<_>>()
|
||||
}
|
||||
|
||||
pub(super) fn extract_mcdc_mappings(
|
||||
mir_body: &mir::Body<'_>,
|
||||
body_span: Span,
|
||||
basic_coverage_blocks: &CoverageGraph,
|
||||
) -> Vec<BcbMapping> {
|
||||
let Some(branch_info) = mir_body.coverage_branch_info.as_deref() else {
|
||||
return vec![];
|
||||
};
|
||||
|
||||
let block_markers = resolve_block_markers(branch_info, mir_body);
|
||||
|
||||
let bcb_from_marker =
|
||||
|marker: BlockMarkerId| basic_coverage_blocks.bcb_from_bb(block_markers[marker]?);
|
||||
|
||||
@ -406,12 +453,6 @@ pub(super) fn extract_branch_mappings(
|
||||
Some((span, true_bcb, false_bcb))
|
||||
};
|
||||
|
||||
let branch_filter_map = |&BranchSpan { span: raw_span, true_marker, false_marker }| {
|
||||
check_branch_bcb(raw_span, true_marker, false_marker).map(|(span, true_bcb, false_bcb)| {
|
||||
BcbMapping { kind: BcbMappingKind::Branch { true_bcb, false_bcb }, span }
|
||||
})
|
||||
};
|
||||
|
||||
let mcdc_branch_filter_map =
|
||||
|&MCDCBranchSpan { span: raw_span, true_marker, false_marker, condition_info }| {
|
||||
check_branch_bcb(raw_span, true_marker, false_marker).map(
|
||||
@ -446,10 +487,7 @@ pub(super) fn extract_branch_mappings(
|
||||
})
|
||||
};
|
||||
|
||||
branch_info
|
||||
.branch_spans
|
||||
.iter()
|
||||
.filter_map(branch_filter_map)
|
||||
std::iter::empty()
|
||||
.chain(branch_info.mcdc_branch_spans.iter().filter_map(mcdc_branch_filter_map))
|
||||
.chain(branch_info.mcdc_decision_spans.iter().filter_map(decision_filter_map))
|
||||
.collect::<Vec<_>>()
|
||||
|
@ -8,7 +8,6 @@
|
||||
#![doc(rust_logo)]
|
||||
#![feature(rustdoc_internals)]
|
||||
#![allow(internal_features)]
|
||||
#![feature(generic_nonzero)]
|
||||
#![feature(let_chains)]
|
||||
#![feature(map_try_insert)]
|
||||
#![feature(try_blocks)]
|
||||
|
@ -3,7 +3,6 @@
|
||||
#![doc(html_root_url = "https://doc.rust-lang.org/nightly/nightly-rustc/")]
|
||||
#![doc(rust_logo)]
|
||||
#![feature(rustdoc_internals)]
|
||||
#![feature(generic_nonzero)]
|
||||
#![feature(min_specialization)]
|
||||
#![feature(rustc_attrs)]
|
||||
#![allow(rustc::potential_query_instability, unused_parens)]
|
||||
|
@ -459,7 +459,8 @@ impl<D: Deps> DepGraph<D> {
|
||||
}
|
||||
TaskDepsRef::Ignore => return,
|
||||
TaskDepsRef::Forbid => {
|
||||
panic!("Illegal read of: {dep_node_index:?}")
|
||||
// Reading is forbidden in this context. ICE with a useful error message.
|
||||
panic_on_forbidden_read(data, dep_node_index)
|
||||
}
|
||||
};
|
||||
let task_deps = &mut *task_deps;
|
||||
@ -1366,3 +1367,45 @@ pub(crate) fn print_markframe_trace<D: Deps>(graph: &DepGraph<D>, frame: Option<
|
||||
|
||||
eprintln!("end of try_mark_green dep node stack");
|
||||
}
|
||||
|
||||
#[cold]
|
||||
#[inline(never)]
|
||||
fn panic_on_forbidden_read<D: Deps>(data: &DepGraphData<D>, dep_node_index: DepNodeIndex) -> ! {
|
||||
// We have to do an expensive reverse-lookup of the DepNode that
|
||||
// corresponds to `dep_node_index`, but that's OK since we are about
|
||||
// to ICE anyway.
|
||||
let mut dep_node = None;
|
||||
|
||||
// First try to find the dep node among those that already existed in the
|
||||
// previous session
|
||||
for (prev_index, index) in data.current.prev_index_to_index.lock().iter_enumerated() {
|
||||
if index == &Some(dep_node_index) {
|
||||
dep_node = Some(data.previous.index_to_node(prev_index));
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if dep_node.is_none() {
|
||||
// Try to find it among the new nodes
|
||||
for shard in data.current.new_node_to_index.lock_shards() {
|
||||
if let Some((node, _)) = shard.iter().find(|(_, index)| **index == dep_node_index) {
|
||||
dep_node = Some(*node);
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
let dep_node = dep_node.map_or_else(
|
||||
|| format!("with index {:?}", dep_node_index),
|
||||
|dep_node| format!("`{:?}`", dep_node),
|
||||
);
|
||||
|
||||
panic!(
|
||||
"Error: trying to record dependency on DepNode {dep_node} in a \
|
||||
context that does not allow it (e.g. during query deserialization). \
|
||||
The most common case of recording a dependency on a DepNode `foo` is \
|
||||
when the correspondng query `foo` is invoked. Invoking queries is not \
|
||||
allowed as part of loading something from the incremental on-disk cache. \
|
||||
See <https://github.com/rust-lang/rust/pull/91919>."
|
||||
)
|
||||
}
|
||||
|
@ -1,6 +1,5 @@
|
||||
#![feature(assert_matches)]
|
||||
#![feature(core_intrinsics)]
|
||||
#![feature(generic_nonzero)]
|
||||
#![feature(hash_raw_entry)]
|
||||
#![feature(min_specialization)]
|
||||
#![feature(let_chains)]
|
||||
|
@ -11,7 +11,6 @@
|
||||
#![cfg_attr(bootstrap, feature(associated_type_bounds))]
|
||||
#![feature(const_option)]
|
||||
#![feature(core_intrinsics)]
|
||||
#![feature(generic_nonzero)]
|
||||
#![feature(inline_const)]
|
||||
#![feature(min_specialization)]
|
||||
#![feature(never_type)]
|
||||
|
@ -1,4 +1,3 @@
|
||||
#![feature(generic_nonzero)]
|
||||
#![feature(let_chains)]
|
||||
#![feature(lazy_cell)]
|
||||
#![feature(option_get_or_insert_default)]
|
||||
|
@ -124,7 +124,7 @@ pub fn suggest_restriction<'tcx, G: EmissionGuarantee>(
|
||||
msg: &str,
|
||||
err: &mut Diag<'_, G>,
|
||||
fn_sig: Option<&hir::FnSig<'_>>,
|
||||
projection: Option<&ty::AliasTy<'_>>,
|
||||
projection: Option<ty::AliasTy<'_>>,
|
||||
trait_pred: ty::PolyTraitPredicate<'tcx>,
|
||||
// When we are dealing with a trait, `super_traits` will be `Some`:
|
||||
// Given `trait T: A + B + C {}`
|
||||
@ -142,7 +142,7 @@ pub fn suggest_restriction<'tcx, G: EmissionGuarantee>(
|
||||
let generics = tcx.generics_of(item_id);
|
||||
// Given `fn foo(t: impl Trait)` where `Trait` requires assoc type `A`...
|
||||
if let Some((param, bound_str, fn_sig)) =
|
||||
fn_sig.zip(projection).and_then(|(sig, p)| match p.self_ty().kind() {
|
||||
fn_sig.zip(projection).and_then(|(sig, p)| match *p.self_ty().kind() {
|
||||
// Shenanigans to get the `Trait` from the `impl Trait`.
|
||||
ty::Param(param) => {
|
||||
let param_def = generics.type_param(param, tcx);
|
||||
@ -252,7 +252,7 @@ impl<'tcx> TypeErrCtxt<'_, 'tcx> {
|
||||
let trait_pred = self.resolve_numeric_literals_with_default(trait_pred);
|
||||
|
||||
let self_ty = trait_pred.skip_binder().self_ty();
|
||||
let (param_ty, projection) = match self_ty.kind() {
|
||||
let (param_ty, projection) = match *self_ty.kind() {
|
||||
ty::Param(_) => (true, None),
|
||||
ty::Alias(ty::Projection, projection) => (false, Some(projection)),
|
||||
_ => (false, None),
|
||||
|
@ -482,7 +482,7 @@ fn is_impossible_associated_item(
|
||||
type Result = ControlFlow<()>;
|
||||
fn visit_ty(&mut self, t: Ty<'tcx>) -> Self::Result {
|
||||
// If this is a parameter from the trait item's own generics, then bail
|
||||
if let ty::Param(param) = t.kind()
|
||||
if let ty::Param(param) = *t.kind()
|
||||
&& let param_def_id = self.generics.type_param(param, self.tcx).def_id
|
||||
&& self.tcx.parent(param_def_id) == self.trait_item_def_id
|
||||
{
|
||||
@ -492,7 +492,7 @@ fn is_impossible_associated_item(
|
||||
}
|
||||
fn visit_region(&mut self, r: ty::Region<'tcx>) -> Self::Result {
|
||||
if let ty::ReEarlyParam(param) = r.kind()
|
||||
&& let param_def_id = self.generics.region_param(¶m, self.tcx).def_id
|
||||
&& let param_def_id = self.generics.region_param(param, self.tcx).def_id
|
||||
&& self.tcx.parent(param_def_id) == self.trait_item_def_id
|
||||
{
|
||||
return ControlFlow::Break(());
|
||||
@ -501,7 +501,7 @@ fn is_impossible_associated_item(
|
||||
}
|
||||
fn visit_const(&mut self, ct: ty::Const<'tcx>) -> Self::Result {
|
||||
if let ty::ConstKind::Param(param) = ct.kind()
|
||||
&& let param_def_id = self.generics.const_param(¶m, self.tcx).def_id
|
||||
&& let param_def_id = self.generics.const_param(param, self.tcx).def_id
|
||||
&& self.tcx.parent(param_def_id) == self.trait_item_def_id
|
||||
{
|
||||
return ControlFlow::Break(());
|
||||
|
@ -130,7 +130,7 @@ impl<'tcx> OpaqueTypeCollector<'tcx> {
|
||||
TaitInBodyFinder { collector: self }.visit_expr(body);
|
||||
}
|
||||
|
||||
fn visit_opaque_ty(&mut self, alias_ty: &ty::AliasTy<'tcx>) {
|
||||
fn visit_opaque_ty(&mut self, alias_ty: ty::AliasTy<'tcx>) {
|
||||
if !self.seen.insert(alias_ty.def_id.expect_local()) {
|
||||
return;
|
||||
}
|
||||
@ -205,7 +205,7 @@ impl<'tcx> TypeVisitor<TyCtxt<'tcx>> for OpaqueTypeCollector<'tcx> {
|
||||
#[instrument(skip(self), ret, level = "trace")]
|
||||
fn visit_ty(&mut self, t: Ty<'tcx>) {
|
||||
t.super_visit_with(self);
|
||||
match t.kind() {
|
||||
match *t.kind() {
|
||||
ty::Alias(ty::Opaque, alias_ty) if alias_ty.def_id.is_local() => {
|
||||
self.visit_opaque_ty(alias_ty);
|
||||
}
|
||||
@ -279,7 +279,7 @@ impl<'tcx> TypeVisitor<TyCtxt<'tcx>> for OpaqueTypeCollector<'tcx> {
|
||||
// assumption to the `param_env` of the default method. We also separately
|
||||
// rely on that assumption here.
|
||||
let ty = self.tcx.type_of(alias_ty.def_id).instantiate(self.tcx, alias_ty.args);
|
||||
let ty::Alias(ty::Opaque, alias_ty) = ty.kind() else { bug!("{ty:?}") };
|
||||
let ty::Alias(ty::Opaque, alias_ty) = *ty.kind() else { bug!("{ty:?}") };
|
||||
self.visit_opaque_ty(alias_ty);
|
||||
}
|
||||
}
|
||||
|
@ -126,7 +126,6 @@
|
||||
#![feature(extend_one)]
|
||||
#![feature(fmt_internals)]
|
||||
#![feature(fn_traits)]
|
||||
#![feature(generic_nonzero)]
|
||||
#![feature(hasher_prefixfree_extras)]
|
||||
#![feature(hint_assert_unchecked)]
|
||||
#![feature(inline_const)]
|
||||
|
@ -14,7 +14,6 @@
|
||||
#![feature(core_intrinsics)]
|
||||
#![feature(extract_if)]
|
||||
#![feature(exact_size_is_empty)]
|
||||
#![feature(generic_nonzero)]
|
||||
#![feature(linked_list_cursors)]
|
||||
#![feature(map_try_insert)]
|
||||
#![feature(new_uninit)]
|
||||
|
@ -1,7 +1,7 @@
|
||||
use rand::Rng;
|
||||
use test::{black_box, Bencher};
|
||||
|
||||
macro_rules! int_log_bench {
|
||||
macro_rules! int_log10_bench {
|
||||
($t:ty, $predictable:ident, $random:ident, $random_small:ident) => {
|
||||
#[bench]
|
||||
fn $predictable(bench: &mut Bencher) {
|
||||
@ -51,8 +51,75 @@ macro_rules! int_log_bench {
|
||||
};
|
||||
}
|
||||
|
||||
int_log_bench! {u8, u8_log10_predictable, u8_log10_random, u8_log10_random_small}
|
||||
int_log_bench! {u16, u16_log10_predictable, u16_log10_random, u16_log10_random_small}
|
||||
int_log_bench! {u32, u32_log10_predictable, u32_log10_random, u32_log10_random_small}
|
||||
int_log_bench! {u64, u64_log10_predictable, u64_log10_random, u64_log10_random_small}
|
||||
int_log_bench! {u128, u128_log10_predictable, u128_log10_random, u128_log10_random_small}
|
||||
int_log10_bench! {u8, u8_log10_predictable, u8_log10_random, u8_log10_random_small}
|
||||
int_log10_bench! {u16, u16_log10_predictable, u16_log10_random, u16_log10_random_small}
|
||||
int_log10_bench! {u32, u32_log10_predictable, u32_log10_random, u32_log10_random_small}
|
||||
int_log10_bench! {u64, u64_log10_predictable, u64_log10_random, u64_log10_random_small}
|
||||
int_log10_bench! {u128, u128_log10_predictable, u128_log10_random, u128_log10_random_small}
|
||||
|
||||
macro_rules! int_log_bench {
|
||||
($t:ty, $random:ident, $random_small:ident, $geometric:ident) => {
|
||||
#[bench]
|
||||
fn $random(bench: &mut Bencher) {
|
||||
let mut rng = crate::bench_rng();
|
||||
/* Exponentially distributed random numbers from the whole range of the type. */
|
||||
let numbers: Vec<$t> = (0..256)
|
||||
.map(|_| {
|
||||
let x = rng.gen::<$t>() >> rng.gen_range(0..<$t>::BITS);
|
||||
if x >= 2 { x } else { 2 }
|
||||
})
|
||||
.collect();
|
||||
bench.iter(|| {
|
||||
for &b in &numbers {
|
||||
for &x in &numbers {
|
||||
black_box(black_box(x).ilog(b));
|
||||
}
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
#[bench]
|
||||
fn $random_small(bench: &mut Bencher) {
|
||||
let mut rng = crate::bench_rng();
|
||||
/* Exponentially distributed random numbers from the range 0..256. */
|
||||
let numbers: Vec<$t> = (0..256)
|
||||
.map(|_| {
|
||||
let x = (rng.gen::<u8>() >> rng.gen_range(0..u8::BITS)) as $t;
|
||||
if x >= 2 { x } else { 2 }
|
||||
})
|
||||
.collect();
|
||||
bench.iter(|| {
|
||||
for &b in &numbers {
|
||||
for &x in &numbers {
|
||||
black_box(black_box(x).ilog(b));
|
||||
}
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
#[bench]
|
||||
fn $geometric(bench: &mut Bencher) {
|
||||
let bases: [$t; 16] = [2, 3, 4, 5, 7, 8, 9, 15, 16, 17, 31, 32, 33, 63, 64, 65];
|
||||
let base_and_numbers: Vec<($t, Vec<$t>)> = bases
|
||||
.iter()
|
||||
.map(|&b| {
|
||||
let numbers = (0..=<$t>::MAX.ilog(b)).map(|exp| b.pow(exp)).collect();
|
||||
(b, numbers)
|
||||
})
|
||||
.collect();
|
||||
bench.iter(|| {
|
||||
for (b, numbers) in &base_and_numbers {
|
||||
for &x in numbers {
|
||||
black_box(black_box(x).ilog(black_box(*b)));
|
||||
}
|
||||
}
|
||||
});
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
int_log_bench! {u8, u8_log_random, u8_log_random_small, u8_log_geometric}
|
||||
int_log_bench! {u16, u16_log_random, u16_log_random_small, u16_log_geometric}
|
||||
int_log_bench! {u32, u32_log_random, u32_log_random_small, u32_log_geometric}
|
||||
int_log_bench! {u64, u64_log_random, u64_log_random_small, u64_log_geometric}
|
||||
int_log_bench! {u128, u128_log_random, u128_log_random_small, u128_log_geometric}
|
||||
|
@ -512,7 +512,8 @@ impl<T, const N: usize> [T; N] {
|
||||
/// # Examples
|
||||
///
|
||||
/// ```
|
||||
/// #![feature(array_try_map, generic_nonzero)]
|
||||
/// #![feature(array_try_map)]
|
||||
///
|
||||
/// let a = ["1", "2", "3"];
|
||||
/// let b = a.try_map(|v| v.parse::<u32>()).unwrap().map(|v| v + 1);
|
||||
/// assert_eq!(b, [2, 3, 4]);
|
||||
@ -522,8 +523,10 @@ impl<T, const N: usize> [T; N] {
|
||||
/// assert!(b.is_err());
|
||||
///
|
||||
/// use std::num::NonZero;
|
||||
///
|
||||
/// let z = [1, 2, 0, 3, 4];
|
||||
/// assert_eq!(z.try_map(NonZero::new), None);
|
||||
///
|
||||
/// let a = [1, 2, 3];
|
||||
/// let b = a.try_map(NonZero::new);
|
||||
/// let c = b.map(|x| x.map(NonZero::get));
|
||||
|
@ -118,7 +118,8 @@ pub trait DoubleEndedIterator: Iterator {
|
||||
/// Basic usage:
|
||||
///
|
||||
/// ```
|
||||
/// #![feature(generic_nonzero, iter_advance_by)]
|
||||
/// #![feature(iter_advance_by)]
|
||||
///
|
||||
/// use std::num::NonZero;
|
||||
///
|
||||
/// let a = [3, 4, 5, 6];
|
||||
|
@ -288,7 +288,8 @@ pub trait Iterator {
|
||||
/// # Examples
|
||||
///
|
||||
/// ```
|
||||
/// #![feature(generic_nonzero, iter_advance_by)]
|
||||
/// #![feature(iter_advance_by)]
|
||||
///
|
||||
/// use std::num::NonZero;
|
||||
///
|
||||
/// let a = [1, 2, 3, 4];
|
||||
@ -2939,7 +2940,8 @@ pub trait Iterator {
|
||||
/// This also supports other types which implement [`Try`], not just [`Result`].
|
||||
///
|
||||
/// ```
|
||||
/// #![feature(generic_nonzero, try_find)]
|
||||
/// #![feature(try_find)]
|
||||
///
|
||||
/// use std::num::NonZero;
|
||||
///
|
||||
/// let a = [3, 5, 7, 4, 9, 0, 11u32];
|
||||
|
@ -3123,21 +3123,9 @@ macro_rules! int_impl {
|
||||
if self <= 0 || base <= 1 {
|
||||
None
|
||||
} else {
|
||||
let mut n = 0;
|
||||
let mut r = self;
|
||||
|
||||
// Optimization for 128 bit wide integers.
|
||||
if Self::BITS == 128 {
|
||||
let b = Self::ilog2(self) / (Self::ilog2(base) + 1);
|
||||
n += b;
|
||||
r /= base.pow(b as u32);
|
||||
}
|
||||
|
||||
while r >= base {
|
||||
r /= base;
|
||||
n += 1;
|
||||
}
|
||||
Some(n)
|
||||
// Delegate to the unsigned implementation.
|
||||
// The condition makes sure that both casts are exact.
|
||||
(self as $UnsignedT).checked_ilog(base as $UnsignedT)
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -67,15 +67,15 @@ pub use error::ParseIntError;
|
||||
)]
|
||||
pub use nonzero::ZeroablePrimitive;
|
||||
|
||||
#[unstable(feature = "generic_nonzero", issue = "120257")]
|
||||
#[stable(feature = "generic_nonzero", since = "CURRENT_RUSTC_VERSION")]
|
||||
pub use nonzero::NonZero;
|
||||
|
||||
#[stable(feature = "nonzero", since = "1.28.0")]
|
||||
pub use nonzero::{NonZeroU128, NonZeroU16, NonZeroU32, NonZeroU64, NonZeroU8, NonZeroUsize};
|
||||
|
||||
#[stable(feature = "signed_nonzero", since = "1.34.0")]
|
||||
pub use nonzero::{NonZeroI128, NonZeroI16, NonZeroI32, NonZeroI64, NonZeroI8, NonZeroIsize};
|
||||
|
||||
#[stable(feature = "nonzero", since = "1.28.0")]
|
||||
pub use nonzero::{NonZeroU128, NonZeroU16, NonZeroU32, NonZeroU64, NonZeroU8, NonZeroUsize};
|
||||
|
||||
#[stable(feature = "try_from", since = "1.34.0")]
|
||||
pub use error::TryFromIntError;
|
||||
|
||||
|
@ -105,12 +105,11 @@ impl_zeroable_primitive!(
|
||||
/// For example, `Option<NonZero<u32>>` is the same size as `u32`:
|
||||
///
|
||||
/// ```
|
||||
/// #![feature(generic_nonzero)]
|
||||
/// use core::mem::size_of;
|
||||
/// use core::{mem::size_of, num::NonZero};
|
||||
///
|
||||
/// assert_eq!(size_of::<Option<core::num::NonZero<u32>>>(), size_of::<u32>());
|
||||
/// assert_eq!(size_of::<Option<NonZero<u32>>>(), size_of::<u32>());
|
||||
/// ```
|
||||
#[unstable(feature = "generic_nonzero", issue = "120257")]
|
||||
#[stable(feature = "generic_nonzero", since = "CURRENT_RUSTC_VERSION")]
|
||||
#[repr(transparent)]
|
||||
#[rustc_nonnull_optimization_guaranteed]
|
||||
#[rustc_diagnostic_item = "NonZero"]
|
||||
@ -562,7 +561,8 @@ macro_rules! nonzero_integer {
|
||||
/// Basic usage:
|
||||
///
|
||||
/// ```
|
||||
/// #![feature(generic_nonzero, non_zero_count_ones)]
|
||||
/// #![feature(non_zero_count_ones)]
|
||||
///
|
||||
/// # fn main() { test().unwrap(); }
|
||||
/// # fn test() -> Option<()> {
|
||||
/// # use std::num::*;
|
||||
|
@ -1095,18 +1095,25 @@ macro_rules! uint_impl {
|
||||
None
|
||||
} else {
|
||||
let mut n = 0;
|
||||
let mut r = self;
|
||||
let mut r = 1;
|
||||
|
||||
// Optimization for 128 bit wide integers.
|
||||
if Self::BITS == 128 {
|
||||
let b = Self::ilog2(self) / (Self::ilog2(base) + 1);
|
||||
n += b;
|
||||
r /= base.pow(b as u32);
|
||||
// The following is a correct lower bound for ⌊log(base,self)⌋ because
|
||||
//
|
||||
// log(base,self) = log(2,self) / log(2,base)
|
||||
// ≥ ⌊log(2,self)⌋ / (⌊log(2,base)⌋ + 1)
|
||||
//
|
||||
// hence
|
||||
//
|
||||
// ⌊log(base,self)⌋ ≥ ⌊ ⌊log(2,self)⌋ / (⌊log(2,base)⌋ + 1) ⌋ .
|
||||
n = self.ilog2() / (base.ilog2() + 1);
|
||||
r = base.pow(n);
|
||||
}
|
||||
|
||||
while r >= base {
|
||||
r /= base;
|
||||
while r <= self / base {
|
||||
n += 1;
|
||||
r *= base;
|
||||
}
|
||||
Some(n)
|
||||
}
|
||||
|
@ -42,7 +42,6 @@
|
||||
#![feature(float_minimum_maximum)]
|
||||
#![feature(future_join)]
|
||||
#![feature(generic_assert_internals)]
|
||||
#![feature(generic_nonzero)]
|
||||
#![feature(array_try_from_fn)]
|
||||
#![feature(hasher_prefixfree_extras)]
|
||||
#![feature(hashmap_internals)]
|
||||
|
@ -26,7 +26,6 @@
|
||||
#![feature(staged_api)]
|
||||
#![feature(allow_internal_unstable)]
|
||||
#![feature(decl_macro)]
|
||||
#![feature(generic_nonzero)]
|
||||
#![feature(maybe_uninit_write_slice)]
|
||||
#![feature(negative_impls)]
|
||||
#![feature(new_uninit)]
|
||||
|
@ -335,7 +335,6 @@
|
||||
#![feature(float_minimum_maximum)]
|
||||
#![feature(float_next_up_down)]
|
||||
#![feature(fmt_internals)]
|
||||
#![feature(generic_nonzero)]
|
||||
#![feature(hasher_prefixfree_extras)]
|
||||
#![feature(hashmap_internals)]
|
||||
#![feature(hint_assert_unchecked)]
|
||||
|
@ -23,11 +23,12 @@ pub use core::num::{FpCategory, ParseFloatError, ParseIntError, TryFromIntError}
|
||||
)]
|
||||
pub use core::num::ZeroablePrimitive;
|
||||
|
||||
#[unstable(feature = "generic_nonzero", issue = "120257")]
|
||||
#[stable(feature = "generic_nonzero", since = "CURRENT_RUSTC_VERSION")]
|
||||
pub use core::num::NonZero;
|
||||
|
||||
#[stable(feature = "signed_nonzero", since = "1.34.0")]
|
||||
pub use core::num::{NonZeroI128, NonZeroI16, NonZeroI32, NonZeroI64, NonZeroI8, NonZeroIsize};
|
||||
|
||||
#[stable(feature = "nonzero", since = "1.28.0")]
|
||||
pub use core::num::{NonZeroU128, NonZeroU16, NonZeroU32, NonZeroU64, NonZeroU8, NonZeroUsize};
|
||||
|
||||
|
@ -1865,7 +1865,8 @@ impl ExitStatusError {
|
||||
/// # Examples
|
||||
///
|
||||
/// ```
|
||||
/// #![feature(exit_status_error, generic_nonzero)]
|
||||
/// #![feature(exit_status_error)]
|
||||
///
|
||||
/// # if cfg!(unix) {
|
||||
/// use std::num::NonZero;
|
||||
/// use std::process::Command;
|
||||
|
@ -17,7 +17,6 @@
|
||||
#![unstable(feature = "test", issue = "50297")]
|
||||
#![doc(test(attr(deny(warnings))))]
|
||||
#![doc(rust_logo)]
|
||||
#![feature(generic_nonzero)]
|
||||
#![feature(rustdoc_internals)]
|
||||
#![feature(internal_output_capture)]
|
||||
#![feature(staged_api)]
|
||||
|
@ -1 +1 @@
|
||||
Subproject commit 3131aa4642c627a24f523c82566b94a7d920f68c
|
||||
Subproject commit d207d894cc5e1d496ab99beeacd1a420e5d4d238
|
@ -1 +1 @@
|
||||
Subproject commit eb3eb80e106d03250c1fb7c5666b1c8c59672862
|
||||
Subproject commit 0c68e90acaae5a611f8f5098a3c2980de9845ab2
|
@ -1 +1 @@
|
||||
Subproject commit 55694913b1301cc809f9bf4a1ad1b3d6920efbd9
|
||||
Subproject commit 5854fcc286557ad3ab34d325073d11d8118096b6
|
@ -1 +1 @@
|
||||
Subproject commit b77a34bd46399687b4ce6a17198e9f316c988794
|
||||
Subproject commit 07425fed36b00e60341c5e29e28d37d40cbd4451
|
@ -1,4 +1,3 @@
|
||||
#![feature(generic_nonzero)]
|
||||
#![feature(rustc_private, stmt_expr_attributes)]
|
||||
#![allow(
|
||||
clippy::manual_range_contains,
|
||||
|
@ -2,7 +2,6 @@
|
||||
#![feature(cell_update)]
|
||||
#![feature(const_option)]
|
||||
#![feature(float_gamma)]
|
||||
#![feature(generic_nonzero)]
|
||||
#![feature(map_try_insert)]
|
||||
#![feature(never_type)]
|
||||
#![feature(try_blocks)]
|
||||
|
@ -1,7 +1,6 @@
|
||||
//@ compile-flags: -O -Z merge-functions=disabled
|
||||
//@ only-x86_64
|
||||
#![crate_type = "lib"]
|
||||
#![feature(generic_nonzero)]
|
||||
|
||||
// CHECK-LABEL: @array_eq_value
|
||||
#[no_mangle]
|
||||
|
@ -7,7 +7,7 @@
|
||||
// CHECK: {{.*}}DICompositeType{{.*}}tag: DW_TAG_variant_part,{{.*}}size: 32,{{.*}}
|
||||
// CHECK: {{.*}}DIDerivedType{{.*}}tag: DW_TAG_member,{{.*}}name: "Placeholder",{{.*}}extraData: i128 4294967295{{[,)].*}}
|
||||
// CHECK: {{.*}}DIDerivedType{{.*}}tag: DW_TAG_member,{{.*}}name: "Error",{{.*}}extraData: i128 0{{[,)].*}}
|
||||
#![feature(generic_nonzero, never_type)]
|
||||
#![feature(never_type)]
|
||||
|
||||
#[derive(Copy, Clone)]
|
||||
pub struct Entity {
|
||||
|
@ -1,7 +1,6 @@
|
||||
//@ compile-flags: -O -C no-prepopulate-passes
|
||||
#![crate_type = "lib"]
|
||||
#![feature(dyn_star)]
|
||||
#![feature(generic_nonzero)]
|
||||
#![feature(allocator_api)]
|
||||
|
||||
use std::mem::MaybeUninit;
|
||||
|
@ -3,7 +3,6 @@
|
||||
//@ [DBG] compile-flags: -C opt-level=0 -C no-prepopulate-passes
|
||||
//@ only-64bit (so I don't need to worry about usize)
|
||||
#![crate_type = "lib"]
|
||||
#![feature(generic_nonzero)]
|
||||
|
||||
use std::mem::transmute;
|
||||
use std::num::NonZero;
|
||||
|
@ -4,7 +4,6 @@
|
||||
//@ compile-flags: -O --edition=2021 -Zmerge-functions=disabled
|
||||
//@ only-64bit (because the LLVM type of i64 for usize shows up)
|
||||
#![crate_type = "lib"]
|
||||
#![feature(generic_nonzero)]
|
||||
|
||||
use core::ptr::NonNull;
|
||||
use core::num::NonZero;
|
||||
|
@ -1,7 +1,6 @@
|
||||
//@ compile-flags: -C no-prepopulate-passes -Zmir-opt-level=0 -O
|
||||
|
||||
#![crate_type = "lib"]
|
||||
#![feature(generic_nonzero)]
|
||||
|
||||
use std::mem::MaybeUninit;
|
||||
use std::num::NonZero;
|
||||
|
@ -1,7 +1,6 @@
|
||||
//@ compile-flags: -O -Z randomize-layout=no
|
||||
//@ only-x86_64
|
||||
#![crate_type = "lib"]
|
||||
#![feature(generic_nonzero)]
|
||||
|
||||
extern crate core;
|
||||
|
||||
|
@ -1,7 +1,6 @@
|
||||
//@ compile-flags: -O -Zmerge-functions=disabled
|
||||
//@ min-llvm-version: 18
|
||||
#![crate_type = "lib"]
|
||||
#![feature(generic_nonzero)]
|
||||
|
||||
extern crate core;
|
||||
use core::cmp::Ordering;
|
||||
|
@ -1,6 +1,5 @@
|
||||
//@ compile-flags: -O -Zmerge-functions=disabled
|
||||
#![crate_type = "lib"]
|
||||
#![feature(generic_nonzero)]
|
||||
|
||||
use std::num::NonZero;
|
||||
|
||||
|
@ -1,6 +1,5 @@
|
||||
//@ compile-flags: -O -Z merge-functions=disabled
|
||||
#![crate_type = "lib"]
|
||||
#![feature(generic_nonzero)]
|
||||
|
||||
// This tests that LLVM can optimize based on the niches in the source or
|
||||
// destination types for transmutes.
|
||||
|
41
tests/coverage/branch/if-let.cov-map
Normal file
41
tests/coverage/branch/if-let.cov-map
Normal file
@ -0,0 +1,41 @@
|
||||
Function name: if_let::if_let
|
||||
Raw bytes (38): 0x[01, 01, 02, 05, 09, 09, 02, 06, 01, 0c, 01, 01, 10, 02, 03, 11, 00, 12, 05, 00, 16, 00, 1b, 02, 00, 1c, 02, 06, 09, 02, 0c, 02, 06, 07, 03, 05, 01, 02]
|
||||
Number of files: 1
|
||||
- file 0 => global file 1
|
||||
Number of expressions: 2
|
||||
- expression 0 operands: lhs = Counter(1), rhs = Counter(2)
|
||||
- expression 1 operands: lhs = Counter(2), rhs = Expression(0, Sub)
|
||||
Number of file 0 mappings: 6
|
||||
- Code(Counter(0)) at (prev + 12, 1) to (start + 1, 16)
|
||||
- Code(Expression(0, Sub)) at (prev + 3, 17) to (start + 0, 18)
|
||||
= (c1 - c2)
|
||||
- Code(Counter(1)) at (prev + 0, 22) to (start + 0, 27)
|
||||
- Code(Expression(0, Sub)) at (prev + 0, 28) to (start + 2, 6)
|
||||
= (c1 - c2)
|
||||
- Code(Counter(2)) at (prev + 2, 12) to (start + 2, 6)
|
||||
- Code(Expression(1, Add)) at (prev + 3, 5) to (start + 1, 2)
|
||||
= (c2 + (c1 - c2))
|
||||
|
||||
Function name: if_let::if_let_chain
|
||||
Raw bytes (52): 0x[01, 01, 04, 01, 05, 05, 09, 0f, 0d, 05, 09, 08, 01, 17, 01, 00, 33, 02, 01, 11, 00, 12, 01, 00, 16, 00, 17, 0d, 01, 15, 00, 16, 02, 00, 1a, 00, 1b, 0d, 01, 05, 03, 06, 0f, 03, 0c, 02, 06, 0b, 03, 05, 01, 02]
|
||||
Number of files: 1
|
||||
- file 0 => global file 1
|
||||
Number of expressions: 4
|
||||
- expression 0 operands: lhs = Counter(0), rhs = Counter(1)
|
||||
- expression 1 operands: lhs = Counter(1), rhs = Counter(2)
|
||||
- expression 2 operands: lhs = Expression(3, Add), rhs = Counter(3)
|
||||
- expression 3 operands: lhs = Counter(1), rhs = Counter(2)
|
||||
Number of file 0 mappings: 8
|
||||
- Code(Counter(0)) at (prev + 23, 1) to (start + 0, 51)
|
||||
- Code(Expression(0, Sub)) at (prev + 1, 17) to (start + 0, 18)
|
||||
= (c0 - c1)
|
||||
- Code(Counter(0)) at (prev + 0, 22) to (start + 0, 23)
|
||||
- Code(Counter(3)) at (prev + 1, 21) to (start + 0, 22)
|
||||
- Code(Expression(0, Sub)) at (prev + 0, 26) to (start + 0, 27)
|
||||
= (c0 - c1)
|
||||
- Code(Counter(3)) at (prev + 1, 5) to (start + 3, 6)
|
||||
- Code(Expression(3, Add)) at (prev + 3, 12) to (start + 2, 6)
|
||||
= (c1 + c2)
|
||||
- Code(Expression(2, Add)) at (prev + 3, 5) to (start + 1, 2)
|
||||
= ((c1 + c2) + c3)
|
||||
|
62
tests/coverage/branch/if-let.coverage
Normal file
62
tests/coverage/branch/if-let.coverage
Normal file
@ -0,0 +1,62 @@
|
||||
LL| |#![feature(coverage_attribute, let_chains)]
|
||||
LL| |//@ edition: 2021
|
||||
LL| |//@ compile-flags: -Zcoverage-options=branch
|
||||
LL| |//@ llvm-cov-flags: --show-branches=count
|
||||
LL| |
|
||||
LL| |macro_rules! no_merge {
|
||||
LL| | () => {
|
||||
LL| | for _ in 0..1 {}
|
||||
LL| | };
|
||||
LL| |}
|
||||
LL| |
|
||||
LL| 3|fn if_let(input: Option<&str>) {
|
||||
LL| 3| no_merge!();
|
||||
LL| |
|
||||
LL| 3| if let Some(x) = input {
|
||||
^2
|
||||
LL| 2| say(x);
|
||||
LL| 2| } else {
|
||||
LL| 1| say("none");
|
||||
LL| 1| }
|
||||
LL| 3| say("done");
|
||||
LL| 3|}
|
||||
LL| |
|
||||
LL| 15|fn if_let_chain(a: Option<&str>, b: Option<&str>) {
|
||||
LL| 15| if let Some(x) = a
|
||||
^12
|
||||
LL| 12| && let Some(y) = b
|
||||
^8
|
||||
LL| 8| {
|
||||
LL| 8| say(x);
|
||||
LL| 8| say(y);
|
||||
LL| 8| } else {
|
||||
LL| 7| say("not both");
|
||||
LL| 7| }
|
||||
LL| 15| say("done");
|
||||
LL| 15|}
|
||||
LL| |
|
||||
LL| |#[coverage(off)]
|
||||
LL| |fn say(message: &str) {
|
||||
LL| | core::hint::black_box(message);
|
||||
LL| |}
|
||||
LL| |
|
||||
LL| |#[coverage(off)]
|
||||
LL| |fn main() {
|
||||
LL| | if_let(Some("x"));
|
||||
LL| | if_let(Some("x"));
|
||||
LL| | if_let(None);
|
||||
LL| |
|
||||
LL| | for _ in 0..8 {
|
||||
LL| | if_let_chain(Some("a"), Some("b"));
|
||||
LL| | }
|
||||
LL| | for _ in 0..4 {
|
||||
LL| | if_let_chain(Some("a"), None);
|
||||
LL| | }
|
||||
LL| | for _ in 0..2 {
|
||||
LL| | if_let_chain(None, Some("b"));
|
||||
LL| | }
|
||||
LL| | if_let_chain(None, None);
|
||||
LL| |}
|
||||
LL| |
|
||||
LL| |// FIXME(#124118) Actually instrument if-let and let-chains for branch coverage.
|
||||
|
58
tests/coverage/branch/if-let.rs
Normal file
58
tests/coverage/branch/if-let.rs
Normal file
@ -0,0 +1,58 @@
|
||||
#![feature(coverage_attribute, let_chains)]
|
||||
//@ edition: 2021
|
||||
//@ compile-flags: -Zcoverage-options=branch
|
||||
//@ llvm-cov-flags: --show-branches=count
|
||||
|
||||
macro_rules! no_merge {
|
||||
() => {
|
||||
for _ in 0..1 {}
|
||||
};
|
||||
}
|
||||
|
||||
fn if_let(input: Option<&str>) {
|
||||
no_merge!();
|
||||
|
||||
if let Some(x) = input {
|
||||
say(x);
|
||||
} else {
|
||||
say("none");
|
||||
}
|
||||
say("done");
|
||||
}
|
||||
|
||||
fn if_let_chain(a: Option<&str>, b: Option<&str>) {
|
||||
if let Some(x) = a
|
||||
&& let Some(y) = b
|
||||
{
|
||||
say(x);
|
||||
say(y);
|
||||
} else {
|
||||
say("not both");
|
||||
}
|
||||
say("done");
|
||||
}
|
||||
|
||||
#[coverage(off)]
|
||||
fn say(message: &str) {
|
||||
core::hint::black_box(message);
|
||||
}
|
||||
|
||||
#[coverage(off)]
|
||||
fn main() {
|
||||
if_let(Some("x"));
|
||||
if_let(Some("x"));
|
||||
if_let(None);
|
||||
|
||||
for _ in 0..8 {
|
||||
if_let_chain(Some("a"), Some("b"));
|
||||
}
|
||||
for _ in 0..4 {
|
||||
if_let_chain(Some("a"), None);
|
||||
}
|
||||
for _ in 0..2 {
|
||||
if_let_chain(None, Some("b"));
|
||||
}
|
||||
if_let_chain(None, None);
|
||||
}
|
||||
|
||||
// FIXME(#124118) Actually instrument if-let and let-chains for branch coverage.
|
18
tests/coverage/branch/let-else.cov-map
Normal file
18
tests/coverage/branch/let-else.cov-map
Normal file
@ -0,0 +1,18 @@
|
||||
Function name: let_else::let_else
|
||||
Raw bytes (38): 0x[01, 01, 02, 05, 09, 09, 02, 06, 01, 0c, 01, 01, 10, 02, 03, 0e, 00, 0f, 05, 00, 13, 00, 18, 09, 01, 09, 01, 0f, 02, 04, 05, 00, 0b, 07, 01, 01, 00, 02]
|
||||
Number of files: 1
|
||||
- file 0 => global file 1
|
||||
Number of expressions: 2
|
||||
- expression 0 operands: lhs = Counter(1), rhs = Counter(2)
|
||||
- expression 1 operands: lhs = Counter(2), rhs = Expression(0, Sub)
|
||||
Number of file 0 mappings: 6
|
||||
- Code(Counter(0)) at (prev + 12, 1) to (start + 1, 16)
|
||||
- Code(Expression(0, Sub)) at (prev + 3, 14) to (start + 0, 15)
|
||||
= (c1 - c2)
|
||||
- Code(Counter(1)) at (prev + 0, 19) to (start + 0, 24)
|
||||
- Code(Counter(2)) at (prev + 1, 9) to (start + 1, 15)
|
||||
- Code(Expression(0, Sub)) at (prev + 4, 5) to (start + 0, 11)
|
||||
= (c1 - c2)
|
||||
- Code(Expression(1, Add)) at (prev + 1, 1) to (start + 0, 2)
|
||||
= (c2 + (c1 - c2))
|
||||
|
37
tests/coverage/branch/let-else.coverage
Normal file
37
tests/coverage/branch/let-else.coverage
Normal file
@ -0,0 +1,37 @@
|
||||
LL| |#![feature(coverage_attribute)]
|
||||
LL| |//@ edition: 2021
|
||||
LL| |//@ compile-flags: -Zcoverage-options=branch
|
||||
LL| |//@ llvm-cov-flags: --show-branches=count
|
||||
LL| |
|
||||
LL| |macro_rules! no_merge {
|
||||
LL| | () => {
|
||||
LL| | for _ in 0..1 {}
|
||||
LL| | };
|
||||
LL| |}
|
||||
LL| |
|
||||
LL| 3|fn let_else(value: Option<&str>) {
|
||||
LL| 3| no_merge!();
|
||||
LL| |
|
||||
LL| 3| let Some(x) = value else {
|
||||
^2
|
||||
LL| 1| say("none");
|
||||
LL| 1| return;
|
||||
LL| | };
|
||||
LL| |
|
||||
LL| 2| say(x);
|
||||
LL| 3|}
|
||||
LL| |
|
||||
LL| |#[coverage(off)]
|
||||
LL| |fn say(message: &str) {
|
||||
LL| | core::hint::black_box(message);
|
||||
LL| |}
|
||||
LL| |
|
||||
LL| |#[coverage(off)]
|
||||
LL| |fn main() {
|
||||
LL| | let_else(Some("x"));
|
||||
LL| | let_else(Some("x"));
|
||||
LL| | let_else(None);
|
||||
LL| |}
|
||||
LL| |
|
||||
LL| |// FIXME(#124118) Actually instrument let-else for branch coverage.
|
||||
|
35
tests/coverage/branch/let-else.rs
Normal file
35
tests/coverage/branch/let-else.rs
Normal file
@ -0,0 +1,35 @@
|
||||
#![feature(coverage_attribute)]
|
||||
//@ edition: 2021
|
||||
//@ compile-flags: -Zcoverage-options=branch
|
||||
//@ llvm-cov-flags: --show-branches=count
|
||||
|
||||
macro_rules! no_merge {
|
||||
() => {
|
||||
for _ in 0..1 {}
|
||||
};
|
||||
}
|
||||
|
||||
fn let_else(value: Option<&str>) {
|
||||
no_merge!();
|
||||
|
||||
let Some(x) = value else {
|
||||
say("none");
|
||||
return;
|
||||
};
|
||||
|
||||
say(x);
|
||||
}
|
||||
|
||||
#[coverage(off)]
|
||||
fn say(message: &str) {
|
||||
core::hint::black_box(message);
|
||||
}
|
||||
|
||||
#[coverage(off)]
|
||||
fn main() {
|
||||
let_else(Some("x"));
|
||||
let_else(Some("x"));
|
||||
let_else(None);
|
||||
}
|
||||
|
||||
// FIXME(#124118) Actually instrument let-else for branch coverage.
|
92
tests/coverage/branch/match-arms.cov-map
Normal file
92
tests/coverage/branch/match-arms.cov-map
Normal file
@ -0,0 +1,92 @@
|
||||
Function name: match_arms::guards
|
||||
Raw bytes (88): 0x[01, 01, 08, 07, 15, 0b, 11, 0f, 0d, 00, 09, 17, 25, 1b, 21, 1f, 1d, 03, 19, 0c, 01, 30, 01, 01, 10, 29, 03, 0b, 00, 10, 19, 01, 11, 00, 29, 20, 19, 09, 00, 17, 00, 1b, 1d, 01, 11, 00, 29, 20, 1d, 0d, 00, 17, 00, 1b, 21, 01, 11, 00, 29, 20, 21, 11, 00, 17, 00, 1b, 25, 01, 11, 00, 29, 20, 25, 15, 00, 17, 00, 1b, 03, 01, 0e, 00, 18, 13, 03, 05, 01, 02]
|
||||
Number of files: 1
|
||||
- file 0 => global file 1
|
||||
Number of expressions: 8
|
||||
- expression 0 operands: lhs = Expression(1, Add), rhs = Counter(5)
|
||||
- expression 1 operands: lhs = Expression(2, Add), rhs = Counter(4)
|
||||
- expression 2 operands: lhs = Expression(3, Add), rhs = Counter(3)
|
||||
- expression 3 operands: lhs = Zero, rhs = Counter(2)
|
||||
- expression 4 operands: lhs = Expression(5, Add), rhs = Counter(9)
|
||||
- expression 5 operands: lhs = Expression(6, Add), rhs = Counter(8)
|
||||
- expression 6 operands: lhs = Expression(7, Add), rhs = Counter(7)
|
||||
- expression 7 operands: lhs = Expression(0, Add), rhs = Counter(6)
|
||||
Number of file 0 mappings: 12
|
||||
- Code(Counter(0)) at (prev + 48, 1) to (start + 1, 16)
|
||||
- Code(Counter(10)) at (prev + 3, 11) to (start + 0, 16)
|
||||
- Code(Counter(6)) at (prev + 1, 17) to (start + 0, 41)
|
||||
- Branch { true: Counter(6), false: Counter(2) } at (prev + 0, 23) to (start + 0, 27)
|
||||
true = c6
|
||||
false = c2
|
||||
- Code(Counter(7)) at (prev + 1, 17) to (start + 0, 41)
|
||||
- Branch { true: Counter(7), false: Counter(3) } at (prev + 0, 23) to (start + 0, 27)
|
||||
true = c7
|
||||
false = c3
|
||||
- Code(Counter(8)) at (prev + 1, 17) to (start + 0, 41)
|
||||
- Branch { true: Counter(8), false: Counter(4) } at (prev + 0, 23) to (start + 0, 27)
|
||||
true = c8
|
||||
false = c4
|
||||
- Code(Counter(9)) at (prev + 1, 17) to (start + 0, 41)
|
||||
- Branch { true: Counter(9), false: Counter(5) } at (prev + 0, 23) to (start + 0, 27)
|
||||
true = c9
|
||||
false = c5
|
||||
- Code(Expression(0, Add)) at (prev + 1, 14) to (start + 0, 24)
|
||||
= ((((Zero + c2) + c3) + c4) + c5)
|
||||
- Code(Expression(4, Add)) at (prev + 3, 5) to (start + 1, 2)
|
||||
= ((((((((Zero + c2) + c3) + c4) + c5) + c6) + c7) + c8) + c9)
|
||||
|
||||
Function name: match_arms::match_arms
|
||||
Raw bytes (51): 0x[01, 01, 06, 05, 07, 0b, 11, 09, 0d, 13, 02, 17, 09, 11, 0d, 07, 01, 18, 01, 01, 10, 05, 03, 0b, 00, 10, 11, 01, 11, 00, 21, 0d, 01, 11, 00, 21, 09, 01, 11, 00, 21, 02, 01, 11, 00, 21, 0f, 03, 05, 01, 02]
|
||||
Number of files: 1
|
||||
- file 0 => global file 1
|
||||
Number of expressions: 6
|
||||
- expression 0 operands: lhs = Counter(1), rhs = Expression(1, Add)
|
||||
- expression 1 operands: lhs = Expression(2, Add), rhs = Counter(4)
|
||||
- expression 2 operands: lhs = Counter(2), rhs = Counter(3)
|
||||
- expression 3 operands: lhs = Expression(4, Add), rhs = Expression(0, Sub)
|
||||
- expression 4 operands: lhs = Expression(5, Add), rhs = Counter(2)
|
||||
- expression 5 operands: lhs = Counter(4), rhs = Counter(3)
|
||||
Number of file 0 mappings: 7
|
||||
- Code(Counter(0)) at (prev + 24, 1) to (start + 1, 16)
|
||||
- Code(Counter(1)) at (prev + 3, 11) to (start + 0, 16)
|
||||
- Code(Counter(4)) at (prev + 1, 17) to (start + 0, 33)
|
||||
- Code(Counter(3)) at (prev + 1, 17) to (start + 0, 33)
|
||||
- Code(Counter(2)) at (prev + 1, 17) to (start + 0, 33)
|
||||
- Code(Expression(0, Sub)) at (prev + 1, 17) to (start + 0, 33)
|
||||
= (c1 - ((c2 + c3) + c4))
|
||||
- Code(Expression(3, Add)) at (prev + 3, 5) to (start + 1, 2)
|
||||
= (((c4 + c3) + c2) + (c1 - ((c2 + c3) + c4)))
|
||||
|
||||
Function name: match_arms::or_patterns
|
||||
Raw bytes (75): 0x[01, 01, 0d, 11, 0d, 05, 2f, 33, 11, 09, 0d, 09, 2a, 05, 2f, 33, 11, 09, 0d, 03, 27, 09, 2a, 05, 2f, 33, 11, 09, 0d, 09, 01, 25, 01, 01, 10, 05, 03, 0b, 00, 10, 11, 01, 11, 00, 12, 0d, 00, 1e, 00, 1f, 03, 00, 24, 00, 2e, 09, 01, 11, 00, 12, 2a, 00, 1e, 00, 1f, 27, 00, 24, 00, 2e, 23, 03, 05, 01, 02]
|
||||
Number of files: 1
|
||||
- file 0 => global file 1
|
||||
Number of expressions: 13
|
||||
- expression 0 operands: lhs = Counter(4), rhs = Counter(3)
|
||||
- expression 1 operands: lhs = Counter(1), rhs = Expression(11, Add)
|
||||
- expression 2 operands: lhs = Expression(12, Add), rhs = Counter(4)
|
||||
- expression 3 operands: lhs = Counter(2), rhs = Counter(3)
|
||||
- expression 4 operands: lhs = Counter(2), rhs = Expression(10, Sub)
|
||||
- expression 5 operands: lhs = Counter(1), rhs = Expression(11, Add)
|
||||
- expression 6 operands: lhs = Expression(12, Add), rhs = Counter(4)
|
||||
- expression 7 operands: lhs = Counter(2), rhs = Counter(3)
|
||||
- expression 8 operands: lhs = Expression(0, Add), rhs = Expression(9, Add)
|
||||
- expression 9 operands: lhs = Counter(2), rhs = Expression(10, Sub)
|
||||
- expression 10 operands: lhs = Counter(1), rhs = Expression(11, Add)
|
||||
- expression 11 operands: lhs = Expression(12, Add), rhs = Counter(4)
|
||||
- expression 12 operands: lhs = Counter(2), rhs = Counter(3)
|
||||
Number of file 0 mappings: 9
|
||||
- Code(Counter(0)) at (prev + 37, 1) to (start + 1, 16)
|
||||
- Code(Counter(1)) at (prev + 3, 11) to (start + 0, 16)
|
||||
- Code(Counter(4)) at (prev + 1, 17) to (start + 0, 18)
|
||||
- Code(Counter(3)) at (prev + 0, 30) to (start + 0, 31)
|
||||
- Code(Expression(0, Add)) at (prev + 0, 36) to (start + 0, 46)
|
||||
= (c4 + c3)
|
||||
- Code(Counter(2)) at (prev + 1, 17) to (start + 0, 18)
|
||||
- Code(Expression(10, Sub)) at (prev + 0, 30) to (start + 0, 31)
|
||||
= (c1 - ((c2 + c3) + c4))
|
||||
- Code(Expression(9, Add)) at (prev + 0, 36) to (start + 0, 46)
|
||||
= (c2 + (c1 - ((c2 + c3) + c4)))
|
||||
- Code(Expression(8, Add)) at (prev + 3, 5) to (start + 1, 2)
|
||||
= ((c4 + c3) + (c2 + (c1 - ((c2 + c3) + c4))))
|
||||
|
105
tests/coverage/branch/match-arms.coverage
Normal file
105
tests/coverage/branch/match-arms.coverage
Normal file
@ -0,0 +1,105 @@
|
||||
LL| |#![feature(coverage_attribute)]
|
||||
LL| |//@ edition: 2021
|
||||
LL| |//@ compile-flags: -Zcoverage-options=branch
|
||||
LL| |//@ llvm-cov-flags: --show-branches=count
|
||||
LL| |
|
||||
LL| |// Tests for branch coverage of various kinds of match arms.
|
||||
LL| |
|
||||
LL| |// Helper macro to prevent start-of-function spans from being merged into
|
||||
LL| |// spans on the lines we care about.
|
||||
LL| |macro_rules! no_merge {
|
||||
LL| | () => {
|
||||
LL| | for _ in 0..1 {}
|
||||
LL| | };
|
||||
LL| |}
|
||||
LL| |
|
||||
LL| |#[derive(Clone, Copy, Debug)]
|
||||
LL| |enum Enum {
|
||||
LL| | A(u32),
|
||||
LL| | B(u32),
|
||||
LL| | C(u32),
|
||||
LL| | D(u32),
|
||||
LL| |}
|
||||
LL| |
|
||||
LL| 15|fn match_arms(value: Enum) {
|
||||
LL| 15| no_merge!();
|
||||
LL| |
|
||||
LL| 15| match value {
|
||||
LL| 8| Enum::D(d) => consume(d),
|
||||
LL| 4| Enum::C(c) => consume(c),
|
||||
LL| 2| Enum::B(b) => consume(b),
|
||||
LL| 1| Enum::A(a) => consume(a),
|
||||
LL| | }
|
||||
LL| |
|
||||
LL| 15| consume(0);
|
||||
LL| 15|}
|
||||
LL| |
|
||||
LL| 15|fn or_patterns(value: Enum) {
|
||||
LL| 15| no_merge!();
|
||||
LL| |
|
||||
LL| 15| match value {
|
||||
LL| 12| Enum::D(x) | Enum::C(x) => consume(x),
|
||||
^8 ^4
|
||||
LL| 3| Enum::B(y) | Enum::A(y) => consume(y),
|
||||
^2 ^1
|
||||
LL| | }
|
||||
LL| |
|
||||
LL| 15| consume(0);
|
||||
LL| 15|}
|
||||
LL| |
|
||||
LL| 45|fn guards(value: Enum, cond: bool) {
|
||||
LL| 45| no_merge!();
|
||||
LL| |
|
||||
LL| 3| match value {
|
||||
LL| 8| Enum::D(d) if cond => consume(d),
|
||||
------------------
|
||||
| Branch (LL:23): [True: 8, False: 16]
|
||||
------------------
|
||||
LL| 4| Enum::C(c) if cond => consume(c),
|
||||
------------------
|
||||
| Branch (LL:23): [True: 4, False: 8]
|
||||
------------------
|
||||
LL| 2| Enum::B(b) if cond => consume(b),
|
||||
------------------
|
||||
| Branch (LL:23): [True: 2, False: 4]
|
||||
------------------
|
||||
LL| 1| Enum::A(a) if cond => consume(a),
|
||||
------------------
|
||||
| Branch (LL:23): [True: 1, False: 2]
|
||||
------------------
|
||||
LL| 30| _ => consume(0),
|
||||
LL| | }
|
||||
LL| |
|
||||
LL| 45| consume(0);
|
||||
LL| 45|}
|
||||
LL| |
|
||||
LL| |#[coverage(off)]
|
||||
LL| |fn consume<T>(x: T) {
|
||||
LL| | core::hint::black_box(x);
|
||||
LL| |}
|
||||
LL| |
|
||||
LL| |#[coverage(off)]
|
||||
LL| |fn main() {
|
||||
LL| | #[coverage(off)]
|
||||
LL| | fn call_everything(e: Enum) {
|
||||
LL| | match_arms(e);
|
||||
LL| | or_patterns(e);
|
||||
LL| | for cond in [false, false, true] {
|
||||
LL| | guards(e, cond);
|
||||
LL| | }
|
||||
LL| | }
|
||||
LL| |
|
||||
LL| | call_everything(Enum::A(0));
|
||||
LL| | for b in 0..2 {
|
||||
LL| | call_everything(Enum::B(b));
|
||||
LL| | }
|
||||
LL| | for c in 0..4 {
|
||||
LL| | call_everything(Enum::C(c));
|
||||
LL| | }
|
||||
LL| | for d in 0..8 {
|
||||
LL| | call_everything(Enum::D(d));
|
||||
LL| | }
|
||||
LL| |}
|
||||
LL| |
|
||||
LL| |// FIXME(#124118) Actually instrument match arms for branch coverage.
|
||||
|
90
tests/coverage/branch/match-arms.rs
Normal file
90
tests/coverage/branch/match-arms.rs
Normal file
@ -0,0 +1,90 @@
|
||||
#![feature(coverage_attribute)]
|
||||
//@ edition: 2021
|
||||
//@ compile-flags: -Zcoverage-options=branch
|
||||
//@ llvm-cov-flags: --show-branches=count
|
||||
|
||||
// Tests for branch coverage of various kinds of match arms.
|
||||
|
||||
// Helper macro to prevent start-of-function spans from being merged into
|
||||
// spans on the lines we care about.
|
||||
macro_rules! no_merge {
|
||||
() => {
|
||||
for _ in 0..1 {}
|
||||
};
|
||||
}
|
||||
|
||||
#[derive(Clone, Copy, Debug)]
|
||||
enum Enum {
|
||||
A(u32),
|
||||
B(u32),
|
||||
C(u32),
|
||||
D(u32),
|
||||
}
|
||||
|
||||
fn match_arms(value: Enum) {
|
||||
no_merge!();
|
||||
|
||||
match value {
|
||||
Enum::D(d) => consume(d),
|
||||
Enum::C(c) => consume(c),
|
||||
Enum::B(b) => consume(b),
|
||||
Enum::A(a) => consume(a),
|
||||
}
|
||||
|
||||
consume(0);
|
||||
}
|
||||
|
||||
fn or_patterns(value: Enum) {
|
||||
no_merge!();
|
||||
|
||||
match value {
|
||||
Enum::D(x) | Enum::C(x) => consume(x),
|
||||
Enum::B(y) | Enum::A(y) => consume(y),
|
||||
}
|
||||
|
||||
consume(0);
|
||||
}
|
||||
|
||||
fn guards(value: Enum, cond: bool) {
|
||||
no_merge!();
|
||||
|
||||
match value {
|
||||
Enum::D(d) if cond => consume(d),
|
||||
Enum::C(c) if cond => consume(c),
|
||||
Enum::B(b) if cond => consume(b),
|
||||
Enum::A(a) if cond => consume(a),
|
||||
_ => consume(0),
|
||||
}
|
||||
|
||||
consume(0);
|
||||
}
|
||||
|
||||
#[coverage(off)]
|
||||
fn consume<T>(x: T) {
|
||||
core::hint::black_box(x);
|
||||
}
|
||||
|
||||
#[coverage(off)]
|
||||
fn main() {
|
||||
#[coverage(off)]
|
||||
fn call_everything(e: Enum) {
|
||||
match_arms(e);
|
||||
or_patterns(e);
|
||||
for cond in [false, false, true] {
|
||||
guards(e, cond);
|
||||
}
|
||||
}
|
||||
|
||||
call_everything(Enum::A(0));
|
||||
for b in 0..2 {
|
||||
call_everything(Enum::B(b));
|
||||
}
|
||||
for c in 0..4 {
|
||||
call_everything(Enum::C(c));
|
||||
}
|
||||
for d in 0..8 {
|
||||
call_everything(Enum::D(d));
|
||||
}
|
||||
}
|
||||
|
||||
// FIXME(#124118) Actually instrument match arms for branch coverage.
|
17
tests/coverage/branch/match-trivial.cov-map
Normal file
17
tests/coverage/branch/match-trivial.cov-map
Normal file
@ -0,0 +1,17 @@
|
||||
Function name: match_trivial::_uninhabited (unused)
|
||||
Raw bytes (9): 0x[01, 01, 00, 01, 00, 16, 01, 01, 10]
|
||||
Number of files: 1
|
||||
- file 0 => global file 1
|
||||
Number of expressions: 0
|
||||
Number of file 0 mappings: 1
|
||||
- Code(Zero) at (prev + 22, 1) to (start + 1, 16)
|
||||
|
||||
Function name: match_trivial::trivial
|
||||
Raw bytes (14): 0x[01, 01, 00, 02, 01, 1e, 01, 01, 10, 05, 03, 0b, 05, 02]
|
||||
Number of files: 1
|
||||
- file 0 => global file 1
|
||||
Number of expressions: 0
|
||||
Number of file 0 mappings: 2
|
||||
- Code(Counter(0)) at (prev + 30, 1) to (start + 1, 16)
|
||||
- Code(Counter(1)) at (prev + 3, 11) to (start + 5, 2)
|
||||
|
49
tests/coverage/branch/match-trivial.coverage
Normal file
49
tests/coverage/branch/match-trivial.coverage
Normal file
@ -0,0 +1,49 @@
|
||||
LL| |#![feature(coverage_attribute)]
|
||||
LL| |//@ edition: 2021
|
||||
LL| |//@ compile-flags: -Zcoverage-options=branch
|
||||
LL| |//@ llvm-cov-flags: --show-branches=count
|
||||
LL| |
|
||||
LL| |// When instrumenting match expressions for branch coverage, make sure we don't
|
||||
LL| |// cause an ICE or produce weird coverage output for matches with <2 arms.
|
||||
LL| |
|
||||
LL| |// Helper macro to prevent start-of-function spans from being merged into
|
||||
LL| |// spans on the lines we care about.
|
||||
LL| |macro_rules! no_merge {
|
||||
LL| | () => {
|
||||
LL| | for _ in 0..1 {}
|
||||
LL| | };
|
||||
LL| |}
|
||||
LL| |
|
||||
LL| |enum Uninhabited {}
|
||||
LL| |enum Trivial {
|
||||
LL| | Value,
|
||||
LL| |}
|
||||
LL| |
|
||||
LL| 0|fn _uninhabited(x: Uninhabited) {
|
||||
LL| 0| no_merge!();
|
||||
LL| |
|
||||
LL| | match x {}
|
||||
LL| |
|
||||
LL| | consume("done");
|
||||
LL| |}
|
||||
LL| |
|
||||
LL| 1|fn trivial(x: Trivial) {
|
||||
LL| 1| no_merge!();
|
||||
LL| |
|
||||
LL| 1| match x {
|
||||
LL| 1| Trivial::Value => consume("trivial"),
|
||||
LL| 1| }
|
||||
LL| 1|
|
||||
LL| 1| consume("done");
|
||||
LL| 1|}
|
||||
LL| |
|
||||
LL| |#[coverage(off)]
|
||||
LL| |fn consume<T>(x: T) {
|
||||
LL| | core::hint::black_box(x);
|
||||
LL| |}
|
||||
LL| |
|
||||
LL| |#[coverage(off)]
|
||||
LL| |fn main() {
|
||||
LL| | trivial(Trivial::Value);
|
||||
LL| |}
|
||||
|
48
tests/coverage/branch/match-trivial.rs
Normal file
48
tests/coverage/branch/match-trivial.rs
Normal file
@ -0,0 +1,48 @@
|
||||
#![feature(coverage_attribute)]
|
||||
//@ edition: 2021
|
||||
//@ compile-flags: -Zcoverage-options=branch
|
||||
//@ llvm-cov-flags: --show-branches=count
|
||||
|
||||
// When instrumenting match expressions for branch coverage, make sure we don't
|
||||
// cause an ICE or produce weird coverage output for matches with <2 arms.
|
||||
|
||||
// Helper macro to prevent start-of-function spans from being merged into
|
||||
// spans on the lines we care about.
|
||||
macro_rules! no_merge {
|
||||
() => {
|
||||
for _ in 0..1 {}
|
||||
};
|
||||
}
|
||||
|
||||
enum Uninhabited {}
|
||||
enum Trivial {
|
||||
Value,
|
||||
}
|
||||
|
||||
fn _uninhabited(x: Uninhabited) {
|
||||
no_merge!();
|
||||
|
||||
match x {}
|
||||
|
||||
consume("done");
|
||||
}
|
||||
|
||||
fn trivial(x: Trivial) {
|
||||
no_merge!();
|
||||
|
||||
match x {
|
||||
Trivial::Value => consume("trivial"),
|
||||
}
|
||||
|
||||
consume("done");
|
||||
}
|
||||
|
||||
#[coverage(off)]
|
||||
fn consume<T>(x: T) {
|
||||
core::hint::black_box(x);
|
||||
}
|
||||
|
||||
#[coverage(off)]
|
||||
fn main() {
|
||||
trivial(Trivial::Value);
|
||||
}
|
@ -132,7 +132,6 @@
|
||||
// cdb-command: dx -r2 arbitrary_discr2,d
|
||||
// cdb-check: arbitrary_discr2,d : Def [Type: enum2$<msvc_pretty_enums::ArbitraryDiscr>]
|
||||
// cdb-check: [+0x[...]] __0 : 5678 [Type: unsigned int]
|
||||
#![feature(generic_nonzero)]
|
||||
#![feature(rustc_attrs)]
|
||||
#![feature(repr128)]
|
||||
#![feature(arbitrary_enum_discriminant)]
|
||||
|
@ -237,7 +237,6 @@
|
||||
|
||||
// lldb-command:v nz_usize
|
||||
// lldb-check:[...] 122 { __0 = { 0 = 122 } }
|
||||
#![feature(generic_nonzero)]
|
||||
|
||||
use std::num::*;
|
||||
use std::sync::atomic::*;
|
||||
|
@ -0,0 +1,138 @@
|
||||
- // MIR for `main` before InstrumentCoverage
|
||||
+ // MIR for `main` after InstrumentCoverage
|
||||
|
||||
fn main() -> () {
|
||||
let mut _0: ();
|
||||
let mut _1: Enum;
|
||||
let mut _2: isize;
|
||||
let _3: u32;
|
||||
let mut _4: u32;
|
||||
let _5: u32;
|
||||
let mut _6: u32;
|
||||
let _7: u32;
|
||||
let mut _8: u32;
|
||||
let _9: u32;
|
||||
let mut _10: u32;
|
||||
scope 1 {
|
||||
debug d => _3;
|
||||
}
|
||||
scope 2 {
|
||||
debug c => _5;
|
||||
}
|
||||
scope 3 {
|
||||
debug b => _7;
|
||||
}
|
||||
scope 4 {
|
||||
debug a => _9;
|
||||
}
|
||||
|
||||
+ coverage ExpressionId(0) => Expression { lhs: Counter(1), op: Add, rhs: Counter(2) };
|
||||
+ coverage ExpressionId(1) => Expression { lhs: Expression(0), op: Add, rhs: Counter(3) };
|
||||
+ coverage ExpressionId(2) => Expression { lhs: Counter(0), op: Subtract, rhs: Expression(1) };
|
||||
+ coverage ExpressionId(3) => Expression { lhs: Counter(3), op: Add, rhs: Counter(2) };
|
||||
+ coverage ExpressionId(4) => Expression { lhs: Expression(3), op: Add, rhs: Counter(1) };
|
||||
+ coverage ExpressionId(5) => Expression { lhs: Expression(4), op: Add, rhs: Expression(2) };
|
||||
+ coverage Code(Counter(0)) => $DIR/branch_match_arms.rs:14:1 - 15:21;
|
||||
+ coverage Code(Counter(3)) => $DIR/branch_match_arms.rs:16:17 - 16:33;
|
||||
+ coverage Code(Counter(2)) => $DIR/branch_match_arms.rs:17:17 - 17:33;
|
||||
+ coverage Code(Counter(1)) => $DIR/branch_match_arms.rs:18:17 - 18:33;
|
||||
+ coverage Code(Expression(2)) => $DIR/branch_match_arms.rs:19:17 - 19:33;
|
||||
+ coverage Code(Expression(5)) => $DIR/branch_match_arms.rs:21:1 - 21:2;
|
||||
+
|
||||
bb0: {
|
||||
+ Coverage::CounterIncrement(0);
|
||||
StorageLive(_1);
|
||||
_1 = Enum::A(const 0_u32);
|
||||
PlaceMention(_1);
|
||||
_2 = discriminant(_1);
|
||||
switchInt(move _2) -> [0: bb5, 1: bb4, 2: bb3, 3: bb2, otherwise: bb1];
|
||||
}
|
||||
|
||||
bb1: {
|
||||
FakeRead(ForMatchedPlace(None), _1);
|
||||
unreachable;
|
||||
}
|
||||
|
||||
bb2: {
|
||||
+ Coverage::CounterIncrement(3);
|
||||
falseEdge -> [real: bb6, imaginary: bb3];
|
||||
}
|
||||
|
||||
bb3: {
|
||||
+ Coverage::CounterIncrement(2);
|
||||
falseEdge -> [real: bb8, imaginary: bb4];
|
||||
}
|
||||
|
||||
bb4: {
|
||||
+ Coverage::CounterIncrement(1);
|
||||
falseEdge -> [real: bb10, imaginary: bb5];
|
||||
}
|
||||
|
||||
bb5: {
|
||||
+ Coverage::ExpressionUsed(2);
|
||||
StorageLive(_9);
|
||||
_9 = ((_1 as A).0: u32);
|
||||
StorageLive(_10);
|
||||
_10 = _9;
|
||||
_0 = consume(move _10) -> [return: bb12, unwind: bb14];
|
||||
}
|
||||
|
||||
bb6: {
|
||||
StorageLive(_3);
|
||||
_3 = ((_1 as D).0: u32);
|
||||
StorageLive(_4);
|
||||
_4 = _3;
|
||||
_0 = consume(move _4) -> [return: bb7, unwind: bb14];
|
||||
}
|
||||
|
||||
bb7: {
|
||||
StorageDead(_4);
|
||||
StorageDead(_3);
|
||||
goto -> bb13;
|
||||
}
|
||||
|
||||
bb8: {
|
||||
StorageLive(_5);
|
||||
_5 = ((_1 as C).0: u32);
|
||||
StorageLive(_6);
|
||||
_6 = _5;
|
||||
_0 = consume(move _6) -> [return: bb9, unwind: bb14];
|
||||
}
|
||||
|
||||
bb9: {
|
||||
StorageDead(_6);
|
||||
StorageDead(_5);
|
||||
goto -> bb13;
|
||||
}
|
||||
|
||||
bb10: {
|
||||
StorageLive(_7);
|
||||
_7 = ((_1 as B).0: u32);
|
||||
StorageLive(_8);
|
||||
_8 = _7;
|
||||
_0 = consume(move _8) -> [return: bb11, unwind: bb14];
|
||||
}
|
||||
|
||||
bb11: {
|
||||
StorageDead(_8);
|
||||
StorageDead(_7);
|
||||
goto -> bb13;
|
||||
}
|
||||
|
||||
bb12: {
|
||||
StorageDead(_10);
|
||||
StorageDead(_9);
|
||||
goto -> bb13;
|
||||
}
|
||||
|
||||
bb13: {
|
||||
+ Coverage::ExpressionUsed(5);
|
||||
StorageDead(_1);
|
||||
return;
|
||||
}
|
||||
|
||||
bb14 (cleanup): {
|
||||
resume;
|
||||
}
|
||||
}
|
||||
|
27
tests/mir-opt/coverage/branch_match_arms.rs
Normal file
27
tests/mir-opt/coverage/branch_match_arms.rs
Normal file
@ -0,0 +1,27 @@
|
||||
#![feature(coverage_attribute)]
|
||||
//@ test-mir-pass: InstrumentCoverage
|
||||
//@ compile-flags: -Cinstrument-coverage -Zno-profiler-runtime -Zcoverage-options=branch
|
||||
// skip-filecheck
|
||||
|
||||
enum Enum {
|
||||
A(u32),
|
||||
B(u32),
|
||||
C(u32),
|
||||
D(u32),
|
||||
}
|
||||
|
||||
// EMIT_MIR branch_match_arms.main.InstrumentCoverage.diff
|
||||
fn main() {
|
||||
match Enum::A(0) {
|
||||
Enum::D(d) => consume(d),
|
||||
Enum::C(c) => consume(c),
|
||||
Enum::B(b) => consume(b),
|
||||
Enum::A(a) => consume(a),
|
||||
}
|
||||
}
|
||||
|
||||
#[inline(never)]
|
||||
#[coverage(off)]
|
||||
fn consume(x: u32) {
|
||||
core::hint::black_box(x);
|
||||
}
|
@ -3,7 +3,6 @@
|
||||
#![crate_type = "lib"]
|
||||
#![feature(core_intrinsics)]
|
||||
#![feature(custom_mir)]
|
||||
#![feature(generic_nonzero)]
|
||||
|
||||
use std::intrinsics::mir::*;
|
||||
use std::mem::{MaybeUninit, ManuallyDrop, transmute};
|
||||
|
@ -64,7 +64,6 @@
|
||||
[csky] needs-llvm-components: csky
|
||||
*/
|
||||
#![feature(rustc_attrs, unsized_fn_params, transparent_unions)]
|
||||
#![cfg_attr(host, feature(generic_nonzero))]
|
||||
#![cfg_attr(not(host), feature(no_core, lang_items), no_std, no_core)]
|
||||
#![allow(unused, improper_ctypes_definitions, internal_features)]
|
||||
|
||||
|
@ -3,7 +3,7 @@
|
||||
// ignore-tidy-linelength
|
||||
//@ normalize-stderr-test "╾─*ALLOC[0-9]+(\+[a-z0-9]+)?(<imm>)?─*╼" -> "╾ALLOC_ID$1╼"
|
||||
#![allow(invalid_value)]
|
||||
#![feature(generic_nonzero, never_type, rustc_attrs, ptr_metadata, slice_from_ptr_range, const_slice_from_ptr_range)]
|
||||
#![feature(never_type, rustc_attrs, ptr_metadata, slice_from_ptr_range, const_slice_from_ptr_range)]
|
||||
|
||||
use std::mem;
|
||||
use std::alloc::Layout;
|
||||
|
@ -2,7 +2,7 @@
|
||||
//@ normalize-stderr-test "(the raw bytes of the constant) \(size: [0-9]*, align: [0-9]*\)" -> "$1 (size: $$SIZE, align: $$ALIGN)"
|
||||
//@ normalize-stderr-test "([0-9a-f][0-9a-f] |╾─*ALLOC[0-9]+(\+[a-z0-9]+)?─*╼ )+ *│.*" -> "HEX_DUMP"
|
||||
#![allow(invalid_value)] // make sure we cannot allow away the errors tested here
|
||||
#![feature(generic_nonzero, rustc_attrs, ptr_metadata)]
|
||||
#![feature(rustc_attrs, ptr_metadata)]
|
||||
|
||||
use std::mem;
|
||||
use std::ptr::NonNull;
|
||||
|
@ -1,7 +1,6 @@
|
||||
//@ check-pass
|
||||
//
|
||||
// Some constants that *are* valid
|
||||
#![feature(generic_nonzero)]
|
||||
|
||||
use std::mem;
|
||||
use std::ptr::NonNull;
|
||||
|
@ -1,7 +1,6 @@
|
||||
//@ run-pass
|
||||
//
|
||||
// https://github.com/rust-lang/rust/issues/41898
|
||||
#![feature(generic_nonzero)]
|
||||
|
||||
use std::num::NonZero;
|
||||
|
||||
|
@ -7,7 +7,6 @@
|
||||
//
|
||||
// This test checks panic emitted from `mem::{uninitialized,zeroed}`.
|
||||
#![allow(deprecated, invalid_value)]
|
||||
#![feature(generic_nonzero)]
|
||||
#![feature(never_type)]
|
||||
|
||||
use std::{
|
||||
|
@ -1,6 +1,5 @@
|
||||
//@ check-pass
|
||||
#![deny(improper_ctypes)]
|
||||
#![feature(generic_nonzero)]
|
||||
|
||||
pub struct Error(std::num::NonZero<u32>);
|
||||
|
||||
|
@ -6,7 +6,6 @@
|
||||
//@ check-pass
|
||||
//@ compile-flags: --crate-type=lib
|
||||
//@ only-x86
|
||||
#![feature(generic_nonzero)]
|
||||
#![feature(repr_simd)]
|
||||
|
||||
use std::cell::{UnsafeCell, RefCell, Cell};
|
||||
|
Some files were not shown because too many files have changed in this diff Show More
Loading…
x
Reference in New Issue
Block a user