Auto merge of #148059 - Zalathar:rollup-zkk5prm, r=Zalathar

Rollup of 5 pull requests

Successful merges:

 - rust-lang/rust#148016 (Revert constification of `Borrow` and `Deref for Cow` due to inference failure)
 - rust-lang/rust#148021 ([rustdoc] Simplify module rendering and HTML tags handling)
 - rust-lang/rust#148039 (Add myself to the review rotation)
 - rust-lang/rust#148042 (test(frontmatter): Cover spaces between infostring parts)
 - rust-lang/rust#148054 (Streamline iterator chaining when computing successors.)

r? `@ghost`
`@rustbot` modify labels: rollup
This commit is contained in:
bors 2025-10-24 06:27:11 +00:00
commit 75948c8bb3
7 changed files with 206 additions and 165 deletions

View file

@ -501,6 +501,8 @@ pub use helper::*;
mod helper {
use super::*;
// Note: the methods below use a `slice.chain(Option).chain(Option)` pattern so that all paths
// produce an iterator with the same concrete type.
pub type Successors<'a> = impl DoubleEndedIterator<Item = BasicBlock> + 'a;
impl SwitchTargets {
@ -510,7 +512,7 @@ mod helper {
#[define_opaque(Successors)]
pub fn successors_for_value(&self, value: u128) -> Successors<'_> {
let target = self.target_for_value(value);
(&[]).into_iter().copied().chain(Some(target).into_iter().chain(None))
(&[]).into_iter().copied().chain(Some(target)).chain(None)
}
}
@ -522,10 +524,7 @@ mod helper {
match *self {
// 3-successors for async drop: target, unwind, dropline (parent coroutine drop)
Drop { target: ref t, unwind: UnwindAction::Cleanup(u), drop: Some(d), .. } => {
slice::from_ref(t)
.into_iter()
.copied()
.chain(Some(u).into_iter().chain(Some(d)))
slice::from_ref(t).into_iter().copied().chain(Some(u)).chain(Some(d))
}
// 2-successors
Call { target: Some(ref t), unwind: UnwindAction::Cleanup(u), .. }
@ -534,7 +533,7 @@ mod helper {
| Drop { target: ref t, unwind: _, drop: Some(u), .. }
| Assert { target: ref t, unwind: UnwindAction::Cleanup(u), .. }
| FalseUnwind { real_target: ref t, unwind: UnwindAction::Cleanup(u) } => {
slice::from_ref(t).into_iter().copied().chain(Some(u).into_iter().chain(None))
slice::from_ref(t).into_iter().copied().chain(Some(u)).chain(None)
}
// single successor
Goto { target: ref t }
@ -544,7 +543,7 @@ mod helper {
| Drop { target: ref t, unwind: _, .. }
| Assert { target: ref t, unwind: _, .. }
| FalseUnwind { real_target: ref t, unwind: _ } => {
slice::from_ref(t).into_iter().copied().chain(None.into_iter().chain(None))
slice::from_ref(t).into_iter().copied().chain(None).chain(None)
}
// No successors
UnwindResume
@ -554,23 +553,24 @@ mod helper {
| Unreachable
| TailCall { .. }
| Call { target: None, unwind: _, .. } => {
(&[]).into_iter().copied().chain(None.into_iter().chain(None))
(&[]).into_iter().copied().chain(None).chain(None)
}
// Multiple successors
InlineAsm { ref targets, unwind: UnwindAction::Cleanup(u), .. } => {
targets.iter().copied().chain(Some(u).into_iter().chain(None))
targets.iter().copied().chain(Some(u)).chain(None)
}
InlineAsm { ref targets, unwind: _, .. } => {
targets.iter().copied().chain(None.into_iter().chain(None))
targets.iter().copied().chain(None).chain(None)
}
SwitchInt { ref targets, .. } => {
targets.targets.iter().copied().chain(None.into_iter().chain(None))
targets.targets.iter().copied().chain(None).chain(None)
}
// FalseEdge
FalseEdge { ref real_target, imaginary_target } => slice::from_ref(real_target)
.into_iter()
.copied()
.chain(Some(imaginary_target).into_iter().chain(None)),
.chain(Some(imaginary_target))
.chain(None),
}
}

View file

@ -16,12 +16,13 @@ use crate::fmt;
#[cfg(not(no_global_oom_handling))]
use crate::string::String;
// FIXME(inference): const bounds removed due to inference regressions found by crater;
// see https://github.com/rust-lang/rust/issues/147964
// #[rustc_const_unstable(feature = "const_convert", issue = "143773")]
#[stable(feature = "rust1", since = "1.0.0")]
#[rustc_const_unstable(feature = "const_convert", issue = "143773")]
impl<'a, B: ?Sized> const Borrow<B> for Cow<'a, B>
where
B: ToOwned,
B::Owned: [const] Borrow<B>,
impl<'a, B: ?Sized + ToOwned> Borrow<B> for Cow<'a, B>
// where
// B::Owned: [const] Borrow<B>,
{
fn borrow(&self) -> &B {
&**self
@ -327,11 +328,13 @@ impl<B: ?Sized + ToOwned> Cow<'_, B> {
}
}
// FIXME(inference): const bounds removed due to inference regressions found by crater;
// see https://github.com/rust-lang/rust/issues/147964
// #[rustc_const_unstable(feature = "const_convert", issue = "143773")]
#[stable(feature = "rust1", since = "1.0.0")]
#[rustc_const_unstable(feature = "const_convert", issue = "143773")]
impl<B: ?Sized + ToOwned> const Deref for Cow<'_, B>
where
B::Owned: [const] Borrow<B>,
impl<B: ?Sized + ToOwned> Deref for Cow<'_, B>
// where
// B::Owned: [const] Borrow<B>,
{
type Target = B;

View file

@ -5,7 +5,7 @@ use std::iter;
use askama::Template;
use rustc_abi::VariantIdx;
use rustc_ast::join_path_syms;
use rustc_data_structures::fx::{FxHashMap, FxIndexSet};
use rustc_data_structures::fx::{FxHashMap, FxIndexMap, FxIndexSet};
use rustc_hir as hir;
use rustc_hir::def::CtorKind;
use rustc_hir::def_id::DefId;
@ -307,8 +307,12 @@ fn item_module(cx: &Context<'_>, item: &clean::Item, items: &[clean::Item]) -> i
fmt::from_fn(|w| {
write!(w, "{}", document(cx, item, None, HeadingOffset::H2))?;
let mut not_stripped_items =
items.iter().filter(|i| !i.is_stripped()).enumerate().collect::<Vec<_>>();
let mut not_stripped_items: FxIndexMap<ItemType, Vec<(usize, &clean::Item)>> =
FxIndexMap::default();
for (index, item) in items.iter().filter(|i| !i.is_stripped()).enumerate() {
not_stripped_items.entry(item.type_()).or_default().push((index, item));
}
// the order of item types in the listing
fn reorder(ty: ItemType) -> u8 {
@ -331,11 +335,6 @@ fn item_module(cx: &Context<'_>, item: &clean::Item, items: &[clean::Item]) -> i
}
fn cmp(i1: &clean::Item, i2: &clean::Item, tcx: TyCtxt<'_>) -> Ordering {
let rty1 = reorder(i1.type_());
let rty2 = reorder(i2.type_());
if rty1 != rty2 {
return rty1.cmp(&rty2);
}
let is_stable1 =
i1.stability(tcx).as_ref().map(|s| s.level.is_stable()).unwrap_or(true);
let is_stable2 =
@ -357,7 +356,9 @@ fn item_module(cx: &Context<'_>, item: &clean::Item, items: &[clean::Item]) -> i
match cx.shared.module_sorting {
ModuleSorting::Alphabetical => {
not_stripped_items.sort_by(|(_, i1), (_, i2)| cmp(i1, i2, tcx));
for items in not_stripped_items.values_mut() {
items.sort_by(|(_, i1), (_, i2)| cmp(i1, i2, tcx));
}
}
ModuleSorting::DeclarationOrder => {}
}
@ -380,155 +381,152 @@ fn item_module(cx: &Context<'_>, item: &clean::Item, items: &[clean::Item]) -> i
// can be identical even if the elements are different (mostly in imports).
// So in case this is an import, we keep everything by adding a "unique id"
// (which is the position in the vector).
not_stripped_items.dedup_by_key(|(idx, i)| {
(
i.item_id,
if i.name.is_some() { Some(full_path(cx, i)) } else { None },
i.type_(),
if i.is_import() { *idx } else { 0 },
)
});
for items in not_stripped_items.values_mut() {
items.dedup_by_key(|(idx, i)| {
(
i.item_id,
if i.name.is_some() { Some(full_path(cx, i)) } else { None },
i.type_(),
if i.is_import() { *idx } else { 0 },
)
});
}
debug!("{not_stripped_items:?}");
let mut last_section = None;
for (_, myitem) in &not_stripped_items {
let my_section = item_ty_to_section(myitem.type_());
if Some(my_section) != last_section {
if last_section.is_some() {
w.write_str(ITEM_TABLE_CLOSE)?;
}
last_section = Some(my_section);
let section_id = my_section.id();
let tag =
if section_id == "reexports" { REEXPORTS_TABLE_OPEN } else { ITEM_TABLE_OPEN };
write!(
w,
"{}",
write_section_heading(my_section.name(), &cx.derive_id(section_id), None, tag)
)?;
}
let mut types = not_stripped_items.keys().copied().collect::<Vec<_>>();
types.sort_unstable_by(|a, b| reorder(*a).cmp(&reorder(*b)));
match myitem.kind {
clean::ExternCrateItem { ref src } => {
use crate::html::format::print_anchor;
for type_ in types {
let my_section = item_ty_to_section(type_);
let tag = if my_section == super::ItemSection::Reexports {
REEXPORTS_TABLE_OPEN
} else {
ITEM_TABLE_OPEN
};
write!(
w,
"{}",
write_section_heading(my_section.name(), &cx.derive_id(my_section.id()), None, tag)
)?;
match *src {
Some(src) => {
write!(
w,
"<dt><code>{}extern crate {} as {};",
visibility_print_with_space(myitem, cx),
print_anchor(myitem.item_id.expect_def_id(), src, cx),
EscapeBodyTextWithWbr(myitem.name.unwrap().as_str())
)?;
}
None => {
write!(
w,
"<dt><code>{}extern crate {};",
visibility_print_with_space(myitem, cx),
print_anchor(
myitem.item_id.expect_def_id(),
myitem.name.unwrap(),
cx
)
)?;
}
}
w.write_str("</code></dt>")?;
}
for (_, myitem) in &not_stripped_items[&type_] {
match myitem.kind {
clean::ExternCrateItem { ref src } => {
use crate::html::format::print_anchor;
clean::ImportItem(ref import) => {
let stab_tags = import.source.did.map_or_else(String::new, |import_def_id| {
print_extra_info_tags(tcx, myitem, item, Some(import_def_id)).to_string()
});
let id = match import.kind {
clean::ImportKind::Simple(s) => {
format!(" id=\"{}\"", cx.derive_id(format!("reexport.{s}")))
}
clean::ImportKind::Glob => String::new(),
};
write!(
w,
"<dt{id}>\
<code>"
)?;
render_attributes_in_code(w, myitem, "", cx);
write!(
w,
"{vis}{imp}</code>{stab_tags}\
</dt>",
vis = visibility_print_with_space(myitem, cx),
imp = import.print(cx)
)?;
}
_ => {
if myitem.name.is_none() {
continue;
}
let unsafety_flag = match myitem.kind {
clean::FunctionItem(_) | clean::ForeignFunctionItem(..)
if myitem.fn_header(tcx).unwrap().safety
== hir::HeaderSafety::Normal(hir::Safety::Unsafe) =>
{
"<sup title=\"unsafe function\">⚠</sup>"
}
clean::ForeignStaticItem(_, hir::Safety::Unsafe) => {
"<sup title=\"unsafe static\">⚠</sup>"
}
_ => "",
};
let visibility_and_hidden = match myitem.visibility(tcx) {
Some(ty::Visibility::Restricted(_)) => {
if myitem.is_doc_hidden() {
// Don't separate with a space when there are two of them
"<span title=\"Restricted Visibility\">&nbsp;🔒</span><span title=\"Hidden item\">👻</span> "
} else {
"<span title=\"Restricted Visibility\">&nbsp;🔒</span> "
match *src {
Some(src) => {
write!(
w,
"<dt><code>{}extern crate {} as {};",
visibility_print_with_space(myitem, cx),
print_anchor(myitem.item_id.expect_def_id(), src, cx),
EscapeBodyTextWithWbr(myitem.name.unwrap().as_str())
)?;
}
None => {
write!(
w,
"<dt><code>{}extern crate {};",
visibility_print_with_space(myitem, cx),
print_anchor(
myitem.item_id.expect_def_id(),
myitem.name.unwrap(),
cx
)
)?;
}
}
_ if myitem.is_doc_hidden() => {
"<span title=\"Hidden item\">&nbsp;👻</span> "
}
clean::ImportItem(ref import) => {
let stab_tags =
import.source.did.map_or_else(String::new, |import_def_id| {
print_extra_info_tags(tcx, myitem, item, Some(import_def_id))
.to_string()
});
let id = match import.kind {
clean::ImportKind::Simple(s) => {
format!(" id=\"{}\"", cx.derive_id(format!("reexport.{s}")))
}
clean::ImportKind::Glob => String::new(),
};
write!(
w,
"<dt{id}>\
<code>"
)?;
render_attributes_in_code(w, myitem, "", cx);
write!(
w,
"{vis}{imp}</code>{stab_tags}\
</dt>",
vis = visibility_print_with_space(myitem, cx),
imp = import.print(cx)
)?;
}
_ => {
if myitem.name.is_none() {
continue;
}
_ => "",
};
let docs =
MarkdownSummaryLine(&myitem.doc_value(), &myitem.links(cx)).into_string();
let (docs_before, docs_after) =
if docs.is_empty() { ("", "") } else { ("<dd>", "</dd>") };
write!(
w,
"<dt>\
<a class=\"{class}\" href=\"{href}\" title=\"{title1} {title2}\">\
{name}\
</a>\
{visibility_and_hidden}\
{unsafety_flag}\
{stab_tags}\
</dt>\
{docs_before}{docs}{docs_after}",
name = EscapeBodyTextWithWbr(myitem.name.unwrap().as_str()),
visibility_and_hidden = visibility_and_hidden,
stab_tags = print_extra_info_tags(tcx, myitem, item, None),
class = myitem.type_(),
unsafety_flag = unsafety_flag,
href = print_item_path(myitem.type_(), myitem.name.unwrap().as_str()),
title1 = myitem.type_(),
title2 = full_path(cx, myitem),
)?;
let unsafety_flag = match myitem.kind {
clean::FunctionItem(_) | clean::ForeignFunctionItem(..)
if myitem.fn_header(tcx).unwrap().safety
== hir::HeaderSafety::Normal(hir::Safety::Unsafe) =>
{
"<sup title=\"unsafe function\">⚠</sup>"
}
clean::ForeignStaticItem(_, hir::Safety::Unsafe) => {
"<sup title=\"unsafe static\">⚠</sup>"
}
_ => "",
};
let visibility_and_hidden = match myitem.visibility(tcx) {
Some(ty::Visibility::Restricted(_)) => {
if myitem.is_doc_hidden() {
// Don't separate with a space when there are two of them
"<span title=\"Restricted Visibility\">&nbsp;🔒</span><span title=\"Hidden item\">👻</span> "
} else {
"<span title=\"Restricted Visibility\">&nbsp;🔒</span> "
}
}
_ if myitem.is_doc_hidden() => {
"<span title=\"Hidden item\">&nbsp;👻</span> "
}
_ => "",
};
let docs = MarkdownSummaryLine(&myitem.doc_value(), &myitem.links(cx))
.into_string();
let (docs_before, docs_after) =
if docs.is_empty() { ("", "") } else { ("<dd>", "</dd>") };
write!(
w,
"<dt>\
<a class=\"{class}\" href=\"{href}\" title=\"{title1} {title2}\">\
{name}\
</a>\
{visibility_and_hidden}\
{unsafety_flag}\
{stab_tags}\
</dt>\
{docs_before}{docs}{docs_after}",
name = EscapeBodyTextWithWbr(myitem.name.unwrap().as_str()),
visibility_and_hidden = visibility_and_hidden,
stab_tags = print_extra_info_tags(tcx, myitem, item, None),
class = type_,
unsafety_flag = unsafety_flag,
href = print_item_path(type_, myitem.name.unwrap().as_str()),
title1 = myitem.type_(),
title2 = full_path(cx, myitem),
)?;
}
}
}
}
if last_section.is_some() {
w.write_str(ITEM_TABLE_CLOSE)?;
}
Ok(())
})
}

View file

@ -0,0 +1,9 @@
--- cargo clippy
//~^ ERROR: invalid infostring for frontmatter
---
// infostrings cannot have spaces
#![feature(frontmatter)]
fn main() {}

View file

@ -0,0 +1,10 @@
error: invalid infostring for frontmatter
--> $DIR/space-in-infostring.rs:1:4
|
LL | --- cargo clippy
| ^^^^^^^^^^^^^
|
= note: frontmatter infostrings must be a single identifier immediately following the opening
error: aborting due to 1 previous error

View file

@ -0,0 +1,20 @@
//@ run-pass
// regression test for #147964:
// constification of these traits resulted in inference errors due to additional where clauses
use std::borrow::{Cow, Borrow};
pub fn generic_deref<'a, T: ToOwned<Owned = U>, U>(cow: Cow<'a, T>) {
let _: &T = &cow;
}
pub fn generic_borrow<'a, T: ToOwned<Owned = U>, U>(cow: Cow<'a, T>) {
let _: &T = cow.borrow();
}
pub fn generic_as_ref<'a, T: ToOwned<Owned = U>, U>(cow: Cow<'a, T>) {
let _: &T = cow.as_ref();
}
fn main() {}

View file

@ -1370,6 +1370,7 @@ compiler = [
"@jackh726",
"@jieyouxu",
"@jdonszelmann",
"@JonathanBrouwer",
"@lcnr",
"@madsmtm",
"@Nadrieril",