diff --git a/src/librustdoc/html/markdown/footnotes.rs b/src/librustdoc/html/markdown/footnotes.rs
index ded0585ddccda..60b2cf268accc 100644
--- a/src/librustdoc/html/markdown/footnotes.rs
+++ b/src/librustdoc/html/markdown/footnotes.rs
@@ -23,6 +23,8 @@ struct FootnoteDef<'a> {
content: Vec>,
/// The number that appears in the footnote reference and list.
id: usize,
+ /// The number of footnote references.
+ num_refs: usize,
}
impl<'a, I: Iterator- >> Footnotes<'a, I> {
@@ -33,21 +35,28 @@ impl<'a, I: Iterator
- >> Footnotes<'a, I> {
Footnotes { inner: iter, footnotes: FxIndexMap::default(), existing_footnotes, start_id }
}
- fn get_entry(&mut self, key: &str) -> (&mut Vec>, usize) {
+ fn get_entry(&mut self, key: &str) -> (&mut Vec>, usize, &mut usize) {
let new_id = self.footnotes.len() + 1 + self.start_id;
let key = key.to_owned();
- let FootnoteDef { content, id } =
- self.footnotes.entry(key).or_insert(FootnoteDef { content: Vec::new(), id: new_id });
+ let FootnoteDef { content, id, num_refs } = self
+ .footnotes
+ .entry(key)
+ .or_insert(FootnoteDef { content: Vec::new(), id: new_id, num_refs: 0 });
// Don't allow changing the ID of existing entrys, but allow changing the contents.
- (content, *id)
+ (content, *id, num_refs)
}
fn handle_footnote_reference(&mut self, reference: &CowStr<'a>) -> Event<'a> {
// When we see a reference (to a footnote we may not know) the definition of,
// reserve a number for it, and emit a link to that number.
- let (_, id) = self.get_entry(reference);
+ let (_, id, num_refs) = self.get_entry(reference);
+ *num_refs += 1;
+ let fnref_suffix = {
+ let num_refs = *num_refs;
+ if num_refs <= 1 { "".to_owned() } else { format!("-{num_refs}") }
+ };
let reference = format!(
- "{1}",
+ "{1}",
id,
// Although the ID count is for the whole page, the footnote reference
// are local to the item so we make this ID "local" when displayed.
@@ -85,7 +94,7 @@ impl<'a, I: Iterator
- >> Iterator for Footnotes<'a, I> {
// When we see a footnote definition, collect the assocated content, and store
// that for rendering later.
let content = self.collect_footnote_def();
- let (entry_content, _) = self.get_entry(&def);
+ let (entry_content, _, _) = self.get_entry(&def);
*entry_content = content;
}
Some(e) => return Some(e),
@@ -113,7 +122,7 @@ fn render_footnotes_defs(mut footnotes: Vec>) -> String {
// browser generated for are right.
footnotes.sort_by_key(|x| x.id);
- for FootnoteDef { mut content, id } in footnotes {
+ for FootnoteDef { mut content, id, num_refs } in footnotes {
write!(ret, "").unwrap();
let mut is_paragraph = false;
if let Some(&Event::End(TagEnd::Paragraph)) = content.last() {
@@ -121,7 +130,16 @@ fn render_footnotes_defs(mut footnotes: Vec>) -> String {
is_paragraph = true;
}
html::push_html(&mut ret, content.into_iter());
- write!(ret, " ↩").unwrap();
+ if num_refs <= 1 {
+ write!(ret, " ↩").unwrap();
+ } else {
+ // There are multiple references to single footnote. Make the first
+ // back link a single "a" element to make touch region larger.
+ write!(ret, " ↩ 1").unwrap();
+ for refid in 2..=num_refs {
+ write!(ret, " {refid}").unwrap();
+ }
+ }
if is_paragraph {
ret.push_str("
");
}
diff --git a/tests/rustdoc/footnote-reference-ids.rs b/tests/rustdoc/footnote-reference-ids.rs
new file mode 100644
index 0000000000000..ffa04e1d7675d
--- /dev/null
+++ b/tests/rustdoc/footnote-reference-ids.rs
@@ -0,0 +1,23 @@
+// This test ensures that multiple references to a single footnote and
+// corresponding back links work as expected.
+
+#![crate_name = "foo"]
+
+//@ has 'foo/index.html'
+//@ has - '//*[@class="docblock"]/p/sup[@id="fnref1"]/a[@href="#fn1"]' '1'
+//@ has - '//*[@class="docblock"]/p/sup[@id="fnref2"]/a[@href="#fn2"]' '2'
+//@ has - '//*[@class="docblock"]/p/sup[@id="fnref2-2"]/a[@href="#fn2"]' '2'
+//@ has - '//li[@id="fn1"]/p' 'meow'
+//@ has - '//li[@id="fn1"]/p/a[@href="#fnref1"]' '↩'
+//@ has - '//li[@id="fn2"]/p' 'uwu'
+//@ has - '//li[@id="fn2"]/p/a[@href="#fnref2"]/sup' '1'
+//@ has - '//li[@id="fn2"]/p/sup/a[@href="#fnref2-2"]' '2'
+
+//! # Footnote, references and back links
+//!
+//! Single: [^a].
+//!
+//! Double: [^b] [^b].
+//!
+//! [^a]: meow
+//! [^b]: uwu
diff --git a/tests/rustdoc/footnote-reference-in-footnote-def.rs b/tests/rustdoc/footnote-reference-in-footnote-def.rs
index db3f9a59ef830..504d0bdb8f79f 100644
--- a/tests/rustdoc/footnote-reference-in-footnote-def.rs
+++ b/tests/rustdoc/footnote-reference-in-footnote-def.rs
@@ -9,7 +9,7 @@
//@ has - '//li[@id="fn1"]/p/sup[@id="fnref2"]/a[@href="#fn2"]' '2'
//@ has - '//li[@id="fn1"]//a[@href="#fn2"]' '2'
//@ has - '//li[@id="fn2"]/p' 'uwu'
-//@ has - '//li[@id="fn2"]/p/sup[@id="fnref1"]/a[@href="#fn1"]' '1'
+//@ has - '//li[@id="fn2"]/p/sup[@id="fnref1-2"]/a[@href="#fn1"]' '1'
//@ has - '//li[@id="fn2"]//a[@href="#fn1"]' '1'
//! # footnote-hell