diff --git a/src/librustdoc/passes/html_tags.rs b/src/librustdoc/passes/html_tags.rs
index 9caadef3dec..f047f6bb169 100644
--- a/src/librustdoc/passes/html_tags.rs
+++ b/src/librustdoc/passes/html_tags.rs
@@ -5,7 +5,7 @@ use crate::core::DocContext;
use crate::html::markdown::main_body_opts;
use crate::visit::DocVisitor;
-use pulldown_cmark::{Event, Parser, Tag};
+use pulldown_cmark::{BrokenLink, Event, LinkType, Parser, Tag};
use std::iter::Peekable;
use std::ops::Range;
@@ -249,7 +249,31 @@ impl<'a, 'tcx> DocVisitor for InvalidHtmlTagsLinter<'a, 'tcx> {
let mut is_in_comment = None;
let mut in_code_block = false;
- let p = Parser::new_ext(&dox, main_body_opts()).into_offset_iter();
+ let link_names = item.link_names(&self.cx.cache);
+
+ let mut replacer = |broken_link: BrokenLink<'_>| {
+ if let Some(link) =
+ link_names.iter().find(|link| *link.original_text == *broken_link.reference)
+ {
+ Some((link.href.as_str().into(), link.new_text.as_str().into()))
+ } else if matches!(
+ &broken_link.link_type,
+ LinkType::Reference | LinkType::ReferenceUnknown
+ ) {
+ // If the link is shaped [like][this], suppress any broken HTML in the [this] part.
+ // The `broken_intra_doc_links` will report typos in there anyway.
+ Some((
+ broken_link.reference.to_string().into(),
+ broken_link.reference.to_string().into(),
+ ))
+ } else {
+ None
+ }
+ };
+
+ let p =
+ Parser::new_with_broken_link_callback(&dox, main_body_opts(), Some(&mut replacer))
+ .into_offset_iter();
for (event, range) in p {
match event {
diff --git a/src/test/rustdoc-ui/intra-doc/html-as-generics-intra-doc.rs b/src/test/rustdoc-ui/intra-doc/html-as-generics-intra-doc.rs
new file mode 100644
index 00000000000..b5470c859fd
--- /dev/null
+++ b/src/test/rustdoc-ui/intra-doc/html-as-generics-intra-doc.rs
@@ -0,0 +1,25 @@
+#![deny(rustdoc::invalid_html_tags)]
+#![deny(rustdoc::broken_intra_doc_links)]
+
+pub struct ExistentStruct(T);
+
+/// This [test][ExistentStruct] thing!
+pub struct NoError;
+
+/// This [ExistentStruct] thing!
+//~^ ERROR unclosed HTML tag `i32`
+pub struct PartialErrorOnlyHtml;
+
+/// This [test][NonExistentStruct] thing!
+//~^ ERROR unresolved link
+pub struct PartialErrorOnlyResolve;
+
+/// This [NonExistentStruct2] thing!
+//~^ ERROR unclosed HTML tag `i32`
+//~| ERROR unresolved link
+pub struct YesError;
+
+/// This [NonExistentStruct3][] thing!
+//~^ ERROR unclosed HTML tag `i32`
+//~| ERROR unresolved link
+pub struct YesErrorCollapsed;
diff --git a/src/test/rustdoc-ui/intra-doc/html-as-generics-intra-doc.stderr b/src/test/rustdoc-ui/intra-doc/html-as-generics-intra-doc.stderr
new file mode 100644
index 00000000000..00fe229da40
--- /dev/null
+++ b/src/test/rustdoc-ui/intra-doc/html-as-generics-intra-doc.stderr
@@ -0,0 +1,69 @@
+error: unresolved link to `NonExistentStruct`
+ --> $DIR/html-as-generics-intra-doc.rs:13:17
+ |
+LL | /// This [test][NonExistentStruct] thing!
+ | ^^^^^^^^^^^^^^^^^^^^^^ no item named `NonExistentStruct` in scope
+ |
+note: the lint level is defined here
+ --> $DIR/html-as-generics-intra-doc.rs:2:9
+ |
+LL | #![deny(rustdoc::broken_intra_doc_links)]
+ | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+ = help: to escape `[` and `]` characters, add '\' before them like `\[` or `\]`
+
+error: unresolved link to `NonExistentStruct2`
+ --> $DIR/html-as-generics-intra-doc.rs:17:11
+ |
+LL | /// This [NonExistentStruct2] thing!
+ | ^^^^^^^^^^^^^^^^^^^^^^^ no item named `NonExistentStruct2` in scope
+ |
+ = help: to escape `[` and `]` characters, add '\' before them like `\[` or `\]`
+
+error: unresolved link to `NonExistentStruct3`
+ --> $DIR/html-as-generics-intra-doc.rs:22:11
+ |
+LL | /// This [NonExistentStruct3][] thing!
+ | ^^^^^^^^^^^^^^^^^^^^^^^ no item named `NonExistentStruct3` in scope
+ |
+ = help: to escape `[` and `]` characters, add '\' before them like `\[` or `\]`
+
+error: unclosed HTML tag `i32`
+ --> $DIR/html-as-generics-intra-doc.rs:9:25
+ |
+LL | /// This [ExistentStruct] thing!
+ | ^^^^^
+ |
+note: the lint level is defined here
+ --> $DIR/html-as-generics-intra-doc.rs:1:9
+ |
+LL | #![deny(rustdoc::invalid_html_tags)]
+ | ^^^^^^^^^^^^^^^^^^^^^^^^^^
+help: try marking as source code
+ |
+LL | /// This [`ExistentStruct`] thing!
+ | + +
+
+error: unclosed HTML tag `i32`
+ --> $DIR/html-as-generics-intra-doc.rs:17:29
+ |
+LL | /// This [NonExistentStruct2] thing!
+ | ^^^^^
+ |
+help: try marking as source code
+ |
+LL | /// This [`NonExistentStruct2`] thing!
+ | + +
+
+error: unclosed HTML tag `i32`
+ --> $DIR/html-as-generics-intra-doc.rs:22:29
+ |
+LL | /// This [NonExistentStruct3][] thing!
+ | ^^^^^
+ |
+help: try marking as source code
+ |
+LL | /// This [`NonExistentStruct3`][] thing!
+ | + +
+
+error: aborting due to 6 previous errors
+