Auto merge of #116820 - GuillaumeGomez:rollup-l54ri5q, r=GuillaumeGomez

Rollup of 6 pull requests

Successful merges:

 - #116754 (coverage: Several small cleanups in `spans`)
 - #116798 (Improve display of parallel jobs in rustdoc-gui tester script)
 - #116800 (Fix implied outlives check for GAT in RPITIT)
 - #116805 (Make `rustc_onunimplemented` export path agnostic)
 - #116808 (Add myself to smir triage)
 - #116811 (Preserve unicode escapes in format string literals when pretty-printing AST)

r? `@ghost`
`@rustbot` modify labels: rollup
This commit is contained in:
bors 2023-10-16 23:01:20 +00:00
commit 64338796ab
16 changed files with 275 additions and 230 deletions

View File

@ -684,8 +684,8 @@ pub fn reconstruct_format_args_template_string(pieces: &[FormatArgsPiece]) -> St
for piece in pieces { for piece in pieces {
match piece { match piece {
FormatArgsPiece::Literal(s) => { FormatArgsPiece::Literal(s) => {
for c in s.as_str().escape_debug() { for c in s.as_str().chars() {
template.push(c); template.extend(c.escape_debug());
if let '{' | '}' = c { if let '{' | '}' = c {
template.push(c); template.push(c);
} }

View File

@ -314,9 +314,10 @@ fn check_trait_item(tcx: TyCtxt<'_>, trait_item: &hir::TraitItem<'_>) {
/// fn into_iter<'a>(&'a self) -> Self::Iter<'a>; /// fn into_iter<'a>(&'a self) -> Self::Iter<'a>;
/// } /// }
/// ``` /// ```
fn check_gat_where_clauses(tcx: TyCtxt<'_>, associated_items: &[hir::TraitItemRef]) { fn check_gat_where_clauses(tcx: TyCtxt<'_>, trait_def_id: LocalDefId) {
// Associates every GAT's def_id to a list of possibly missing bounds detected by this lint. // Associates every GAT's def_id to a list of possibly missing bounds detected by this lint.
let mut required_bounds_by_item = FxHashMap::default(); let mut required_bounds_by_item = FxHashMap::default();
let associated_items = tcx.associated_items(trait_def_id);
// Loop over all GATs together, because if this lint suggests adding a where-clause bound // Loop over all GATs together, because if this lint suggests adding a where-clause bound
// to one GAT, it might then require us to an additional bound on another GAT. // to one GAT, it might then require us to an additional bound on another GAT.
@ -325,8 +326,8 @@ fn check_gat_where_clauses(tcx: TyCtxt<'_>, associated_items: &[hir::TraitItemRe
// those GATs. // those GATs.
loop { loop {
let mut should_continue = false; let mut should_continue = false;
for gat_item in associated_items { for gat_item in associated_items.in_definition_order() {
let gat_def_id = gat_item.id.owner_id; let gat_def_id = gat_item.def_id.expect_local();
let gat_item = tcx.associated_item(gat_def_id); let gat_item = tcx.associated_item(gat_def_id);
// If this item is not an assoc ty, or has no args, then it's not a GAT // If this item is not an assoc ty, or has no args, then it's not a GAT
if gat_item.kind != ty::AssocKind::Type { if gat_item.kind != ty::AssocKind::Type {
@ -342,8 +343,8 @@ fn check_gat_where_clauses(tcx: TyCtxt<'_>, associated_items: &[hir::TraitItemRe
// This is calculated by taking the intersection of the bounds that each item // This is calculated by taking the intersection of the bounds that each item
// constrains the GAT with individually. // constrains the GAT with individually.
let mut new_required_bounds: Option<FxHashSet<ty::Clause<'_>>> = None; let mut new_required_bounds: Option<FxHashSet<ty::Clause<'_>>> = None;
for item in associated_items { for item in associated_items.in_definition_order() {
let item_def_id = item.id.owner_id; let item_def_id = item.def_id.expect_local();
// Skip our own GAT, since it does not constrain itself at all. // Skip our own GAT, since it does not constrain itself at all.
if item_def_id == gat_def_id { if item_def_id == gat_def_id {
continue; continue;
@ -351,9 +352,9 @@ fn check_gat_where_clauses(tcx: TyCtxt<'_>, associated_items: &[hir::TraitItemRe
let param_env = tcx.param_env(item_def_id); let param_env = tcx.param_env(item_def_id);
let item_required_bounds = match item.kind { let item_required_bounds = match tcx.associated_item(item_def_id).kind {
// In our example, this corresponds to `into_iter` method // In our example, this corresponds to `into_iter` method
hir::AssocItemKind::Fn { .. } => { ty::AssocKind::Fn => {
// For methods, we check the function signature's return type for any GATs // For methods, we check the function signature's return type for any GATs
// to constrain. In the `into_iter` case, we see that the return type // to constrain. In the `into_iter` case, we see that the return type
// `Self::Iter<'a>` is a GAT we want to gather any potential missing bounds from. // `Self::Iter<'a>` is a GAT we want to gather any potential missing bounds from.
@ -369,12 +370,12 @@ fn check_gat_where_clauses(tcx: TyCtxt<'_>, associated_items: &[hir::TraitItemRe
// We also assume that all of the function signature's parameter types // We also assume that all of the function signature's parameter types
// are well formed. // are well formed.
&sig.inputs().iter().copied().collect(), &sig.inputs().iter().copied().collect(),
gat_def_id.def_id, gat_def_id,
gat_generics, gat_generics,
) )
} }
// In our example, this corresponds to the `Iter` and `Item` associated types // In our example, this corresponds to the `Iter` and `Item` associated types
hir::AssocItemKind::Type => { ty::AssocKind::Type => {
// If our associated item is a GAT with missing bounds, add them to // If our associated item is a GAT with missing bounds, add them to
// the param-env here. This allows this GAT to propagate missing bounds // the param-env here. This allows this GAT to propagate missing bounds
// to other GATs. // to other GATs.
@ -391,11 +392,11 @@ fn check_gat_where_clauses(tcx: TyCtxt<'_>, associated_items: &[hir::TraitItemRe
.instantiate_identity_iter_copied() .instantiate_identity_iter_copied()
.collect::<Vec<_>>(), .collect::<Vec<_>>(),
&FxIndexSet::default(), &FxIndexSet::default(),
gat_def_id.def_id, gat_def_id,
gat_generics, gat_generics,
) )
} }
hir::AssocItemKind::Const => None, ty::AssocKind::Const => None,
}; };
if let Some(item_required_bounds) = item_required_bounds { if let Some(item_required_bounds) = item_required_bounds {
@ -431,7 +432,12 @@ fn check_gat_where_clauses(tcx: TyCtxt<'_>, associated_items: &[hir::TraitItemRe
} }
for (gat_def_id, required_bounds) in required_bounds_by_item { for (gat_def_id, required_bounds) in required_bounds_by_item {
let gat_item_hir = tcx.hir().expect_trait_item(gat_def_id.def_id); // Don't suggest adding `Self: 'a` to a GAT that can't be named
if tcx.is_impl_trait_in_trait(gat_def_id.to_def_id()) {
continue;
}
let gat_item_hir = tcx.hir().expect_trait_item(gat_def_id);
debug!(?required_bounds); debug!(?required_bounds);
let param_env = tcx.param_env(gat_def_id); let param_env = tcx.param_env(gat_def_id);
@ -441,21 +447,16 @@ fn check_gat_where_clauses(tcx: TyCtxt<'_>, associated_items: &[hir::TraitItemRe
ty::ClauseKind::RegionOutlives(ty::OutlivesPredicate(a, b)) => { ty::ClauseKind::RegionOutlives(ty::OutlivesPredicate(a, b)) => {
!region_known_to_outlive( !region_known_to_outlive(
tcx, tcx,
gat_def_id.def_id, gat_def_id,
param_env, param_env,
&FxIndexSet::default(), &FxIndexSet::default(),
a, a,
b, b,
) )
} }
ty::ClauseKind::TypeOutlives(ty::OutlivesPredicate(a, b)) => !ty_known_to_outlive( ty::ClauseKind::TypeOutlives(ty::OutlivesPredicate(a, b)) => {
tcx, !ty_known_to_outlive(tcx, gat_def_id, param_env, &FxIndexSet::default(), a, b)
gat_def_id.def_id, }
param_env,
&FxIndexSet::default(),
a,
b,
),
_ => bug!("Unexpected ClauseKind"), _ => bug!("Unexpected ClauseKind"),
}) })
.map(|clause| clause.to_string()) .map(|clause| clause.to_string())
@ -534,7 +535,7 @@ fn augment_param_env<'tcx>(
fn gather_gat_bounds<'tcx, T: TypeFoldable<TyCtxt<'tcx>>>( fn gather_gat_bounds<'tcx, T: TypeFoldable<TyCtxt<'tcx>>>(
tcx: TyCtxt<'tcx>, tcx: TyCtxt<'tcx>,
param_env: ty::ParamEnv<'tcx>, param_env: ty::ParamEnv<'tcx>,
item_def_id: hir::OwnerId, item_def_id: LocalDefId,
to_check: T, to_check: T,
wf_tys: &FxIndexSet<Ty<'tcx>>, wf_tys: &FxIndexSet<Ty<'tcx>>,
gat_def_id: LocalDefId, gat_def_id: LocalDefId,
@ -567,7 +568,7 @@ fn gather_gat_bounds<'tcx, T: TypeFoldable<TyCtxt<'tcx>>>(
// reflected in a where clause on the GAT itself. // reflected in a where clause on the GAT itself.
for (ty, ty_idx) in &types { for (ty, ty_idx) in &types {
// In our example, requires that `Self: 'a` // In our example, requires that `Self: 'a`
if ty_known_to_outlive(tcx, item_def_id.def_id, param_env, &wf_tys, *ty, *region_a) { if ty_known_to_outlive(tcx, item_def_id, param_env, &wf_tys, *ty, *region_a) {
debug!(?ty_idx, ?region_a_idx); debug!(?ty_idx, ?region_a_idx);
debug!("required clause: {ty} must outlive {region_a}"); debug!("required clause: {ty} must outlive {region_a}");
// Translate into the generic parameters of the GAT. In // Translate into the generic parameters of the GAT. In
@ -606,14 +607,7 @@ fn gather_gat_bounds<'tcx, T: TypeFoldable<TyCtxt<'tcx>>>(
if matches!(**region_b, ty::ReStatic | ty::ReError(_)) || region_a == region_b { if matches!(**region_b, ty::ReStatic | ty::ReError(_)) || region_a == region_b {
continue; continue;
} }
if region_known_to_outlive( if region_known_to_outlive(tcx, item_def_id, param_env, &wf_tys, *region_a, *region_b) {
tcx,
item_def_id.def_id,
param_env,
&wf_tys,
*region_a,
*region_b,
) {
debug!(?region_a_idx, ?region_b_idx); debug!(?region_a_idx, ?region_b_idx);
debug!("required clause: {region_a} must outlive {region_b}"); debug!("required clause: {region_a} must outlive {region_b}");
// Translate into the generic parameters of the GAT. // Translate into the generic parameters of the GAT.
@ -1114,8 +1108,8 @@ fn check_trait(tcx: TyCtxt<'_>, item: &hir::Item<'_>) {
}); });
// Only check traits, don't check trait aliases // Only check traits, don't check trait aliases
if let hir::ItemKind::Trait(_, _, _, _, items) = item.kind { if let hir::ItemKind::Trait(..) = item.kind {
check_gat_where_clauses(tcx, items); check_gat_where_clauses(tcx, item.owner_id.def_id);
} }
} }

View File

@ -3,7 +3,7 @@
use rustc_data_structures::graph::WithNumNodes; use rustc_data_structures::graph::WithNumNodes;
use rustc_index::IndexVec; use rustc_index::IndexVec;
use rustc_middle::mir::{self, AggregateKind, Rvalue, Statement, StatementKind}; use rustc_middle::mir::{self, AggregateKind, Rvalue, Statement, StatementKind};
use rustc_span::{BytePos, ExpnKind, MacroKind, Span, Symbol}; use rustc_span::{BytePos, ExpnKind, MacroKind, Span, Symbol, DUMMY_SP};
use super::graph::{BasicCoverageBlock, CoverageGraph, START_BCB}; use super::graph::{BasicCoverageBlock, CoverageGraph, START_BCB};
@ -215,9 +215,6 @@ struct CoverageSpansGenerator<'a> {
/// is mutated. /// is mutated.
prev_original_span: Span, prev_original_span: Span,
/// A copy of the expn_span from the prior iteration.
prev_expn_span: Option<Span>,
/// One or more `CoverageSpan`s with the same `Span` but different `BasicCoverageBlock`s, and /// One or more `CoverageSpan`s with the same `Span` but different `BasicCoverageBlock`s, and
/// no `BasicCoverageBlock` in this list dominates another `BasicCoverageBlock` in the list. /// no `BasicCoverageBlock` in this list dominates another `BasicCoverageBlock` in the list.
/// If a new `curr` span also fits this criteria (compared to an existing list of /// If a new `curr` span also fits this criteria (compared to an existing list of
@ -272,13 +269,12 @@ pub(super) fn generate_coverage_spans(
body_span, body_span,
basic_coverage_blocks, basic_coverage_blocks,
sorted_spans_iter: sorted_spans.into_iter(), sorted_spans_iter: sorted_spans.into_iter(),
refined_spans: Vec::with_capacity(basic_coverage_blocks.num_nodes() * 2),
some_curr: None, some_curr: None,
curr_original_span: Span::with_root_ctxt(BytePos(0), BytePos(0)), curr_original_span: DUMMY_SP,
some_prev: None, some_prev: None,
prev_original_span: Span::with_root_ctxt(BytePos(0), BytePos(0)), prev_original_span: DUMMY_SP,
prev_expn_span: None,
pending_dups: Vec::new(), pending_dups: Vec::new(),
refined_spans: Vec::with_capacity(basic_coverage_blocks.num_nodes() * 2),
}; };
coverage_spans.to_refined_spans() coverage_spans.to_refined_spans()
@ -288,43 +284,48 @@ pub(super) fn generate_coverage_spans(
/// de-duplicated `CoverageSpan`s. /// de-duplicated `CoverageSpan`s.
fn to_refined_spans(mut self) -> Vec<CoverageSpan> { fn to_refined_spans(mut self) -> Vec<CoverageSpan> {
while self.next_coverage_span() { while self.next_coverage_span() {
// For the first span we don't have `prev` set, so most of the
// span-processing steps don't make sense yet.
if self.some_prev.is_none() { if self.some_prev.is_none() {
debug!(" initial span"); debug!(" initial span");
self.check_invoked_macro_name_span(); self.maybe_push_macro_name_span();
} else if self.curr().is_mergeable(self.prev()) { continue;
debug!(" same bcb (and neither is a closure), merge with prev={:?}", self.prev()); }
// The remaining cases assume that `prev` and `curr` are set.
let prev = self.prev();
let curr = self.curr();
if curr.is_mergeable(prev) {
debug!(" same bcb (and neither is a closure), merge with prev={prev:?}");
let prev = self.take_prev(); let prev = self.take_prev();
self.curr_mut().merge_from(prev); self.curr_mut().merge_from(prev);
self.check_invoked_macro_name_span(); self.maybe_push_macro_name_span();
// Note that curr.span may now differ from curr_original_span // Note that curr.span may now differ from curr_original_span
} else if self.prev_ends_before_curr() { } else if prev.span.hi() <= curr.span.lo() {
debug!( debug!(
" different bcbs and disjoint spans, so keep curr for next iter, and add \ " different bcbs and disjoint spans, so keep curr for next iter, and add prev={prev:?}",
prev={:?}",
self.prev()
); );
let prev = self.take_prev(); let prev = self.take_prev();
self.push_refined_span(prev); self.push_refined_span(prev);
self.check_invoked_macro_name_span(); self.maybe_push_macro_name_span();
} else if self.prev().is_closure { } else if prev.is_closure {
// drop any equal or overlapping span (`curr`) and keep `prev` to test again in the // drop any equal or overlapping span (`curr`) and keep `prev` to test again in the
// next iter // next iter
debug!( debug!(
" curr overlaps a closure (prev). Drop curr and keep prev for next iter. \ " curr overlaps a closure (prev). Drop curr and keep prev for next iter. prev={prev:?}",
prev={:?}",
self.prev()
); );
self.take_curr(); self.take_curr(); // Discards curr.
} else if self.curr().is_closure { } else if curr.is_closure {
self.carve_out_span_for_closure(); self.carve_out_span_for_closure();
} else if self.prev_original_span == self.curr().span { } else if self.prev_original_span == curr.span {
// Note that this compares the new (`curr`) span to `prev_original_span`. // Note that this compares the new (`curr`) span to `prev_original_span`.
// In this branch, the actual span byte range of `prev_original_span` is not // In this branch, the actual span byte range of `prev_original_span` is not
// important. What is important is knowing whether the new `curr` span was // important. What is important is knowing whether the new `curr` span was
// **originally** the same as the original span of `prev()`. The original spans // **originally** the same as the original span of `prev()`. The original spans
// reflect their original sort order, and for equal spans, conveys a partial // reflect their original sort order, and for equal spans, conveys a partial
// ordering based on CFG dominator priority. // ordering based on CFG dominator priority.
if self.prev().is_macro_expansion() && self.curr().is_macro_expansion() { if prev.is_macro_expansion() && curr.is_macro_expansion() {
// Macros that expand to include branching (such as // Macros that expand to include branching (such as
// `assert_eq!()`, `assert_ne!()`, `info!()`, `debug!()`, or // `assert_eq!()`, `assert_ne!()`, `info!()`, `debug!()`, or
// `trace!()`) typically generate callee spans with identical // `trace!()`) typically generate callee spans with identical
@ -338,23 +339,24 @@ fn to_refined_spans(mut self) -> Vec<CoverageSpan> {
debug!( debug!(
" curr and prev are part of a macro expansion, and curr has the same span \ " curr and prev are part of a macro expansion, and curr has the same span \
as prev, but is in a different bcb. Drop curr and keep prev for next iter. \ as prev, but is in a different bcb. Drop curr and keep prev for next iter. \
prev={:?}", prev={prev:?}",
self.prev()
); );
self.take_curr(); self.take_curr(); // Discards curr.
} else { } else {
self.hold_pending_dups_unless_dominated(); self.update_pending_dups();
} }
} else { } else {
self.cutoff_prev_at_overlapping_curr(); self.cutoff_prev_at_overlapping_curr();
self.check_invoked_macro_name_span(); self.maybe_push_macro_name_span();
} }
} }
debug!(" AT END, adding last prev={:?}", self.prev());
let prev = self.take_prev(); let prev = self.take_prev();
let pending_dups = self.pending_dups.split_off(0); debug!(" AT END, adding last prev={prev:?}");
for dup in pending_dups {
// Take `pending_dups` so that we can drain it while calling self methods.
// It is never used as a field after this point.
for dup in std::mem::take(&mut self.pending_dups) {
debug!(" ...adding at least one pending dup={:?}", dup); debug!(" ...adding at least one pending dup={:?}", dup);
self.push_refined_span(dup); self.push_refined_span(dup);
} }
@ -384,44 +386,41 @@ fn to_refined_spans(mut self) -> Vec<CoverageSpan> {
} }
fn push_refined_span(&mut self, covspan: CoverageSpan) { fn push_refined_span(&mut self, covspan: CoverageSpan) {
let len = self.refined_spans.len(); if let Some(last) = self.refined_spans.last_mut()
if len > 0 { && last.is_mergeable(&covspan)
let last = &mut self.refined_spans[len - 1]; {
if last.is_mergeable(&covspan) { // Instead of pushing the new span, merge it with the last refined span.
debug!( debug!(?last, ?covspan, "merging new refined span with last refined span");
"merging new refined span with last refined span, last={:?}, covspan={:?}",
last, covspan
);
last.merge_from(covspan); last.merge_from(covspan);
return; } else {
self.refined_spans.push(covspan);
} }
} }
self.refined_spans.push(covspan)
}
fn check_invoked_macro_name_span(&mut self) { /// If `curr` is part of a new macro expansion, carve out and push a separate
if let Some(visible_macro) = self.curr().visible_macro(self.body_span) { /// span that ends just after the macro name and its subsequent `!`.
if !self fn maybe_push_macro_name_span(&mut self) {
.prev_expn_span let curr = self.curr();
.is_some_and(|prev_expn_span| self.curr().expn_span.ctxt() == prev_expn_span.ctxt())
let Some(visible_macro) = curr.visible_macro(self.body_span) else { return };
if let Some(prev) = &self.some_prev
&& prev.expn_span.ctxt() == curr.expn_span.ctxt()
{ {
let merged_prefix_len = self.curr_original_span.lo() - self.curr().span.lo(); return;
let after_macro_bang = }
merged_prefix_len + BytePos(visible_macro.as_str().len() as u32 + 1);
let mut macro_name_cov = self.curr().clone(); let merged_prefix_len = self.curr_original_span.lo() - curr.span.lo();
self.curr_mut().span = let after_macro_bang = merged_prefix_len + BytePos(visible_macro.as_str().len() as u32 + 1);
self.curr().span.with_lo(self.curr().span.lo() + after_macro_bang); let mut macro_name_cov = curr.clone();
self.curr_mut().span = curr.span.with_lo(curr.span.lo() + after_macro_bang);
macro_name_cov.span = macro_name_cov.span =
macro_name_cov.span.with_hi(macro_name_cov.span.lo() + after_macro_bang); macro_name_cov.span.with_hi(macro_name_cov.span.lo() + after_macro_bang);
debug!( debug!(
" and curr starts a new macro expansion, so add a new span just for \ " and curr starts a new macro expansion, so add a new span just for \
the macro `{}!`, new span={:?}", the macro `{visible_macro}!`, new span={macro_name_cov:?}",
visible_macro, macro_name_cov
); );
self.push_refined_span(macro_name_cov); self.push_refined_span(macro_name_cov);
} }
}
}
fn curr(&self) -> &CoverageSpan { fn curr(&self) -> &CoverageSpan {
self.some_curr self.some_curr
@ -435,6 +434,12 @@ fn curr_mut(&mut self) -> &mut CoverageSpan {
.unwrap_or_else(|| bug!("invalid attempt to unwrap a None some_curr")) .unwrap_or_else(|| bug!("invalid attempt to unwrap a None some_curr"))
} }
/// If called, then the next call to `next_coverage_span()` will *not* update `prev` with the
/// `curr` coverage span.
fn take_curr(&mut self) -> CoverageSpan {
self.some_curr.take().unwrap_or_else(|| bug!("invalid attempt to unwrap a None some_curr"))
}
fn prev(&self) -> &CoverageSpan { fn prev(&self) -> &CoverageSpan {
self.some_prev self.some_prev
.as_ref() .as_ref()
@ -460,84 +465,78 @@ fn take_prev(&mut self) -> CoverageSpan {
/// `pending_dups` could have as few as one span) /// `pending_dups` could have as few as one span)
/// In either case, no more spans will match the span of `pending_dups`, so /// In either case, no more spans will match the span of `pending_dups`, so
/// add the `pending_dups` if they don't overlap `curr`, and clear the list. /// add the `pending_dups` if they don't overlap `curr`, and clear the list.
fn check_pending_dups(&mut self) { fn maybe_flush_pending_dups(&mut self) {
if let Some(dup) = self.pending_dups.last() let Some(last_dup) = self.pending_dups.last() else { return };
&& dup.span != self.prev().span if last_dup.span == self.prev().span {
{ return;
}
debug!( debug!(
" SAME spans, but pending_dups are NOT THE SAME, so BCBs matched on \ " SAME spans, but pending_dups are NOT THE SAME, so BCBs matched on \
previous iteration, or prev started a new disjoint span" previous iteration, or prev started a new disjoint span"
); );
if dup.span.hi() <= self.curr().span.lo() { if last_dup.span.hi() <= self.curr().span.lo() {
let pending_dups = self.pending_dups.split_off(0); // Temporarily steal `pending_dups` into a local, so that we can
for dup in pending_dups.into_iter() { // drain it while calling other self methods.
let mut pending_dups = std::mem::take(&mut self.pending_dups);
for dup in pending_dups.drain(..) {
debug!(" ...adding at least one pending={:?}", dup); debug!(" ...adding at least one pending={:?}", dup);
self.push_refined_span(dup); self.push_refined_span(dup);
} }
// The list of dups is now empty, but we can recycle its capacity.
assert!(pending_dups.is_empty() && self.pending_dups.is_empty());
self.pending_dups = pending_dups;
} else { } else {
self.pending_dups.clear(); self.pending_dups.clear();
} }
} }
}
/// Advance `prev` to `curr` (if any), and `curr` to the next `CoverageSpan` in sorted order. /// Advance `prev` to `curr` (if any), and `curr` to the next `CoverageSpan` in sorted order.
fn next_coverage_span(&mut self) -> bool { fn next_coverage_span(&mut self) -> bool {
if let Some(curr) = self.some_curr.take() { if let Some(curr) = self.some_curr.take() {
self.prev_expn_span = Some(curr.expn_span);
self.some_prev = Some(curr); self.some_prev = Some(curr);
self.prev_original_span = self.curr_original_span; self.prev_original_span = self.curr_original_span;
} }
while let Some(curr) = self.sorted_spans_iter.next() { while let Some(curr) = self.sorted_spans_iter.next() {
debug!("FOR curr={:?}", curr); debug!("FOR curr={:?}", curr);
if self.some_prev.is_some() && self.prev_starts_after_next(&curr) { if let Some(prev) = &self.some_prev && prev.span.lo() > curr.span.lo() {
// Skip curr because prev has already advanced beyond the end of curr.
// This can only happen if a prior iteration updated `prev` to skip past
// a region of code, such as skipping past a closure.
debug!( debug!(
" prev.span starts after curr.span, so curr will be dropped (skipping past \ " prev.span starts after curr.span, so curr will be dropped (skipping past \
closure?); prev={:?}", closure?); prev={prev:?}",
self.prev()
); );
} else { } else {
// Save a copy of the original span for `curr` in case the `CoverageSpan` is changed // Save a copy of the original span for `curr` in case the `CoverageSpan` is changed
// by `self.curr_mut().merge_from(prev)`. // by `self.curr_mut().merge_from(prev)`.
self.curr_original_span = curr.span; self.curr_original_span = curr.span;
self.some_curr.replace(curr); self.some_curr.replace(curr);
self.check_pending_dups(); self.maybe_flush_pending_dups();
return true; return true;
} }
} }
false false
} }
/// If called, then the next call to `next_coverage_span()` will *not* update `prev` with the
/// `curr` coverage span.
fn take_curr(&mut self) -> CoverageSpan {
self.some_curr.take().unwrap_or_else(|| bug!("invalid attempt to unwrap a None some_curr"))
}
/// Returns true if the curr span should be skipped because prev has already advanced beyond the
/// end of curr. This can only happen if a prior iteration updated `prev` to skip past a region
/// of code, such as skipping past a closure.
fn prev_starts_after_next(&self, next_curr: &CoverageSpan) -> bool {
self.prev().span.lo() > next_curr.span.lo()
}
/// Returns true if the curr span starts past the end of the prev span, which means they don't
/// overlap, so we now know the prev can be added to the refined coverage spans.
fn prev_ends_before_curr(&self) -> bool {
self.prev().span.hi() <= self.curr().span.lo()
}
/// If `prev`s span extends left of the closure (`curr`), carve out the closure's span from /// If `prev`s span extends left of the closure (`curr`), carve out the closure's span from
/// `prev`'s span. (The closure's coverage counters will be injected when processing the /// `prev`'s span. (The closure's coverage counters will be injected when processing the
/// closure's own MIR.) Add the portion of the span to the left of the closure; and if the span /// closure's own MIR.) Add the portion of the span to the left of the closure; and if the span
/// extends to the right of the closure, update `prev` to that portion of the span. For any /// extends to the right of the closure, update `prev` to that portion of the span. For any
/// `pending_dups`, repeat the same process. /// `pending_dups`, repeat the same process.
fn carve_out_span_for_closure(&mut self) { fn carve_out_span_for_closure(&mut self) {
let curr_span = self.curr().span; let prev = self.prev();
let left_cutoff = curr_span.lo(); let curr = self.curr();
let right_cutoff = curr_span.hi();
let has_pre_closure_span = self.prev().span.lo() < right_cutoff; let left_cutoff = curr.span.lo();
let has_post_closure_span = self.prev().span.hi() > right_cutoff; let right_cutoff = curr.span.hi();
let mut pending_dups = self.pending_dups.split_off(0); let has_pre_closure_span = prev.span.lo() < right_cutoff;
let has_post_closure_span = prev.span.hi() > right_cutoff;
// Temporarily steal `pending_dups` into a local, so that we can
// mutate and/or drain it while calling other self methods.
let mut pending_dups = std::mem::take(&mut self.pending_dups);
if has_pre_closure_span { if has_pre_closure_span {
let mut pre_closure = self.prev().clone(); let mut pre_closure = self.prev().clone();
pre_closure.span = pre_closure.span.with_hi(left_cutoff); pre_closure.span = pre_closure.span.with_hi(left_cutoff);
@ -551,6 +550,7 @@ fn carve_out_span_for_closure(&mut self) {
} }
self.push_refined_span(pre_closure); self.push_refined_span(pre_closure);
} }
if has_post_closure_span { if has_post_closure_span {
// Mutate `prev.span()` to start after the closure (and discard curr). // Mutate `prev.span()` to start after the closure (and discard curr).
// (**NEVER** update `prev_original_span` because it affects the assumptions // (**NEVER** update `prev_original_span` because it affects the assumptions
@ -561,12 +561,15 @@ fn carve_out_span_for_closure(&mut self) {
debug!(" ...and at least one overlapping dup={:?}", dup); debug!(" ...and at least one overlapping dup={:?}", dup);
dup.span = dup.span.with_lo(right_cutoff); dup.span = dup.span.with_lo(right_cutoff);
} }
self.pending_dups.append(&mut pending_dups); let closure_covspan = self.take_curr(); // Prevent this curr from becoming prev.
let closure_covspan = self.take_curr();
self.push_refined_span(closure_covspan); // since self.prev() was already updated self.push_refined_span(closure_covspan); // since self.prev() was already updated
} else { } else {
pending_dups.clear(); pending_dups.clear();
} }
// Restore the modified post-closure spans, or the empty vector's capacity.
assert!(self.pending_dups.is_empty());
self.pending_dups = pending_dups;
} }
/// Called if `curr.span` equals `prev_original_span` (and potentially equal to all /// Called if `curr.span` equals `prev_original_span` (and potentially equal to all
@ -583,26 +586,28 @@ fn carve_out_span_for_closure(&mut self) {
/// neither `CoverageSpan` dominates the other, both (or possibly more than two) are held, /// neither `CoverageSpan` dominates the other, both (or possibly more than two) are held,
/// until their disposition is determined. In this latter case, the `prev` dup is moved into /// until their disposition is determined. In this latter case, the `prev` dup is moved into
/// `pending_dups` so the new `curr` dup can be moved to `prev` for the next iteration. /// `pending_dups` so the new `curr` dup can be moved to `prev` for the next iteration.
fn hold_pending_dups_unless_dominated(&mut self) { fn update_pending_dups(&mut self) {
let prev_bcb = self.prev().bcb;
let curr_bcb = self.curr().bcb;
// Equal coverage spans are ordered by dominators before dominated (if any), so it should be // Equal coverage spans are ordered by dominators before dominated (if any), so it should be
// impossible for `curr` to dominate any previous `CoverageSpan`. // impossible for `curr` to dominate any previous `CoverageSpan`.
debug_assert!(!self.span_bcb_dominates(self.curr(), self.prev())); debug_assert!(!self.basic_coverage_blocks.dominates(curr_bcb, prev_bcb));
let initial_pending_count = self.pending_dups.len(); let initial_pending_count = self.pending_dups.len();
if initial_pending_count > 0 { if initial_pending_count > 0 {
let mut pending_dups = self.pending_dups.split_off(0); self.pending_dups
pending_dups.retain(|dup| !self.span_bcb_dominates(dup, self.curr())); .retain(|dup| !self.basic_coverage_blocks.dominates(dup.bcb, curr_bcb));
self.pending_dups.append(&mut pending_dups);
if self.pending_dups.len() < initial_pending_count { let n_discarded = initial_pending_count - self.pending_dups.len();
if n_discarded > 0 {
debug!( debug!(
" discarded {} of {} pending_dups that dominated curr", " discarded {n_discarded} of {initial_pending_count} pending_dups that dominated curr",
initial_pending_count - self.pending_dups.len(),
initial_pending_count
); );
} }
} }
if self.span_bcb_dominates(self.prev(), self.curr()) { if self.basic_coverage_blocks.dominates(prev_bcb, curr_bcb) {
debug!( debug!(
" different bcbs but SAME spans, and prev dominates curr. Discard prev={:?}", " different bcbs but SAME spans, and prev dominates curr. Discard prev={:?}",
self.prev() self.prev()
@ -667,8 +672,4 @@ fn cutoff_prev_at_overlapping_curr(&mut self) {
self.pending_dups.clear(); self.pending_dups.clear();
} }
} }
fn span_bcb_dominates(&self, dom_covspan: &CoverageSpan, covspan: &CoverageSpan) -> bool {
self.basic_coverage_blocks.dominates(dom_covspan.bcb, covspan.bcb)
}
} }

View File

@ -180,8 +180,9 @@ fn on_unimplemented_note(
flags.push((sym::cause, Some("MainFunctionType".to_string()))); flags.push((sym::cause, Some("MainFunctionType".to_string())));
} }
// Add all types without trimmed paths. // Add all types without trimmed paths or visible paths, ensuring they end up with
ty::print::with_no_trimmed_paths!({ // their "canonical" def path.
ty::print::with_no_trimmed_paths!(ty::print::with_no_visible_paths!({
let generics = self.tcx.generics_of(def_id); let generics = self.tcx.generics_of(def_id);
let self_ty = trait_ref.self_ty(); let self_ty = trait_ref.self_ty();
// This is also included through the generics list as `Self`, // This is also included through the generics list as `Self`,
@ -296,7 +297,7 @@ fn on_unimplemented_note(
{ {
flags.push((sym::_Self, Some("&[{integral}]".to_owned()))); flags.push((sym::_Self, Some("&[{integral}]".to_owned())));
} }
}); }));
if let Ok(Some(command)) = OnUnimplementedDirective::of_item(self.tcx, def_id) { if let Ok(Some(command)) = OnUnimplementedDirective::of_item(self.tcx, def_id) {
command.evaluate(self.tcx, trait_ref, &flags) command.evaluate(self.tcx, trait_ref, &flags)
@ -578,7 +579,9 @@ pub fn evaluate(
Some(tcx.features()), Some(tcx.features()),
&mut |cfg| { &mut |cfg| {
let value = cfg.value.map(|v| { let value = cfg.value.map(|v| {
OnUnimplementedFormatString(v).format(tcx, trait_ref, &options_map) // `with_no_visible_paths` is also used when generating the options,
// so we need to match it here.
ty::print::with_no_visible_paths!(OnUnimplementedFormatString(v).format(tcx, trait_ref, &options_map))
}); });
options.contains(&(cfg.name, value)) options.contains(&(cfg.name, value))

View File

@ -573,7 +573,7 @@ pub trait Into<T>: Sized {
#[rustc_diagnostic_item = "From"] #[rustc_diagnostic_item = "From"]
#[stable(feature = "rust1", since = "1.0.0")] #[stable(feature = "rust1", since = "1.0.0")]
#[rustc_on_unimplemented(on( #[rustc_on_unimplemented(on(
all(_Self = "&str", any(T = "alloc::string::String", T = "std::string::String")), all(_Self = "&str", T = "alloc::string::String"),
note = "to coerce a `{T}` into a `{Self}`, use `&*` as a prefix", note = "to coerce a `{T}` into a `{Self}`, use `&*` as a prefix",
))] ))]
pub trait From<T>: Sized { pub trait From<T>: Sized {

View File

@ -27,13 +27,13 @@ fn _assert_is_object_safe(_: &dyn Iterator<Item = ()>) {}
#[stable(feature = "rust1", since = "1.0.0")] #[stable(feature = "rust1", since = "1.0.0")]
#[rustc_on_unimplemented( #[rustc_on_unimplemented(
on( on(
any(_Self = "core::ops::RangeTo<Idx>", _Self = "std::ops::RangeTo<Idx>"), _Self = "core::ops::range::RangeTo<Idx>",
label = "if you meant to iterate until a value, add a starting value", label = "if you meant to iterate until a value, add a starting value",
note = "`..end` is a `RangeTo`, which cannot be iterated on; you might have meant to have a \ note = "`..end` is a `RangeTo`, which cannot be iterated on; you might have meant to have a \
bounded `Range`: `0..end`" bounded `Range`: `0..end`"
), ),
on( on(
any(_Self = "core::ops::RangeToInclusive<Idx>", _Self = "std::ops::RangeToInclusive<Idx>"), _Self = "core::ops::range::RangeToInclusive<Idx>",
label = "if you meant to iterate until a value (including it), add a starting value", label = "if you meant to iterate until a value (including it), add a starting value",
note = "`..=end` is a `RangeToInclusive`, which cannot be iterated on; you might have meant \ note = "`..=end` is a `RangeToInclusive`, which cannot be iterated on; you might have meant \
to have a bounded `RangeInclusive`: `0..=end`" to have a bounded `RangeInclusive`: `0..=end`"
@ -44,7 +44,7 @@ fn _assert_is_object_safe(_: &dyn Iterator<Item = ()>) {}
), ),
on(_Self = "&[]", label = "`{Self}` is not an iterator; try calling `.iter()`"), on(_Self = "&[]", label = "`{Self}` is not an iterator; try calling `.iter()`"),
on( on(
any(_Self = "alloc::vec::Vec<T, A>", _Self = "std::vec::Vec<T, A>"), _Self = "alloc::vec::Vec<T, A>",
label = "`{Self}` is not an iterator; try calling `.into_iter()` or `.iter()`" label = "`{Self}` is not an iterator; try calling `.into_iter()` or `.iter()`"
), ),
on( on(
@ -52,7 +52,7 @@ fn _assert_is_object_safe(_: &dyn Iterator<Item = ()>) {}
label = "`{Self}` is not an iterator; try calling `.chars()` or `.bytes()`" label = "`{Self}` is not an iterator; try calling `.chars()` or `.bytes()`"
), ),
on( on(
any(_Self = "alloc::string::String", _Self = "std::string::String"), _Self = "alloc::string::String",
label = "`{Self}` is not an iterator; try calling `.chars()` or `.bytes()`" label = "`{Self}` is not an iterator; try calling `.chars()` or `.bytes()`"
), ),
on( on(

View File

@ -573,59 +573,59 @@ impl<T: ?Sized> Copy for &T {}
#[lang = "sync"] #[lang = "sync"]
#[rustc_on_unimplemented( #[rustc_on_unimplemented(
on( on(
any(_Self = "core::cell:OnceCell<T>", _Self = "std::cell::OnceCell<T>"), _Self = "core::cell::once::OnceCell<T>",
note = "if you want to do aliasing and mutation between multiple threads, use `std::sync::OnceLock` instead" note = "if you want to do aliasing and mutation between multiple threads, use `std::sync::OnceLock` instead"
), ),
on( on(
any(_Self = "core::cell::Cell<u8>", _Self = "std::cell::Cell<u8>"), _Self = "core::cell::Cell<u8>",
note = "if you want to do aliasing and mutation between multiple threads, use `std::sync::RwLock` or `std::sync::atomic::AtomicU8` instead", note = "if you want to do aliasing and mutation between multiple threads, use `std::sync::RwLock` or `std::sync::atomic::AtomicU8` instead",
), ),
on( on(
any(_Self = "core::cell::Cell<u16>", _Self = "std::cell::Cell<u16>"), _Self = "core::cell::Cell<u16>",
note = "if you want to do aliasing and mutation between multiple threads, use `std::sync::RwLock` or `std::sync::atomic::AtomicU16` instead", note = "if you want to do aliasing and mutation between multiple threads, use `std::sync::RwLock` or `std::sync::atomic::AtomicU16` instead",
), ),
on( on(
any(_Self = "core::cell::Cell<u32>", _Self = "std::cell::Cell<u32>"), _Self = "core::cell::Cell<u32>",
note = "if you want to do aliasing and mutation between multiple threads, use `std::sync::RwLock` or `std::sync::atomic::AtomicU32` instead", note = "if you want to do aliasing and mutation between multiple threads, use `std::sync::RwLock` or `std::sync::atomic::AtomicU32` instead",
), ),
on( on(
any(_Self = "core::cell::Cell<u64>", _Self = "std::cell::Cell<u64>"), _Self = "core::cell::Cell<u64>",
note = "if you want to do aliasing and mutation between multiple threads, use `std::sync::RwLock` or `std::sync::atomic::AtomicU64` instead", note = "if you want to do aliasing and mutation between multiple threads, use `std::sync::RwLock` or `std::sync::atomic::AtomicU64` instead",
), ),
on( on(
any(_Self = "core::cell::Cell<usize>", _Self = "std::cell::Cell<usize>"), _Self = "core::cell::Cell<usize>",
note = "if you want to do aliasing and mutation between multiple threads, use `std::sync::RwLock` or `std::sync::atomic::AtomicUsize` instead", note = "if you want to do aliasing and mutation between multiple threads, use `std::sync::RwLock` or `std::sync::atomic::AtomicUsize` instead",
), ),
on( on(
any(_Self = "core::cell::Cell<i8>", _Self = "std::cell::Cell<i8>"), _Self = "core::cell::Cell<i8>",
note = "if you want to do aliasing and mutation between multiple threads, use `std::sync::RwLock` or `std::sync::atomic::AtomicI8` instead", note = "if you want to do aliasing and mutation between multiple threads, use `std::sync::RwLock` or `std::sync::atomic::AtomicI8` instead",
), ),
on( on(
any(_Self = "core::cell::Cell<i16>", _Self = "std::cell::Cell<i16>"), _Self = "core::cell::Cell<i16>",
note = "if you want to do aliasing and mutation between multiple threads, use `std::sync::RwLock` or `std::sync::atomic::AtomicI16` instead", note = "if you want to do aliasing and mutation between multiple threads, use `std::sync::RwLock` or `std::sync::atomic::AtomicI16` instead",
), ),
on( on(
any(_Self = "core::cell::Cell<i32>", _Self = "std::cell::Cell<i32>"), _Self = "core::cell::Cell<i32>",
note = "if you want to do aliasing and mutation between multiple threads, use `std::sync::RwLock` or `std::sync::atomic::AtomicI32` instead", note = "if you want to do aliasing and mutation between multiple threads, use `std::sync::RwLock` or `std::sync::atomic::AtomicI32` instead",
), ),
on( on(
any(_Self = "core::cell::Cell<i64>", _Self = "std::cell::Cell<i64>"), _Self = "core::cell::Cell<i64>",
note = "if you want to do aliasing and mutation between multiple threads, use `std::sync::RwLock` or `std::sync::atomic::AtomicI64` instead", note = "if you want to do aliasing and mutation between multiple threads, use `std::sync::RwLock` or `std::sync::atomic::AtomicI64` instead",
), ),
on( on(
any(_Self = "core::cell::Cell<isize>", _Self = "std::cell::Cell<isize>"), _Self = "core::cell::Cell<isize>",
note = "if you want to do aliasing and mutation between multiple threads, use `std::sync::RwLock` or `std::sync::atomic::AtomicIsize` instead", note = "if you want to do aliasing and mutation between multiple threads, use `std::sync::RwLock` or `std::sync::atomic::AtomicIsize` instead",
), ),
on( on(
any(_Self = "core::cell::Cell<bool>", _Self = "std::cell::Cell<bool>"), _Self = "core::cell::Cell<bool>",
note = "if you want to do aliasing and mutation between multiple threads, use `std::sync::RwLock` or `std::sync::atomic::AtomicBool` instead", note = "if you want to do aliasing and mutation between multiple threads, use `std::sync::RwLock` or `std::sync::atomic::AtomicBool` instead",
), ),
on( on(
any(_Self = "core::cell::Cell<T>", _Self = "std::cell::Cell<T>"), _Self = "core::cell::Cell<T>",
note = "if you want to do aliasing and mutation between multiple threads, use `std::sync::RwLock`", note = "if you want to do aliasing and mutation between multiple threads, use `std::sync::RwLock`",
), ),
on( on(
any(_Self = "core::cell::RefCell<T>", _Self = "std::cell::RefCell<T>"), _Self = "core::cell::RefCell<T>",
note = "if you want to do aliasing and mutation between multiple threads, use `std::sync::RwLock` instead", note = "if you want to do aliasing and mutation between multiple threads, use `std::sync::RwLock` instead",
), ),
message = "`{Self}` cannot be shared between threads safely", message = "`{Self}` cannot be shared between threads safely",

View File

@ -153,7 +153,7 @@ pub trait Index<Idx: ?Sized> {
see chapter in The Book <https://doc.rust-lang.org/book/ch08-02-strings.html#indexing-into-strings>" see chapter in The Book <https://doc.rust-lang.org/book/ch08-02-strings.html#indexing-into-strings>"
), ),
on( on(
any(_Self = "alloc::string::String", _Self = "std::string::String"), _Self = "alloc::string::String",
note = "you can use `.chars().nth()` or `.bytes().nth()` note = "you can use `.chars().nth()` or `.bytes().nth()`
see chapter in The Book <https://doc.rust-lang.org/book/ch08-02-strings.html#indexing-into-strings>" see chapter in The Book <https://doc.rust-lang.org/book/ch08-02-strings.html#indexing-into-strings>"
), ),

View File

@ -226,14 +226,8 @@ pub trait Try: FromResidual {
on( on(
all( all(
from_desugaring = "QuestionMark", from_desugaring = "QuestionMark",
any(
_Self = "core::result::Result<T, E>", _Self = "core::result::Result<T, E>",
_Self = "std::result::Result<T, E>",
),
any(
R = "core::option::Option<core::convert::Infallible>", R = "core::option::Option<core::convert::Infallible>",
R = "std::option::Option<std::convert::Infallible>",
)
), ),
message = "the `?` operator can only be used on `Result`s, not `Option`s, \ message = "the `?` operator can only be used on `Result`s, not `Option`s, \
in {ItemContext} that returns `Result`", in {ItemContext} that returns `Result`",
@ -243,10 +237,7 @@ pub trait Try: FromResidual {
on( on(
all( all(
from_desugaring = "QuestionMark", from_desugaring = "QuestionMark",
any(
_Self = "core::result::Result<T, E>", _Self = "core::result::Result<T, E>",
_Self = "std::result::Result<T, E>",
)
), ),
// There's a special error message in the trait selection code for // There's a special error message in the trait selection code for
// `From` in `?`, so this is not shown for result-in-result errors, // `From` in `?`, so this is not shown for result-in-result errors,
@ -259,14 +250,8 @@ pub trait Try: FromResidual {
on( on(
all( all(
from_desugaring = "QuestionMark", from_desugaring = "QuestionMark",
any(
_Self = "core::option::Option<T>", _Self = "core::option::Option<T>",
_Self = "std::option::Option<T>",
),
any(
R = "core::result::Result<T, E>", R = "core::result::Result<T, E>",
R = "std::result::Result<T, E>",
)
), ),
message = "the `?` operator can only be used on `Option`s, not `Result`s, \ message = "the `?` operator can only be used on `Option`s, not `Result`s, \
in {ItemContext} that returns `Option`", in {ItemContext} that returns `Option`",
@ -276,10 +261,7 @@ pub trait Try: FromResidual {
on( on(
all( all(
from_desugaring = "QuestionMark", from_desugaring = "QuestionMark",
any(
_Self = "core::option::Option<T>", _Self = "core::option::Option<T>",
_Self = "std::option::Option<T>",
)
), ),
// `Option`-in-`Option` always works, as there's only one possible // `Option`-in-`Option` always works, as there's only one possible
// residual, so this can also be phrased strongly. // residual, so this can also be phrased strongly.
@ -291,14 +273,8 @@ pub trait Try: FromResidual {
on( on(
all( all(
from_desugaring = "QuestionMark", from_desugaring = "QuestionMark",
any( _Self = "core::ops::control_flow::ControlFlow<B, C>",
_Self = "core::ops::ControlFlow<B, C>", R = "core::ops::control_flow::ControlFlow<B, C>",
_Self = "std::ops::ControlFlow<B, C>",
),
any(
R = "core::ops::ControlFlow<B, C>",
R = "std::ops::ControlFlow<B, C>",
)
), ),
message = "the `?` operator in {ItemContext} that returns `ControlFlow<B, _>` \ message = "the `?` operator in {ItemContext} that returns `ControlFlow<B, _>` \
can only be used on other `ControlFlow<B, _>`s (with the same Break type)", can only be used on other `ControlFlow<B, _>`s (with the same Break type)",
@ -309,10 +285,7 @@ pub trait Try: FromResidual {
on( on(
all( all(
from_desugaring = "QuestionMark", from_desugaring = "QuestionMark",
any( _Self = "core::ops::control_flow::ControlFlow<B, C>",
_Self = "core::ops::ControlFlow<B, C>",
_Self = "std::ops::ControlFlow<B, C>",
)
// `R` is not a `ControlFlow`, as that case was matched previously // `R` is not a `ControlFlow`, as that case was matched previously
), ),
message = "the `?` operator can only be used on `ControlFlow`s \ message = "the `?` operator can only be used on `ControlFlow`s \

View File

@ -152,10 +152,7 @@ impl Sealed for ops::IndexRange {}
#[rustc_on_unimplemented( #[rustc_on_unimplemented(
on(T = "str", label = "string indices are ranges of `usize`",), on(T = "str", label = "string indices are ranges of `usize`",),
on( on(
all( all(any(T = "str", T = "&str", T = "alloc::string::String"), _Self = "{integer}"),
any(T = "str", T = "&str", T = "alloc::string::String", T = "std::string::String"),
_Self = "{integer}"
),
note = "you can use `.chars().nth()` or `.bytes().nth()`\n\ note = "you can use `.chars().nth()` or `.bytes().nth()`\n\
for more information, see chapter 8 in The Book: \ for more information, see chapter 8 in The Book: \
<https://doc.rust-lang.org/book/ch08-02-strings.html#indexing-into-strings>" <https://doc.rust-lang.org/book/ch08-02-strings.html#indexing-into-strings>"

View File

@ -249,12 +249,17 @@ async function main(argv) {
console.log("`--no-headless` option is active, disabling concurrency for running tests."); console.log("`--no-headless` option is active, disabling concurrency for running tests.");
} }
console.log(`Running ${files.length} rustdoc-gui (${opts["jobs"]} concurrently) ...`);
if (opts["jobs"] < 1) { if (opts["jobs"] < 1) {
const len = files.length;
console.log(
`Running ${len} rustdoc-gui (UNBOUNDED concurrency; use "-j#" for a limit) ...`,
);
process.setMaxListeners(files.length + 1); process.setMaxListeners(files.length + 1);
} else if (headless) { } else if (headless) {
console.log(`Running ${files.length} rustdoc-gui (${opts["jobs"]} concurrently) ...`);
process.setMaxListeners(opts["jobs"] + 1); process.setMaxListeners(opts["jobs"] + 1);
} else {
console.log(`Running ${files.length} rustdoc-gui ...`);
} }
// We catch this "event" to display a nicer message in case of unexpected exit (because of a // We catch this "event" to display a nicer message in case of unexpected exit (because of a

View File

@ -0,0 +1,21 @@
#![feature(prelude_import)]
#![no_std]
#[prelude_import]
use ::std::prelude::rust_2015::*;
#[macro_use]
extern crate std;
// pretty-compare-only
// pretty-mode:expanded
// pp-exact:format-args-str-escape.pp
fn main() {
{ ::std::io::_print(format_args!("\u{1b}[1mHello, world!\u{1b}[0m\n")); };
{ ::std::io::_print(format_args!("\u{1b}[1mHello, world!\u{1b}[0m\n")); };
{
::std::io::_print(format_args!("Not an escape sequence: \\u{{1B}}[1mbold\\x1B[0m\n"));
};
{
::std::io::_print(format_args!("{0}\n",
"\x1B[1mHello, world!\x1B[0m"));
};
}

View File

@ -0,0 +1,10 @@
// pretty-compare-only
// pretty-mode:expanded
// pp-exact:format-args-str-escape.pp
fn main() {
println!("\x1B[1mHello, world!\x1B[0m");
println!("\u{1B}[1mHello, world!\u{1B}[0m");
println!("Not an escape sequence: \\u{{1B}}[1mbold\\x1B[0m");
println!("{}", "\x1B[1mHello, world!\x1B[0m");
}

View File

@ -0,0 +1,17 @@
// edition: 2021
use std::future::Future;
trait Trait {
type Gat<'a>;
//~^ ERROR missing required bound on `Gat`
async fn foo(&self) -> Self::Gat<'_>;
}
trait Trait2 {
type Gat<'a>;
//~^ ERROR missing required bound on `Gat`
async fn foo(&self) -> impl Future<Output = Self::Gat<'_>>;
}
fn main() {}

View File

@ -0,0 +1,24 @@
error: missing required bound on `Gat`
--> $DIR/gat-outlives.rs:6:5
|
LL | type Gat<'a>;
| ^^^^^^^^^^^^-
| |
| help: add the required where clause: `where Self: 'a`
|
= note: this bound is currently required to ensure that impls have maximum flexibility
= note: we are soliciting feedback, see issue #87479 <https://github.com/rust-lang/rust/issues/87479> for more information
error: missing required bound on `Gat`
--> $DIR/gat-outlives.rs:12:5
|
LL | type Gat<'a>;
| ^^^^^^^^^^^^-
| |
| help: add the required where clause: `where Self: 'a`
|
= note: this bound is currently required to ensure that impls have maximum flexibility
= note: we are soliciting feedback, see issue #87479 <https://github.com/rust-lang/rust/issues/87479> for more information
error: aborting due to 2 previous errors

View File

@ -556,7 +556,7 @@ cc = ["@davidtwco", "@compiler-errors", "@JohnTitor", "@TaKO8Ki"]
[mentions."compiler/rustc_smir"] [mentions."compiler/rustc_smir"]
message = "This PR changes Stable MIR" message = "This PR changes Stable MIR"
cc = ["@oli-obk", "@celinval", "@spastorino"] cc = ["@oli-obk", "@celinval", "@spastorino", "@ouz-a"]
[mentions."compiler/stable_mir"] [mentions."compiler/stable_mir"]
message = "This PR changes Stable MIR" message = "This PR changes Stable MIR"