mirror of
https://github.com/rust-lang/rust.git
synced 2025-05-14 02:49:40 +00:00
Auto merge of #118771 - workingjubilee:rollup-q1p3riz, r=workingjubilee
Rollup of 7 pull requests Successful merges: - #118198 (coverage: Use `SpanMarker` to improve coverage spans for `if !` expressions) - #118512 (Add tests related to normalization in implied bounds) - #118610 (update target feature following LLVM API change) - #118666 (coverage: Simplify the heuristic for ignoring `async fn` return spans) - #118737 (Extend tidy alphabetical checking to `tests/`.) - #118762 (Some more minor `async gen`-related nits) - #118764 (Make async generators fused by default) r? `@ghost` `@rustbot` modify labels: rollup
This commit is contained in:
commit
ce670339c3
@ -2450,6 +2450,14 @@ impl CoroutineKind {
|
||||
matches!(self, CoroutineKind::Gen { .. })
|
||||
}
|
||||
|
||||
pub fn closure_id(self) -> NodeId {
|
||||
match self {
|
||||
CoroutineKind::Async { closure_id, .. }
|
||||
| CoroutineKind::Gen { closure_id, .. }
|
||||
| CoroutineKind::AsyncGen { closure_id, .. } => closure_id,
|
||||
}
|
||||
}
|
||||
|
||||
/// In this case this is an `async` or `gen` return, the `NodeId` for the generated `impl Trait`
|
||||
/// item.
|
||||
pub fn return_id(self) -> (NodeId, Span) {
|
||||
|
@ -1035,10 +1035,7 @@ impl<'hir> LoweringContext<'_, 'hir> {
|
||||
let (Some(coroutine_kind), Some(body)) = (coroutine_kind, body) else {
|
||||
return self.lower_fn_body_block(span, decl, body);
|
||||
};
|
||||
// FIXME(gen_blocks): Introduce `closure_id` method and remove ALL destructuring.
|
||||
let (CoroutineKind::Async { closure_id, .. }
|
||||
| CoroutineKind::Gen { closure_id, .. }
|
||||
| CoroutineKind::AsyncGen { closure_id, .. }) = coroutine_kind;
|
||||
let closure_id = coroutine_kind.closure_id();
|
||||
|
||||
self.lower_body(|this| {
|
||||
let mut parameters: Vec<hir::Param<'_>> = Vec::new();
|
||||
|
@ -177,7 +177,8 @@ impl<'a, 'hir> LoweringContext<'a, 'hir> {
|
||||
} else {
|
||||
[sym::gen_future].into()
|
||||
},
|
||||
// FIXME(gen_blocks): how does `closure_track_caller`
|
||||
// FIXME(gen_blocks): how does `closure_track_caller`/`async_fn_track_caller`
|
||||
// interact with `gen`/`async gen` blocks
|
||||
allow_async_iterator: [sym::gen_future, sym::async_iterator].into(),
|
||||
generics_def_id_map: Default::default(),
|
||||
host_param_id: None,
|
||||
|
@ -1271,11 +1271,11 @@ impl<'a> Visitor<'a> for AstValidator<'a> {
|
||||
// Functions cannot both be `const async` or `const gen`
|
||||
if let Some(&FnHeader {
|
||||
constness: Const::Yes(cspan),
|
||||
coroutine_kind: Some(coro_kind),
|
||||
coroutine_kind: Some(coroutine_kind),
|
||||
..
|
||||
}) = fk.header()
|
||||
{
|
||||
let aspan = match coro_kind {
|
||||
let aspan = match coroutine_kind {
|
||||
CoroutineKind::Async { span: aspan, .. }
|
||||
| CoroutineKind::Gen { span: aspan, .. }
|
||||
| CoroutineKind::AsyncGen { span: aspan, .. } => aspan,
|
||||
|
@ -541,8 +541,8 @@ fn check_test_signature(
|
||||
return Err(sd.emit_err(errors::TestBadFn { span: i.span, cause: span, kind: "unsafe" }));
|
||||
}
|
||||
|
||||
if let Some(coro_kind) = f.sig.header.coroutine_kind {
|
||||
match coro_kind {
|
||||
if let Some(coroutine_kind) = f.sig.header.coroutine_kind {
|
||||
match coroutine_kind {
|
||||
ast::CoroutineKind::Async { span, .. } => {
|
||||
return Err(sd.emit_err(errors::TestBadFn {
|
||||
span: i.span,
|
||||
|
@ -100,6 +100,9 @@ impl<'tcx> CoverageInfoBuilderMethods<'tcx> for Builder<'_, '_, 'tcx> {
|
||||
|
||||
let Coverage { kind } = coverage;
|
||||
match *kind {
|
||||
// Span markers are only meaningful during MIR instrumentation,
|
||||
// and have no effect during codegen.
|
||||
CoverageKind::SpanMarker => {}
|
||||
CoverageKind::CounterIncrement { id } => {
|
||||
func_coverage.mark_counter_id_seen(id);
|
||||
// We need to explicitly drop the `RefMut` before calling into `instrprof_increment`,
|
||||
|
@ -263,6 +263,10 @@ pub fn to_llvm_features<'a>(sess: &Session, s: &'a str) -> LLVMFeature<'a> {
|
||||
"sve2-bitperm",
|
||||
TargetFeatureFoldStrength::EnableOnly("neon"),
|
||||
),
|
||||
// The unaligned-scalar-mem feature was renamed to fast-unaligned-access.
|
||||
("riscv32" | "riscv64", "fast-unaligned-access") if get_version().0 <= 17 => {
|
||||
LLVMFeature::new("unaligned-scalar-mem")
|
||||
}
|
||||
(_, s) => LLVMFeature::new(s),
|
||||
}
|
||||
}
|
||||
|
@ -291,9 +291,9 @@ const RISCV_ALLOWED_FEATURES: &[(&str, Stability)] = &[
|
||||
("d", Unstable(sym::riscv_target_feature)),
|
||||
("e", Unstable(sym::riscv_target_feature)),
|
||||
("f", Unstable(sym::riscv_target_feature)),
|
||||
("fast-unaligned-access", Unstable(sym::riscv_target_feature)),
|
||||
("m", Stable),
|
||||
("relax", Unstable(sym::riscv_target_feature)),
|
||||
("unaligned-scalar-mem", Unstable(sym::riscv_target_feature)),
|
||||
("v", Unstable(sym::riscv_target_feature)),
|
||||
("zba", Stable),
|
||||
("zbb", Stable),
|
||||
|
@ -162,11 +162,8 @@ impl<'a, T: EarlyLintPass> ast_visit::Visitor<'a> for EarlyContextAndPass<'a, T>
|
||||
// Explicitly check for lints associated with 'closure_id', since
|
||||
// it does not have a corresponding AST node
|
||||
if let ast_visit::FnKind::Fn(_, _, sig, _, _, _) = fk {
|
||||
if let Some(coro_kind) = sig.header.coroutine_kind {
|
||||
let (ast::CoroutineKind::Async { closure_id, .. }
|
||||
| ast::CoroutineKind::Gen { closure_id, .. }
|
||||
| ast::CoroutineKind::AsyncGen { closure_id, .. }) = coro_kind;
|
||||
self.check_id(closure_id);
|
||||
if let Some(coroutine_kind) = sig.header.coroutine_kind {
|
||||
self.check_id(coroutine_kind.closure_id());
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -226,12 +223,10 @@ impl<'a, T: EarlyLintPass> ast_visit::Visitor<'a> for EarlyContextAndPass<'a, T>
|
||||
// it does not have a corresponding AST node
|
||||
match e.kind {
|
||||
ast::ExprKind::Closure(box ast::Closure {
|
||||
coroutine_kind: Some(coro_kind), ..
|
||||
coroutine_kind: Some(coroutine_kind),
|
||||
..
|
||||
}) => {
|
||||
let (ast::CoroutineKind::Async { closure_id, .. }
|
||||
| ast::CoroutineKind::Gen { closure_id, .. }
|
||||
| ast::CoroutineKind::AsyncGen { closure_id, .. }) = coro_kind;
|
||||
self.check_id(closure_id);
|
||||
self.check_id(coroutine_kind.closure_id());
|
||||
}
|
||||
_ => {}
|
||||
}
|
||||
|
@ -76,6 +76,13 @@ impl Debug for CovTerm {
|
||||
|
||||
#[derive(Clone, PartialEq, TyEncodable, TyDecodable, Hash, HashStable, TypeFoldable, TypeVisitable)]
|
||||
pub enum CoverageKind {
|
||||
/// Marks a span that might otherwise not be represented in MIR, so that
|
||||
/// coverage instrumentation can associate it with its enclosing block/BCB.
|
||||
///
|
||||
/// Only used by the `InstrumentCoverage` pass, and has no effect during
|
||||
/// codegen.
|
||||
SpanMarker,
|
||||
|
||||
/// Marks the point in MIR control flow represented by a coverage counter.
|
||||
///
|
||||
/// This is eventually lowered to `llvm.instrprof.increment` in LLVM IR.
|
||||
@ -99,6 +106,7 @@ impl Debug for CoverageKind {
|
||||
fn fmt(&self, fmt: &mut Formatter<'_>) -> fmt::Result {
|
||||
use CoverageKind::*;
|
||||
match self {
|
||||
SpanMarker => write!(fmt, "SpanMarker"),
|
||||
CounterIncrement { id } => write!(fmt, "CounterIncrement({:?})", id.index()),
|
||||
ExpressionUsed { id } => write!(fmt, "ExpressionUsed({:?})", id.index()),
|
||||
}
|
||||
|
@ -101,6 +101,19 @@ impl<'tcx> CFG<'tcx> {
|
||||
self.push(block, stmt);
|
||||
}
|
||||
|
||||
/// Adds a dummy statement whose only role is to associate a span with its
|
||||
/// enclosing block for the purposes of coverage instrumentation.
|
||||
///
|
||||
/// This results in more accurate coverage reports for certain kinds of
|
||||
/// syntax (e.g. `continue` or `if !`) that would otherwise not appear in MIR.
|
||||
pub(crate) fn push_coverage_span_marker(&mut self, block: BasicBlock, source_info: SourceInfo) {
|
||||
let kind = StatementKind::Coverage(Box::new(Coverage {
|
||||
kind: coverage::CoverageKind::SpanMarker,
|
||||
}));
|
||||
let stmt = Statement { source_info, kind };
|
||||
self.push(block, stmt);
|
||||
}
|
||||
|
||||
pub(crate) fn terminate(
|
||||
&mut self,
|
||||
block: BasicBlock,
|
||||
|
@ -90,6 +90,11 @@ impl<'a, 'tcx> Builder<'a, 'tcx> {
|
||||
let local_scope = this.local_scope();
|
||||
let (success_block, failure_block) =
|
||||
this.in_if_then_scope(local_scope, expr_span, |this| {
|
||||
// Help out coverage instrumentation by injecting a dummy statement with
|
||||
// the original condition's span (including `!`). This fixes #115468.
|
||||
if this.tcx.sess.instrument_coverage() {
|
||||
this.cfg.push_coverage_span_marker(block, this.source_info(expr_span));
|
||||
}
|
||||
this.then_else_break(
|
||||
block,
|
||||
&this.thir[arg],
|
||||
|
@ -90,7 +90,6 @@ use rustc_index::{IndexSlice, IndexVec};
|
||||
use rustc_middle::middle::region;
|
||||
use rustc_middle::mir::*;
|
||||
use rustc_middle::thir::{Expr, LintLevel};
|
||||
use rustc_middle::ty::Ty;
|
||||
use rustc_session::lint::Level;
|
||||
use rustc_span::{Span, DUMMY_SP};
|
||||
|
||||
@ -660,14 +659,15 @@ impl<'a, 'tcx> Builder<'a, 'tcx> {
|
||||
(None, Some(_)) => {
|
||||
panic!("`return`, `become` and `break` with value and must have a destination")
|
||||
}
|
||||
(None, None) if self.tcx.sess.instrument_coverage() => {
|
||||
// Unlike `break` and `return`, which push an `Assign` statement to MIR, from which
|
||||
// a Coverage code region can be generated, `continue` needs no `Assign`; but
|
||||
// without one, the `InstrumentCoverage` MIR pass cannot generate a code region for
|
||||
// `continue`. Coverage will be missing unless we add a dummy `Assign` to MIR.
|
||||
self.add_dummy_assignment(span, block, source_info);
|
||||
(None, None) => {
|
||||
if self.tcx.sess.instrument_coverage() {
|
||||
// Normally we wouldn't build any MIR in this case, but that makes it
|
||||
// harder for coverage instrumentation to extract a relevant span for
|
||||
// `continue` expressions. So here we inject a dummy statement with the
|
||||
// desired span.
|
||||
self.cfg.push_coverage_span_marker(block, source_info);
|
||||
}
|
||||
}
|
||||
(None, None) => {}
|
||||
}
|
||||
|
||||
let region_scope = self.scopes.breakable_scopes[break_index].region_scope;
|
||||
@ -723,14 +723,6 @@ impl<'a, 'tcx> Builder<'a, 'tcx> {
|
||||
self.cfg.terminate(block, source_info, TerminatorKind::UnwindResume);
|
||||
}
|
||||
|
||||
// Add a dummy `Assign` statement to the CFG, with the span for the source code's `continue`
|
||||
// statement.
|
||||
fn add_dummy_assignment(&mut self, span: Span, block: BasicBlock, source_info: SourceInfo) {
|
||||
let local_decl = LocalDecl::new(Ty::new_unit(self.tcx), span);
|
||||
let temp_place = Place::from(self.local_decls.push(local_decl));
|
||||
self.cfg.push_assign_unit(block, source_info, temp_place, self.tcx);
|
||||
}
|
||||
|
||||
fn leave_top_scope(&mut self, block: BasicBlock) -> BasicBlock {
|
||||
// If we are emitting a `drop` statement, we need to have the cached
|
||||
// diverge cleanup pads ready in case that drop panics.
|
||||
|
@ -252,15 +252,15 @@ struct TransformVisitor<'tcx> {
|
||||
|
||||
impl<'tcx> TransformVisitor<'tcx> {
|
||||
fn insert_none_ret_block(&self, body: &mut Body<'tcx>) -> BasicBlock {
|
||||
assert!(matches!(self.coroutine_kind, CoroutineKind::Gen(_)));
|
||||
|
||||
let block = BasicBlock::new(body.basic_blocks.len());
|
||||
let source_info = SourceInfo::outermost(body.span);
|
||||
let option_def_id = self.tcx.require_lang_item(LangItem::Option, None);
|
||||
|
||||
let statements = vec![Statement {
|
||||
kind: StatementKind::Assign(Box::new((
|
||||
Place::return_place(),
|
||||
let none_value = match self.coroutine_kind {
|
||||
CoroutineKind::Async(_) => span_bug!(body.span, "`Future`s are not fused inherently"),
|
||||
CoroutineKind::Coroutine => span_bug!(body.span, "`Coroutine`s cannot be fused"),
|
||||
// `gen` continues return `None`
|
||||
CoroutineKind::Gen(_) => {
|
||||
let option_def_id = self.tcx.require_lang_item(LangItem::Option, None);
|
||||
Rvalue::Aggregate(
|
||||
Box::new(AggregateKind::Adt(
|
||||
option_def_id,
|
||||
@ -270,8 +270,29 @@ impl<'tcx> TransformVisitor<'tcx> {
|
||||
None,
|
||||
)),
|
||||
IndexVec::new(),
|
||||
),
|
||||
))),
|
||||
)
|
||||
}
|
||||
// `async gen` continues to return `Poll::Ready(None)`
|
||||
CoroutineKind::AsyncGen(_) => {
|
||||
let ty::Adt(_poll_adt, args) = *self.old_yield_ty.kind() else { bug!() };
|
||||
let ty::Adt(_option_adt, args) = *args.type_at(0).kind() else { bug!() };
|
||||
let yield_ty = args.type_at(0);
|
||||
Rvalue::Use(Operand::Constant(Box::new(ConstOperand {
|
||||
span: source_info.span,
|
||||
const_: Const::Unevaluated(
|
||||
UnevaluatedConst::new(
|
||||
self.tcx.require_lang_item(LangItem::AsyncGenFinished, None),
|
||||
self.tcx.mk_args(&[yield_ty.into()]),
|
||||
),
|
||||
self.old_yield_ty,
|
||||
),
|
||||
user_ty: None,
|
||||
})))
|
||||
}
|
||||
};
|
||||
|
||||
let statements = vec![Statement {
|
||||
kind: StatementKind::Assign(Box::new((Place::return_place(), none_value))),
|
||||
source_info,
|
||||
}];
|
||||
|
||||
@ -1393,11 +1414,12 @@ fn create_coroutine_resume_function<'tcx>(
|
||||
|
||||
if can_return {
|
||||
let block = match coroutine_kind {
|
||||
// FIXME(gen_blocks): Should `async gen` yield `None` when resumed once again?
|
||||
CoroutineKind::Async(_) | CoroutineKind::AsyncGen(_) | CoroutineKind::Coroutine => {
|
||||
CoroutineKind::Async(_) | CoroutineKind::Coroutine => {
|
||||
insert_panic_block(tcx, body, ResumedAfterReturn(coroutine_kind))
|
||||
}
|
||||
CoroutineKind::Gen(_) => transform.insert_none_ret_block(body),
|
||||
CoroutineKind::AsyncGen(_) | CoroutineKind::Gen(_) => {
|
||||
transform.insert_none_ret_block(body)
|
||||
}
|
||||
};
|
||||
cases.insert(1, (RETURNED, block));
|
||||
}
|
||||
|
@ -319,29 +319,16 @@ impl<'a> CoverageSpansGenerator<'a> {
|
||||
}
|
||||
}
|
||||
|
||||
let prev = self.take_prev();
|
||||
debug!(" AT END, adding last prev={prev:?}");
|
||||
|
||||
// Drain any remaining dups into the output.
|
||||
for dup in self.pending_dups.drain(..) {
|
||||
debug!(" ...adding at least one pending dup={:?}", dup);
|
||||
self.refined_spans.push(dup);
|
||||
}
|
||||
|
||||
// Async functions wrap a closure that implements the body to be executed. The enclosing
|
||||
// function is called and returns an `impl Future` without initially executing any of the
|
||||
// body. To avoid showing the return from the enclosing function as a "covered" return from
|
||||
// the closure, the enclosing function's `TerminatorKind::Return`s `CoverageSpan` is
|
||||
// excluded. The closure's `Return` is the only one that will be counted. This provides
|
||||
// adequate coverage, and more intuitive counts. (Avoids double-counting the closing brace
|
||||
// of the function body.)
|
||||
let body_ends_with_closure = if let Some(last_covspan) = self.refined_spans.last() {
|
||||
last_covspan.is_closure && last_covspan.span.hi() == self.body_span.hi()
|
||||
} else {
|
||||
false
|
||||
};
|
||||
|
||||
if !body_ends_with_closure {
|
||||
// There is usually a final span remaining in `prev` after the loop ends,
|
||||
// so add it to the output as well.
|
||||
if let Some(prev) = self.some_prev.take() {
|
||||
debug!(" AT END, adding last prev={prev:?}");
|
||||
self.refined_spans.push(prev);
|
||||
}
|
||||
|
||||
@ -398,38 +385,36 @@ impl<'a> CoverageSpansGenerator<'a> {
|
||||
self.refined_spans.push(macro_name_cov);
|
||||
}
|
||||
|
||||
#[track_caller]
|
||||
fn curr(&self) -> &CoverageSpan {
|
||||
self.some_curr
|
||||
.as_ref()
|
||||
.unwrap_or_else(|| bug!("invalid attempt to unwrap a None some_curr"))
|
||||
self.some_curr.as_ref().unwrap_or_else(|| bug!("some_curr is None (curr)"))
|
||||
}
|
||||
|
||||
#[track_caller]
|
||||
fn curr_mut(&mut self) -> &mut CoverageSpan {
|
||||
self.some_curr
|
||||
.as_mut()
|
||||
.unwrap_or_else(|| bug!("invalid attempt to unwrap a None some_curr"))
|
||||
self.some_curr.as_mut().unwrap_or_else(|| bug!("some_curr is None (curr_mut)"))
|
||||
}
|
||||
|
||||
/// If called, then the next call to `next_coverage_span()` will *not* update `prev` with the
|
||||
/// `curr` coverage span.
|
||||
#[track_caller]
|
||||
fn take_curr(&mut self) -> CoverageSpan {
|
||||
self.some_curr.take().unwrap_or_else(|| bug!("invalid attempt to unwrap a None some_curr"))
|
||||
self.some_curr.take().unwrap_or_else(|| bug!("some_curr is None (take_curr)"))
|
||||
}
|
||||
|
||||
#[track_caller]
|
||||
fn prev(&self) -> &CoverageSpan {
|
||||
self.some_prev
|
||||
.as_ref()
|
||||
.unwrap_or_else(|| bug!("invalid attempt to unwrap a None some_prev"))
|
||||
self.some_prev.as_ref().unwrap_or_else(|| bug!("some_prev is None (prev)"))
|
||||
}
|
||||
|
||||
#[track_caller]
|
||||
fn prev_mut(&mut self) -> &mut CoverageSpan {
|
||||
self.some_prev
|
||||
.as_mut()
|
||||
.unwrap_or_else(|| bug!("invalid attempt to unwrap a None some_prev"))
|
||||
self.some_prev.as_mut().unwrap_or_else(|| bug!("some_prev is None (prev_mut)"))
|
||||
}
|
||||
|
||||
#[track_caller]
|
||||
fn take_prev(&mut self) -> CoverageSpan {
|
||||
self.some_prev.take().unwrap_or_else(|| bug!("invalid attempt to unwrap a None some_prev"))
|
||||
self.some_prev.take().unwrap_or_else(|| bug!("some_prev is None (take_prev)"))
|
||||
}
|
||||
|
||||
/// If there are `pending_dups` but `prev` is not a matching dup (`prev.span` doesn't match the
|
||||
|
@ -44,6 +44,16 @@ pub(super) fn mir_to_initial_sorted_coverage_spans(
|
||||
.then_with(|| Ord::cmp(&a.is_closure, &b.is_closure).reverse())
|
||||
});
|
||||
|
||||
// The desugaring of an async function includes a closure containing the
|
||||
// original function body, and a terminator that returns the `impl Future`.
|
||||
// That terminator will cause a confusing coverage count for the function's
|
||||
// closing brace, so discard everything after the body closure span.
|
||||
if let Some(body_closure_index) =
|
||||
initial_spans.iter().rposition(|covspan| covspan.is_closure && covspan.span == body_span)
|
||||
{
|
||||
initial_spans.truncate(body_closure_index + 1);
|
||||
}
|
||||
|
||||
initial_spans
|
||||
}
|
||||
|
||||
@ -92,13 +102,13 @@ fn is_closure(statement: &Statement<'_>) -> bool {
|
||||
/// If the MIR `Statement` has a span contributive to computing coverage spans,
|
||||
/// return it; otherwise return `None`.
|
||||
fn filtered_statement_span(statement: &Statement<'_>) -> Option<Span> {
|
||||
use mir::coverage::CoverageKind;
|
||||
|
||||
match statement.kind {
|
||||
// These statements have spans that are often outside the scope of the executed source code
|
||||
// for their parent `BasicBlock`.
|
||||
StatementKind::StorageLive(_)
|
||||
| StatementKind::StorageDead(_)
|
||||
// Coverage should not be encountered, but don't inject coverage coverage
|
||||
| StatementKind::Coverage(_)
|
||||
// Ignore `ConstEvalCounter`s
|
||||
| StatementKind::ConstEvalCounter
|
||||
// Ignore `Nop`s
|
||||
@ -122,9 +132,13 @@ fn filtered_statement_span(statement: &Statement<'_>) -> Option<Span> {
|
||||
// If and when the Issue is resolved, remove this special case match pattern:
|
||||
StatementKind::FakeRead(box (FakeReadCause::ForGuardBinding, _)) => None,
|
||||
|
||||
// Retain spans from all other statements
|
||||
// Retain spans from most other statements.
|
||||
StatementKind::FakeRead(box (_, _)) // Not including `ForGuardBinding`
|
||||
| StatementKind::Intrinsic(..)
|
||||
| StatementKind::Coverage(box mir::Coverage {
|
||||
// The purpose of `SpanMarker` is to be matched and accepted here.
|
||||
kind: CoverageKind::SpanMarker
|
||||
})
|
||||
| StatementKind::Assign(_)
|
||||
| StatementKind::SetDiscriminant { .. }
|
||||
| StatementKind::Deinit(..)
|
||||
@ -133,6 +147,11 @@ fn filtered_statement_span(statement: &Statement<'_>) -> Option<Span> {
|
||||
| StatementKind::AscribeUserType(_, _) => {
|
||||
Some(statement.source_info.span)
|
||||
}
|
||||
|
||||
StatementKind::Coverage(box mir::Coverage {
|
||||
// These coverage statements should not exist prior to coverage instrumentation.
|
||||
kind: CoverageKind::CounterIncrement { .. } | CoverageKind::ExpressionUsed { .. }
|
||||
}) => bug!("Unexpected coverage statement found during coverage instrumentation: {statement:?}"),
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -157,11 +157,7 @@ impl<'a, 'b, 'tcx> visit::Visitor<'a> for DefCollector<'a, 'b, 'tcx> {
|
||||
fn visit_fn(&mut self, fn_kind: FnKind<'a>, span: Span, _: NodeId) {
|
||||
if let FnKind::Fn(_, _, sig, _, generics, body) = fn_kind {
|
||||
match sig.header.coroutine_kind {
|
||||
Some(
|
||||
CoroutineKind::Async { closure_id, .. }
|
||||
| CoroutineKind::Gen { closure_id, .. }
|
||||
| CoroutineKind::AsyncGen { closure_id, .. },
|
||||
) => {
|
||||
Some(coroutine_kind) => {
|
||||
self.visit_generics(generics);
|
||||
|
||||
// For async functions, we need to create their inner defs inside of a
|
||||
@ -176,8 +172,12 @@ impl<'a, 'b, 'tcx> visit::Visitor<'a> for DefCollector<'a, 'b, 'tcx> {
|
||||
// then the closure_def will never be used, and we should avoid generating a
|
||||
// def-id for it.
|
||||
if let Some(body) = body {
|
||||
let closure_def =
|
||||
self.create_def(closure_id, kw::Empty, DefKind::Closure, span);
|
||||
let closure_def = self.create_def(
|
||||
coroutine_kind.closure_id(),
|
||||
kw::Empty,
|
||||
DefKind::Closure,
|
||||
span,
|
||||
);
|
||||
self.with_parent(closure_def, |this| this.visit_block(body));
|
||||
}
|
||||
return;
|
||||
@ -289,11 +289,12 @@ impl<'a, 'b, 'tcx> visit::Visitor<'a> for DefCollector<'a, 'b, 'tcx> {
|
||||
// we must create two defs.
|
||||
let closure_def = self.create_def(expr.id, kw::Empty, DefKind::Closure, expr.span);
|
||||
match closure.coroutine_kind {
|
||||
Some(
|
||||
CoroutineKind::Async { closure_id, .. }
|
||||
| CoroutineKind::Gen { closure_id, .. }
|
||||
| CoroutineKind::AsyncGen { closure_id, .. },
|
||||
) => self.create_def(closure_id, kw::Empty, DefKind::Closure, expr.span),
|
||||
Some(coroutine_kind) => self.create_def(
|
||||
coroutine_kind.closure_id(),
|
||||
kw::Empty,
|
||||
DefKind::Closure,
|
||||
expr.span,
|
||||
),
|
||||
None => closure_def,
|
||||
}
|
||||
}
|
||||
|
@ -3144,10 +3144,9 @@ impl<'tcx> TypeErrCtxtExt<'tcx> for TypeErrCtxt<'_, 'tcx> {
|
||||
let what = match self.tcx.coroutine_kind(coroutine_def_id) {
|
||||
None
|
||||
| Some(hir::CoroutineKind::Coroutine)
|
||||
| Some(hir::CoroutineKind::Gen(_))
|
||||
// FIXME(gen_blocks): This could be yield or await...
|
||||
| Some(hir::CoroutineKind::AsyncGen(_)) => "yield",
|
||||
| Some(hir::CoroutineKind::Gen(_)) => "yield",
|
||||
Some(hir::CoroutineKind::Async(..)) => "await",
|
||||
Some(hir::CoroutineKind::AsyncGen(_)) => "yield`/`await",
|
||||
};
|
||||
err.note(format!(
|
||||
"all values live across `{what}` must have a statically known size"
|
||||
|
@ -132,6 +132,7 @@ fn main() {
|
||||
check!(edition, &library_path);
|
||||
|
||||
check!(alphabetical, &src_path);
|
||||
check!(alphabetical, &tests_path);
|
||||
check!(alphabetical, &compiler_path);
|
||||
check!(alphabetical, &library_path);
|
||||
|
||||
|
39
tests/coverage/if_not.cov-map
Normal file
39
tests/coverage/if_not.cov-map
Normal file
@ -0,0 +1,39 @@
|
||||
Function name: if_not::if_not
|
||||
Raw bytes (86): 0x[01, 01, 10, 01, 05, 05, 02, 3f, 09, 05, 02, 09, 3a, 3f, 09, 05, 02, 37, 0d, 09, 3a, 3f, 09, 05, 02, 0d, 32, 37, 0d, 09, 3a, 3f, 09, 05, 02, 0a, 01, 04, 01, 03, 0d, 02, 04, 05, 02, 06, 05, 02, 06, 00, 07, 3f, 03, 09, 01, 0d, 3a, 02, 05, 02, 06, 09, 02, 06, 00, 07, 37, 03, 09, 01, 0d, 32, 02, 05, 02, 06, 0d, 02, 0c, 02, 06, 2f, 03, 01, 00, 02]
|
||||
Number of files: 1
|
||||
- file 0 => global file 1
|
||||
Number of expressions: 16
|
||||
- expression 0 operands: lhs = Counter(0), rhs = Counter(1)
|
||||
- expression 1 operands: lhs = Counter(1), rhs = Expression(0, Sub)
|
||||
- expression 2 operands: lhs = Expression(15, Add), rhs = Counter(2)
|
||||
- expression 3 operands: lhs = Counter(1), rhs = Expression(0, Sub)
|
||||
- expression 4 operands: lhs = Counter(2), rhs = Expression(14, Sub)
|
||||
- expression 5 operands: lhs = Expression(15, Add), rhs = Counter(2)
|
||||
- expression 6 operands: lhs = Counter(1), rhs = Expression(0, Sub)
|
||||
- expression 7 operands: lhs = Expression(13, Add), rhs = Counter(3)
|
||||
- expression 8 operands: lhs = Counter(2), rhs = Expression(14, Sub)
|
||||
- expression 9 operands: lhs = Expression(15, Add), rhs = Counter(2)
|
||||
- expression 10 operands: lhs = Counter(1), rhs = Expression(0, Sub)
|
||||
- expression 11 operands: lhs = Counter(3), rhs = Expression(12, Sub)
|
||||
- expression 12 operands: lhs = Expression(13, Add), rhs = Counter(3)
|
||||
- expression 13 operands: lhs = Counter(2), rhs = Expression(14, Sub)
|
||||
- expression 14 operands: lhs = Expression(15, Add), rhs = Counter(2)
|
||||
- expression 15 operands: lhs = Counter(1), rhs = Expression(0, Sub)
|
||||
Number of file 0 mappings: 10
|
||||
- Code(Counter(0)) at (prev + 4, 1) to (start + 3, 13)
|
||||
- Code(Expression(0, Sub)) at (prev + 4, 5) to (start + 2, 6)
|
||||
= (c0 - c1)
|
||||
- Code(Counter(1)) at (prev + 2, 6) to (start + 0, 7)
|
||||
- Code(Expression(15, Add)) at (prev + 3, 9) to (start + 1, 13)
|
||||
= (c1 + (c0 - c1))
|
||||
- Code(Expression(14, Sub)) at (prev + 2, 5) to (start + 2, 6)
|
||||
= ((c1 + (c0 - c1)) - c2)
|
||||
- Code(Counter(2)) at (prev + 2, 6) to (start + 0, 7)
|
||||
- Code(Expression(13, Add)) at (prev + 3, 9) to (start + 1, 13)
|
||||
= (c2 + ((c1 + (c0 - c1)) - c2))
|
||||
- Code(Expression(12, Sub)) at (prev + 2, 5) to (start + 2, 6)
|
||||
= ((c2 + ((c1 + (c0 - c1)) - c2)) - c3)
|
||||
- Code(Counter(3)) at (prev + 2, 12) to (start + 2, 6)
|
||||
- Code(Expression(11, Add)) at (prev + 3, 1) to (start + 0, 2)
|
||||
= (c3 + ((c2 + ((c1 + (c0 - c1)) - c2)) - c3))
|
||||
|
38
tests/coverage/if_not.coverage
Normal file
38
tests/coverage/if_not.coverage
Normal file
@ -0,0 +1,38 @@
|
||||
LL| |#![feature(coverage_attribute)]
|
||||
LL| |// edition: 2021
|
||||
LL| |
|
||||
LL| 12|fn if_not(cond: bool) {
|
||||
LL| 12| if
|
||||
LL| 12| !
|
||||
LL| 12| cond
|
||||
LL| 4| {
|
||||
LL| 4| println!("cond was false");
|
||||
LL| 8| }
|
||||
LL| |
|
||||
LL| | if
|
||||
LL| 12| !
|
||||
LL| 12| cond
|
||||
LL| 4| {
|
||||
LL| 4| println!("cond was false");
|
||||
LL| 8| }
|
||||
LL| |
|
||||
LL| | if
|
||||
LL| 12| !
|
||||
LL| 12| cond
|
||||
LL| 4| {
|
||||
LL| 4| println!("cond was false");
|
||||
LL| 8| } else {
|
||||
LL| 8| println!("cond was true");
|
||||
LL| 8| }
|
||||
LL| 12|}
|
||||
LL| |
|
||||
LL| |#[coverage(off)]
|
||||
LL| |fn main() {
|
||||
LL| | for _ in 0..8 {
|
||||
LL| | if_not(std::hint::black_box(true));
|
||||
LL| | }
|
||||
LL| | for _ in 0..4 {
|
||||
LL| | if_not(std::hint::black_box(false));
|
||||
LL| | }
|
||||
LL| |}
|
||||
|
37
tests/coverage/if_not.rs
Normal file
37
tests/coverage/if_not.rs
Normal file
@ -0,0 +1,37 @@
|
||||
#![feature(coverage_attribute)]
|
||||
// edition: 2021
|
||||
|
||||
fn if_not(cond: bool) {
|
||||
if
|
||||
!
|
||||
cond
|
||||
{
|
||||
println!("cond was false");
|
||||
}
|
||||
|
||||
if
|
||||
!
|
||||
cond
|
||||
{
|
||||
println!("cond was false");
|
||||
}
|
||||
|
||||
if
|
||||
!
|
||||
cond
|
||||
{
|
||||
println!("cond was false");
|
||||
} else {
|
||||
println!("cond was true");
|
||||
}
|
||||
}
|
||||
|
||||
#[coverage(off)]
|
||||
fn main() {
|
||||
for _ in 0..8 {
|
||||
if_not(std::hint::black_box(true));
|
||||
}
|
||||
for _ in 0..4 {
|
||||
if_not(std::hint::black_box(false));
|
||||
}
|
||||
}
|
@ -1,5 +1,5 @@
|
||||
Function name: lazy_boolean::main
|
||||
Raw bytes (636): 0x[01, 01, a4, 01, 01, 05, 09, 8a, 05, 8f, 05, 09, 05, 02, 05, 02, 8f, 05, 09, 05, 02, 0d, 82, 05, 87, 05, 0d, 09, 8a, 05, 8f, 05, 09, 05, 02, 09, 8a, 05, 8f, 05, 09, 05, 02, 87, 05, 0d, 09, 8a, 05, 8f, 05, 09, 05, 02, 11, fa, 04, ff, 04, 11, 0d, 82, 05, 87, 05, 0d, 09, 8a, 05, 8f, 05, 09, 05, 02, 0d, 82, 05, 87, 05, 0d, 09, 8a, 05, 8f, 05, 09, 05, 02, 15, f2, 04, f7, 04, 15, 11, fa, 04, ff, 04, 11, 0d, 82, 05, 87, 05, 0d, 09, 8a, 05, 8f, 05, 09, 05, 02, 11, fa, 04, ff, 04, 11, 0d, 82, 05, 87, 05, 0d, 09, 8a, 05, 8f, 05, 09, 05, 02, 15, f2, 04, f7, 04, 15, 11, fa, 04, ff, 04, 11, 0d, 82, 05, 87, 05, 0d, 09, 8a, 05, 8f, 05, 09, 05, 02, ef, 04, 19, 15, f2, 04, f7, 04, 15, 11, fa, 04, ff, 04, 11, 0d, 82, 05, 87, 05, 0d, 09, 8a, 05, 8f, 05, 09, 05, 02, 19, ea, 04, ef, 04, 19, 15, f2, 04, f7, 04, 15, 11, fa, 04, ff, 04, 11, 0d, 82, 05, 87, 05, 0d, 09, 8a, 05, 8f, 05, 09, 05, 02, e7, 04, 1d, 19, ea, 04, ef, 04, 19, 15, f2, 04, f7, 04, 15, 11, fa, 04, ff, 04, 11, 0d, 82, 05, 87, 05, 0d, 09, 8a, 05, 8f, 05, 09, 05, 02, 1d, e2, 04, e7, 04, 1d, 19, ea, 04, ef, 04, 19, 15, f2, 04, f7, 04, 15, 11, fa, 04, ff, 04, 11, 0d, 82, 05, 87, 05, 0d, 09, 8a, 05, 8f, 05, 09, 05, 02, df, 04, 21, 1d, e2, 04, e7, 04, 1d, 19, ea, 04, ef, 04, 19, 15, f2, 04, f7, 04, 15, 11, fa, 04, ff, 04, 11, 0d, 82, 05, 87, 05, 0d, 09, 8a, 05, 8f, 05, 09, 05, 02, 21, da, 04, df, 04, 21, 1d, e2, 04, e7, 04, 1d, 19, ea, 04, ef, 04, 19, 15, f2, 04, f7, 04, 15, 11, fa, 04, ff, 04, 11, 0d, 82, 05, 87, 05, 0d, 09, 8a, 05, 8f, 05, 09, 05, 02, d7, 04, 25, 21, da, 04, df, 04, 21, 1d, e2, 04, e7, 04, 1d, 19, ea, 04, ef, 04, 19, 15, f2, 04, f7, 04, 15, 11, fa, 04, ff, 04, 11, 0d, 82, 05, 87, 05, 0d, 09, 8a, 05, 8f, 05, 09, 05, 02, 25, d2, 04, d7, 04, 25, 21, da, 04, df, 04, 21, 1d, e2, 04, e7, 04, 1d, 19, ea, 04, ef, 04, 19, 15, f2, 04, f7, 04, 15, 11, fa, 04, ff, 04, 11, 0d, 82, 05, 87, 05, 0d, 09, 8a, 05, 8f, 05, 09, 05, 02, 1c, 01, 03, 01, 07, 0f, 05, 07, 10, 04, 06, 02, 04, 06, 00, 07, 87, 05, 02, 09, 00, 11, 8f, 05, 02, 0d, 00, 12, 8a, 05, 02, 0d, 00, 12, ff, 04, 03, 09, 00, 11, 87, 05, 02, 0d, 00, 12, 82, 05, 02, 0d, 00, 12, f7, 04, 02, 09, 00, 11, ff, 04, 00, 14, 00, 19, 11, 00, 1d, 00, 22, ef, 04, 01, 09, 00, 11, f7, 04, 00, 14, 00, 19, 15, 00, 1d, 00, 22, ef, 04, 04, 09, 00, 10, ea, 04, 01, 05, 03, 06, 19, 03, 06, 00, 07, e7, 04, 03, 09, 00, 10, 1d, 01, 05, 03, 06, e2, 04, 05, 05, 03, 06, df, 04, 05, 09, 00, 10, da, 04, 00, 11, 02, 06, 21, 02, 06, 00, 07, d7, 04, 02, 08, 00, 0f, 25, 00, 10, 02, 06, d2, 04, 02, 0c, 02, 06, cf, 04, 03, 01, 00, 02]
|
||||
Raw bytes (636): 0x[01, 01, a4, 01, 01, 05, 09, 8a, 05, 8f, 05, 09, 05, 02, 05, 02, 8f, 05, 09, 05, 02, 0d, 82, 05, 87, 05, 0d, 09, 8a, 05, 8f, 05, 09, 05, 02, 09, 8a, 05, 8f, 05, 09, 05, 02, 87, 05, 0d, 09, 8a, 05, 8f, 05, 09, 05, 02, 11, fa, 04, ff, 04, 11, 0d, 82, 05, 87, 05, 0d, 09, 8a, 05, 8f, 05, 09, 05, 02, 0d, 82, 05, 87, 05, 0d, 09, 8a, 05, 8f, 05, 09, 05, 02, 15, f2, 04, f7, 04, 15, 11, fa, 04, ff, 04, 11, 0d, 82, 05, 87, 05, 0d, 09, 8a, 05, 8f, 05, 09, 05, 02, 11, fa, 04, ff, 04, 11, 0d, 82, 05, 87, 05, 0d, 09, 8a, 05, 8f, 05, 09, 05, 02, 15, f2, 04, f7, 04, 15, 11, fa, 04, ff, 04, 11, 0d, 82, 05, 87, 05, 0d, 09, 8a, 05, 8f, 05, 09, 05, 02, ef, 04, 19, 15, f2, 04, f7, 04, 15, 11, fa, 04, ff, 04, 11, 0d, 82, 05, 87, 05, 0d, 09, 8a, 05, 8f, 05, 09, 05, 02, 19, ea, 04, ef, 04, 19, 15, f2, 04, f7, 04, 15, 11, fa, 04, ff, 04, 11, 0d, 82, 05, 87, 05, 0d, 09, 8a, 05, 8f, 05, 09, 05, 02, e7, 04, 1d, 19, ea, 04, ef, 04, 19, 15, f2, 04, f7, 04, 15, 11, fa, 04, ff, 04, 11, 0d, 82, 05, 87, 05, 0d, 09, 8a, 05, 8f, 05, 09, 05, 02, 1d, e2, 04, e7, 04, 1d, 19, ea, 04, ef, 04, 19, 15, f2, 04, f7, 04, 15, 11, fa, 04, ff, 04, 11, 0d, 82, 05, 87, 05, 0d, 09, 8a, 05, 8f, 05, 09, 05, 02, df, 04, 21, 1d, e2, 04, e7, 04, 1d, 19, ea, 04, ef, 04, 19, 15, f2, 04, f7, 04, 15, 11, fa, 04, ff, 04, 11, 0d, 82, 05, 87, 05, 0d, 09, 8a, 05, 8f, 05, 09, 05, 02, 21, da, 04, df, 04, 21, 1d, e2, 04, e7, 04, 1d, 19, ea, 04, ef, 04, 19, 15, f2, 04, f7, 04, 15, 11, fa, 04, ff, 04, 11, 0d, 82, 05, 87, 05, 0d, 09, 8a, 05, 8f, 05, 09, 05, 02, d7, 04, 25, 21, da, 04, df, 04, 21, 1d, e2, 04, e7, 04, 1d, 19, ea, 04, ef, 04, 19, 15, f2, 04, f7, 04, 15, 11, fa, 04, ff, 04, 11, 0d, 82, 05, 87, 05, 0d, 09, 8a, 05, 8f, 05, 09, 05, 02, 25, d2, 04, d7, 04, 25, 21, da, 04, df, 04, 21, 1d, e2, 04, e7, 04, 1d, 19, ea, 04, ef, 04, 19, 15, f2, 04, f7, 04, 15, 11, fa, 04, ff, 04, 11, 0d, 82, 05, 87, 05, 0d, 09, 8a, 05, 8f, 05, 09, 05, 02, 1c, 01, 03, 01, 07, 0f, 05, 07, 10, 04, 06, 02, 04, 06, 00, 07, 87, 05, 02, 09, 00, 11, 8f, 05, 02, 0d, 00, 12, 8a, 05, 02, 0d, 00, 12, ff, 04, 03, 09, 00, 11, 87, 05, 02, 0d, 00, 12, 82, 05, 02, 0d, 00, 12, f7, 04, 02, 09, 00, 11, ff, 04, 00, 14, 00, 19, 11, 00, 1d, 00, 22, ef, 04, 01, 09, 00, 11, f7, 04, 00, 14, 00, 19, 15, 00, 1d, 00, 22, ef, 04, 03, 09, 01, 10, ea, 04, 02, 05, 03, 06, 19, 03, 06, 00, 07, e7, 04, 03, 09, 00, 10, 1d, 01, 05, 03, 06, e2, 04, 05, 05, 03, 06, df, 04, 05, 08, 00, 10, da, 04, 00, 11, 02, 06, 21, 02, 06, 00, 07, d7, 04, 02, 08, 00, 0f, 25, 00, 10, 02, 06, d2, 04, 02, 0c, 02, 06, cf, 04, 03, 01, 00, 02]
|
||||
Number of files: 1
|
||||
- file 0 => global file 1
|
||||
Number of expressions: 164
|
||||
@ -194,9 +194,9 @@ Number of file 0 mappings: 28
|
||||
- Code(Expression(157, Add)) at (prev + 0, 20) to (start + 0, 25)
|
||||
= (c4 + ((c3 + ((c2 + ((c1 + (c0 - c1)) - c2)) - c3)) - c4))
|
||||
- Code(Counter(5)) at (prev + 0, 29) to (start + 0, 34)
|
||||
- Code(Expression(155, Add)) at (prev + 4, 9) to (start + 0, 16)
|
||||
- Code(Expression(155, Add)) at (prev + 3, 9) to (start + 1, 16)
|
||||
= (c5 + ((c4 + ((c3 + ((c2 + ((c1 + (c0 - c1)) - c2)) - c3)) - c4)) - c5))
|
||||
- Code(Expression(154, Sub)) at (prev + 1, 5) to (start + 3, 6)
|
||||
- Code(Expression(154, Sub)) at (prev + 2, 5) to (start + 3, 6)
|
||||
= ((c5 + ((c4 + ((c3 + ((c2 + ((c1 + (c0 - c1)) - c2)) - c3)) - c4)) - c5)) - c6)
|
||||
- Code(Counter(6)) at (prev + 3, 6) to (start + 0, 7)
|
||||
- Code(Expression(153, Add)) at (prev + 3, 9) to (start + 0, 16)
|
||||
@ -204,7 +204,7 @@ Number of file 0 mappings: 28
|
||||
- Code(Counter(7)) at (prev + 1, 5) to (start + 3, 6)
|
||||
- Code(Expression(152, Sub)) at (prev + 5, 5) to (start + 3, 6)
|
||||
= ((c6 + ((c5 + ((c4 + ((c3 + ((c2 + ((c1 + (c0 - c1)) - c2)) - c3)) - c4)) - c5)) - c6)) - c7)
|
||||
- Code(Expression(151, Add)) at (prev + 5, 9) to (start + 0, 16)
|
||||
- Code(Expression(151, Add)) at (prev + 5, 8) to (start + 0, 16)
|
||||
= (c7 + ((c6 + ((c5 + ((c4 + ((c3 + ((c2 + ((c1 + (c0 - c1)) - c2)) - c3)) - c4)) - c5)) - c6)) - c7))
|
||||
- Code(Expression(150, Sub)) at (prev + 0, 17) to (start + 2, 6)
|
||||
= ((c7 + ((c6 + ((c5 + ((c4 + ((c3 + ((c2 + ((c1 + (c0 - c1)) - c2)) - c3)) - c4)) - c5)) - c6)) - c7)) - c8)
|
||||
|
@ -32,7 +32,7 @@
|
||||
^0
|
||||
LL| |
|
||||
LL| | if
|
||||
LL| | !
|
||||
LL| 1| !
|
||||
LL| 1| is_true
|
||||
LL| 0| {
|
||||
LL| 0| a = 2
|
||||
|
8
tests/coverage/no_spans.cov-map
Normal file
8
tests/coverage/no_spans.cov-map
Normal file
@ -0,0 +1,8 @@
|
||||
Function name: no_spans::affected_function::{closure#0}
|
||||
Raw bytes (9): 0x[01, 01, 00, 01, 01, 1b, 0c, 00, 0e]
|
||||
Number of files: 1
|
||||
- file 0 => global file 1
|
||||
Number of expressions: 0
|
||||
Number of file 0 mappings: 1
|
||||
- Code(Counter(0)) at (prev + 27, 12) to (start + 0, 14)
|
||||
|
30
tests/coverage/no_spans.coverage
Normal file
30
tests/coverage/no_spans.coverage
Normal file
@ -0,0 +1,30 @@
|
||||
LL| |#![feature(coverage_attribute)]
|
||||
LL| |// edition: 2021
|
||||
LL| |
|
||||
LL| |// If the span extractor can't find any relevant spans for a function, the
|
||||
LL| |// refinement loop will terminate with nothing in its `prev` slot. If the
|
||||
LL| |// subsequent code tries to unwrap `prev`, it will panic.
|
||||
LL| |//
|
||||
LL| |// This scenario became more likely after #118525 started discarding spans that
|
||||
LL| |// can't be un-expanded back to within the function body.
|
||||
LL| |//
|
||||
LL| |// Regression test for "invalid attempt to unwrap a None some_prev", as seen
|
||||
LL| |// in issues such as #118643 and #118662.
|
||||
LL| |
|
||||
LL| |#[coverage(off)]
|
||||
LL| |fn main() {
|
||||
LL| | affected_function()();
|
||||
LL| |}
|
||||
LL| |
|
||||
LL| |macro_rules! macro_that_defines_a_function {
|
||||
LL| | (fn $name:ident () $body:tt) => {
|
||||
LL| | fn $name () -> impl Fn() $body
|
||||
LL| | }
|
||||
LL| |}
|
||||
LL| |
|
||||
LL| |macro_that_defines_a_function! {
|
||||
LL| | fn affected_function() {
|
||||
LL| 1| || ()
|
||||
LL| | }
|
||||
LL| |}
|
||||
|
29
tests/coverage/no_spans.rs
Normal file
29
tests/coverage/no_spans.rs
Normal file
@ -0,0 +1,29 @@
|
||||
#![feature(coverage_attribute)]
|
||||
// edition: 2021
|
||||
|
||||
// If the span extractor can't find any relevant spans for a function, the
|
||||
// refinement loop will terminate with nothing in its `prev` slot. If the
|
||||
// subsequent code tries to unwrap `prev`, it will panic.
|
||||
//
|
||||
// This scenario became more likely after #118525 started discarding spans that
|
||||
// can't be un-expanded back to within the function body.
|
||||
//
|
||||
// Regression test for "invalid attempt to unwrap a None some_prev", as seen
|
||||
// in issues such as #118643 and #118662.
|
||||
|
||||
#[coverage(off)]
|
||||
fn main() {
|
||||
affected_function()();
|
||||
}
|
||||
|
||||
macro_rules! macro_that_defines_a_function {
|
||||
(fn $name:ident () $body:tt) => {
|
||||
fn $name () -> impl Fn() $body
|
||||
}
|
||||
}
|
||||
|
||||
macro_that_defines_a_function! {
|
||||
fn affected_function() {
|
||||
|| ()
|
||||
}
|
||||
}
|
@ -2,9 +2,9 @@
|
||||
// revisions: riscv32 riscv64
|
||||
//
|
||||
// [riscv32] needs-llvm-components: riscv
|
||||
// [riscv32] compile-flags: --target=riscv32i-unknown-none-elf -C target-feature=-unaligned-scalar-mem --crate-type=rlib
|
||||
// [riscv32] compile-flags: --target=riscv32i-unknown-none-elf -C target-feature=-fast-unaligned-access --crate-type=rlib
|
||||
// [riscv64] needs-llvm-components: riscv
|
||||
// [riscv64] compile-flags: --target=riscv64gc-unknown-none-elf -C target-feature=-unaligned-scalar-mem --crate-type=rlib
|
||||
// [riscv64] compile-flags: --target=riscv64gc-unknown-none-elf -C target-feature=-fast-unaligned-access --crate-type=rlib
|
||||
#![no_core]
|
||||
#![feature(
|
||||
no_core,
|
||||
|
@ -33,6 +33,10 @@ async fn async_main() {
|
||||
assert_eq!(iter.as_mut().next().await, Some(2));
|
||||
assert_eq!(iter.as_mut().next().await, Some(3));
|
||||
assert_eq!(iter.as_mut().next().await, None);
|
||||
|
||||
// Test that the iterator is fused and does not panic
|
||||
assert_eq!(iter.as_mut().next().await, None);
|
||||
assert_eq!(iter.as_mut().next().await, None);
|
||||
}
|
||||
|
||||
// ------------------------------------------------------------------------- //
|
||||
|
18
tests/ui/implied-bounds/auxiliary/bevy_ecs.rs
Normal file
18
tests/ui/implied-bounds/auxiliary/bevy_ecs.rs
Normal file
@ -0,0 +1,18 @@
|
||||
// Related to Bevy regression #118553
|
||||
|
||||
pub trait WorldQuery {}
|
||||
impl WorldQuery for &u8 {}
|
||||
|
||||
pub struct Query<Q: WorldQuery>(Q);
|
||||
|
||||
pub trait SystemParam {
|
||||
type State;
|
||||
}
|
||||
impl<Q: WorldQuery + 'static> SystemParam for Query<Q> {
|
||||
type State = ();
|
||||
// `Q: 'static` is required because we need the TypeId of Q ...
|
||||
}
|
||||
|
||||
pub struct ParamSet<T: SystemParam>(T)
|
||||
where
|
||||
T::State: Sized;
|
11
tests/ui/implied-bounds/bevy_world_query.rs
Normal file
11
tests/ui/implied-bounds/bevy_world_query.rs
Normal file
@ -0,0 +1,11 @@
|
||||
// aux-crate:bevy_ecs=bevy_ecs.rs
|
||||
// check-pass
|
||||
// Related to Bevy regression #118553
|
||||
|
||||
extern crate bevy_ecs;
|
||||
|
||||
use bevy_ecs::*;
|
||||
|
||||
fn handler<'a>(_: ParamSet<Query<&'a u8>>) {}
|
||||
|
||||
fn main() {}
|
24
tests/ui/implied-bounds/from-trait-impl.rs
Normal file
24
tests/ui/implied-bounds/from-trait-impl.rs
Normal file
@ -0,0 +1,24 @@
|
||||
// check-pass
|
||||
// known-bug: #109628
|
||||
|
||||
trait Trait {
|
||||
type Assoc;
|
||||
}
|
||||
|
||||
impl<X: 'static> Trait for (X,) {
|
||||
type Assoc = ();
|
||||
}
|
||||
|
||||
struct Foo<T: Trait>(T)
|
||||
where
|
||||
T::Assoc: Clone; // any predicate using `T::Assoc` works here
|
||||
|
||||
fn func1(foo: Foo<(&str,)>) {
|
||||
let _: &'static str = foo.0.0;
|
||||
}
|
||||
|
||||
trait TestTrait {}
|
||||
|
||||
impl<X> TestTrait for [Foo<(X,)>; 1] {}
|
||||
|
||||
fn main() {}
|
31
tests/ui/implied-bounds/gluon_salsa.rs
Normal file
31
tests/ui/implied-bounds/gluon_salsa.rs
Normal file
@ -0,0 +1,31 @@
|
||||
// check-pass
|
||||
// Related to Bevy regression #118553
|
||||
|
||||
pub trait QueryBase {
|
||||
type Db;
|
||||
}
|
||||
|
||||
pub trait AsyncQueryFunction<'f>: // 'f is important
|
||||
QueryBase<Db = <Self as AsyncQueryFunction<'f>>::SendDb> // bound is important
|
||||
{
|
||||
type SendDb;
|
||||
}
|
||||
|
||||
pub struct QueryTable<'me, Q, DB> {
|
||||
_q: Option<Q>,
|
||||
_db: Option<DB>,
|
||||
_marker: Option<&'me ()>,
|
||||
}
|
||||
|
||||
impl<'me, Q> QueryTable<'me, Q, <Q as QueryBase>::Db>
|
||||
// projection is important
|
||||
// ^^^ removing 'me (and in QueryTable) gives a different error
|
||||
where
|
||||
Q: for<'f> AsyncQueryFunction<'f>,
|
||||
{
|
||||
pub fn get_async<'a>(&'a mut self) {
|
||||
panic!();
|
||||
}
|
||||
}
|
||||
|
||||
fn main() {}
|
@ -1,11 +1,11 @@
|
||||
error[E0759]: `fn` parameter has lifetime `'x` but it needs to satisfy a `'static` lifetime requirement
|
||||
--> $DIR/normalization-nested.rs:35:20
|
||||
--> $DIR/normalization-nested.rs:35:28
|
||||
|
|
||||
LL | pub fn test<'x>(_: Map<Vec<&'x ()>>, s: &'x str) -> &'static str {
|
||||
| ^^^^^^^^^^^^^^^^
|
||||
| |
|
||||
| this data with lifetime `'x`...
|
||||
| ...is used and required to live as long as `'static` here
|
||||
LL | pub fn test_wfcheck<'x>(_: Map<Vec<&'x ()>>) {}
|
||||
| ^^^^^^^^^^^^^^^^
|
||||
| |
|
||||
| this data with lifetime `'x`...
|
||||
| ...is used and required to live as long as `'static` here
|
||||
|
|
||||
note: `'static` lifetime requirement introduced by this bound
|
||||
--> $DIR/normalization-nested.rs:33:14
|
||||
@ -13,6 +13,21 @@ note: `'static` lifetime requirement introduced by this bound
|
||||
LL | I::Item: 'static;
|
||||
| ^^^^^^^
|
||||
|
||||
error: aborting due to 1 previous error
|
||||
error[E0759]: `fn` parameter has lifetime `'x` but it needs to satisfy a `'static` lifetime requirement
|
||||
--> $DIR/normalization-nested.rs:37:29
|
||||
|
|
||||
LL | pub fn test_borrowck<'x>(_: Map<Vec<&'x ()>>, s: &'x str) -> &'static str {
|
||||
| ^^^^^^^^^^^^^^^^
|
||||
| |
|
||||
| this data with lifetime `'x`...
|
||||
| ...is used and required to live as long as `'static` here
|
||||
|
|
||||
note: `'static` lifetime requirement introduced by this bound
|
||||
--> $DIR/normalization-nested.rs:33:14
|
||||
|
|
||||
LL | I::Item: 'static;
|
||||
| ^^^^^^^
|
||||
|
||||
error: aborting due to 2 previous errors
|
||||
|
||||
For more information about this error, try `rustc --explain E0759`.
|
||||
|
@ -32,7 +32,9 @@ where
|
||||
I: Iter,
|
||||
I::Item: 'static;
|
||||
|
||||
pub fn test<'x>(_: Map<Vec<&'x ()>>, s: &'x str) -> &'static str {
|
||||
pub fn test_wfcheck<'x>(_: Map<Vec<&'x ()>>) {}
|
||||
|
||||
pub fn test_borrowck<'x>(_: Map<Vec<&'x ()>>, s: &'x str) -> &'static str {
|
||||
s
|
||||
}
|
||||
|
||||
|
@ -0,0 +1,28 @@
|
||||
error: lifetime may not live long enough
|
||||
--> $DIR/normalization-preserve-equality.rs:24:1
|
||||
|
|
||||
LL | fn test_borrowck<'a, 'b>(_: (<Equal<'a, 'b> as Trait>::Ty, Equal<'a, 'b>)) {
|
||||
| ^^^^^^^^^^^^^^^^^--^^--^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
|
||||
| | | |
|
||||
| | | lifetime `'b` defined here
|
||||
| | lifetime `'a` defined here
|
||||
| requires that `'a` must outlive `'b`
|
||||
|
|
||||
= help: consider adding the following bound: `'a: 'b`
|
||||
|
||||
error: lifetime may not live long enough
|
||||
--> $DIR/normalization-preserve-equality.rs:24:1
|
||||
|
|
||||
LL | fn test_borrowck<'a, 'b>(_: (<Equal<'a, 'b> as Trait>::Ty, Equal<'a, 'b>)) {
|
||||
| ^^^^^^^^^^^^^^^^^--^^--^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
|
||||
| | | |
|
||||
| | | lifetime `'b` defined here
|
||||
| | lifetime `'a` defined here
|
||||
| requires that `'b` must outlive `'a`
|
||||
|
|
||||
= help: consider adding the following bound: `'b: 'a`
|
||||
|
||||
help: `'a` and `'b` must be the same: replace one with the other
|
||||
|
||||
error: aborting due to 2 previous errors
|
||||
|
28
tests/ui/implied-bounds/normalization-preserve-equality.rs
Normal file
28
tests/ui/implied-bounds/normalization-preserve-equality.rs
Normal file
@ -0,0 +1,28 @@
|
||||
// Both revisions should pass. `borrowck` revision is a bug!
|
||||
//
|
||||
// revisions: wfcheck borrowck
|
||||
// [wfcheck] check-pass
|
||||
// [borrowck] check-fail
|
||||
// [borrowck] known-bug: #106569
|
||||
|
||||
struct Equal<'a, 'b>(&'a &'b (), &'b &'a ()); // implies 'a == 'b
|
||||
|
||||
trait Trait {
|
||||
type Ty;
|
||||
}
|
||||
|
||||
impl<'x> Trait for Equal<'x, 'x> {
|
||||
type Ty = ();
|
||||
}
|
||||
|
||||
trait WfCheckTrait {}
|
||||
|
||||
#[cfg(wfcheck)]
|
||||
impl<'a, 'b> WfCheckTrait for (<Equal<'a, 'b> as Trait>::Ty, Equal<'a, 'b>) {}
|
||||
|
||||
#[cfg(borrowck)]
|
||||
fn test_borrowck<'a, 'b>(_: (<Equal<'a, 'b> as Trait>::Ty, Equal<'a, 'b>)) {
|
||||
let _ = None::<Equal<'a, 'b>>;
|
||||
}
|
||||
|
||||
fn main() {}
|
37
tests/ui/implied-bounds/sod_service_chain.rs
Normal file
37
tests/ui/implied-bounds/sod_service_chain.rs
Normal file
@ -0,0 +1,37 @@
|
||||
// check-pass
|
||||
// Related to crater regressions on #118553
|
||||
|
||||
pub trait Debug {}
|
||||
|
||||
pub trait Service {
|
||||
type Input;
|
||||
type Output;
|
||||
type Error;
|
||||
}
|
||||
|
||||
pub struct ServiceChain<P, S> {
|
||||
prev: P,
|
||||
service: S,
|
||||
}
|
||||
impl<P: Service, S: Service<Input = P::Output>> Service for ServiceChain<P, S>
|
||||
where
|
||||
P::Error: 'static,
|
||||
S::Error: 'static,
|
||||
{
|
||||
type Input = P::Input;
|
||||
type Output = S::Output;
|
||||
type Error = ();
|
||||
}
|
||||
|
||||
pub struct ServiceChainBuilder<P: Service, S: Service<Input = P::Output>> {
|
||||
chain: ServiceChain<P, S>,
|
||||
}
|
||||
impl<P: Service, S: Service<Input = P::Output>> ServiceChainBuilder<P, S> {
|
||||
pub fn next<NS: Service<Input = S::Output>>(
|
||||
self,
|
||||
) -> ServiceChainBuilder<ServiceChain<P, S>, NS> {
|
||||
panic!();
|
||||
}
|
||||
}
|
||||
|
||||
fn main() {}
|
Loading…
Reference in New Issue
Block a user