about summary refs log tree commit diff
diff options
context:
space:
mode:
-rw-r--r--src/librustdoc/passes/collect_intra_doc_links.rs32
-rw-r--r--tests/rustdoc-ui/disambiguator-endswith-named-suffix.rs111
-rw-r--r--tests/rustdoc-ui/disambiguator-endswith-named-suffix.stderr395
-rw-r--r--tests/rustdoc-ui/disambiguator-macro-endswith-exclamatory.rs11
-rw-r--r--tests/rustdoc-ui/disambiguator-macro-endswith-exclamatory.stderr11
5 files changed, 552 insertions, 8 deletions
diff --git a/src/librustdoc/passes/collect_intra_doc_links.rs b/src/librustdoc/passes/collect_intra_doc_links.rs
index 440b02a1fa7..37f7e7ed385 100644
--- a/src/librustdoc/passes/collect_intra_doc_links.rs
+++ b/src/librustdoc/passes/collect_intra_doc_links.rs
@@ -1507,6 +1507,15 @@ impl Disambiguator {
     fn from_str(link: &str) -> Result<Option<(Self, &str, &str)>, (String, Range<usize>)> {
         use Disambiguator::{Kind, Namespace as NS, Primitive};
 
+        let suffixes = [
+            // If you update this list, please also update the relevant rustdoc book section!
+            ("!()", DefKind::Macro(MacroKind::Bang)),
+            ("!{}", DefKind::Macro(MacroKind::Bang)),
+            ("![]", DefKind::Macro(MacroKind::Bang)),
+            ("()", DefKind::Fn),
+            ("!", DefKind::Macro(MacroKind::Bang)),
+        ];
+
         if let Some(idx) = link.find('@') {
             let (prefix, rest) = link.split_at(idx);
             let d = match prefix {
@@ -1530,16 +1539,23 @@ impl Disambiguator {
                 "prim" | "primitive" => Primitive,
                 _ => return Err((format!("unknown disambiguator `{prefix}`"), 0..idx)),
             };
+
+            for (suffix, kind) in suffixes {
+                if let Some(path_str) = rest.strip_suffix(suffix) {
+                    if d.ns() != Kind(kind).ns() {
+                        return Err((
+                            format!("unmatched disambiguator `{prefix}` and suffix `{suffix}`"),
+                            0..idx,
+                        ));
+                    } else if path_str.len() > 1 {
+                        // path_str != "@"
+                        return Ok(Some((d, &path_str[1..], &rest[1..])));
+                    }
+                }
+            }
+
             Ok(Some((d, &rest[1..], &rest[1..])))
         } else {
-            let suffixes = [
-                // If you update this list, please also update the relevant rustdoc book section!
-                ("!()", DefKind::Macro(MacroKind::Bang)),
-                ("!{}", DefKind::Macro(MacroKind::Bang)),
-                ("![]", DefKind::Macro(MacroKind::Bang)),
-                ("()", DefKind::Fn),
-                ("!", DefKind::Macro(MacroKind::Bang)),
-            ];
             for (suffix, kind) in suffixes {
                 if let Some(path_str) = link.strip_suffix(suffix) {
                     // Avoid turning `!` or `()` into an empty string
diff --git a/tests/rustdoc-ui/disambiguator-endswith-named-suffix.rs b/tests/rustdoc-ui/disambiguator-endswith-named-suffix.rs
new file mode 100644
index 00000000000..c3da1fdd7cc
--- /dev/null
+++ b/tests/rustdoc-ui/disambiguator-endswith-named-suffix.rs
@@ -0,0 +1,111 @@
+//@ check-pass
+//@ normalize-stderr-test: "nightly|beta|1\.[0-9][0-9]\.[0-9]" -> "$$CHANNEL"
+
+//! [struct@m!()]   //~ WARN: unmatched disambiguator `struct` and suffix `!()`
+//! [struct@m!{}]
+//! [struct@m![]]
+//! [struct@f()]    //~ WARN: unmatched disambiguator `struct` and suffix `()`
+//! [struct@m!]     //~ WARN: unmatched disambiguator `struct` and suffix `!`
+//!
+//! [enum@m!()]     //~ WARN: unmatched disambiguator `enum` and suffix `!()`
+//! [enum@m!{}]
+//! [enum@m![]]
+//! [enum@f()]      //~ WARN: unmatched disambiguator `enum` and suffix `()`
+//! [enum@m!]       //~ WARN: unmatched disambiguator `enum` and suffix `!`
+//!
+//! [trait@m!()]    //~ WARN: unmatched disambiguator `trait` and suffix `!()`
+//! [trait@m!{}]
+//! [trait@m![]]
+//! [trait@f()]     //~ WARN: unmatched disambiguator `trait` and suffix `()`
+//! [trait@m!]      //~ WARN: unmatched disambiguator `trait` and suffix `!`
+//!
+//! [module@m!()]   //~ WARN: unmatched disambiguator `module` and suffix `!()`
+//! [module@m!{}]
+//! [module@m![]]
+//! [module@f()]    //~ WARN: unmatched disambiguator `module` and suffix `()`
+//! [module@m!]     //~ WARN: unmatched disambiguator `module` and suffix `!`
+//!
+//! [mod@m!()]      //~ WARN: unmatched disambiguator `mod` and suffix `!()`
+//! [mod@m!{}]
+//! [mod@m![]]
+//! [mod@f()]       //~ WARN: unmatched disambiguator `mod` and suffix `()`
+//! [mod@m!]        //~ WARN: unmatched disambiguator `mod` and suffix `!`
+//!
+//! [const@m!()]    //~ WARN: unmatched disambiguator `const` and suffix `!()`
+//! [const@m!{}]
+//! [const@m![]]
+//! [const@f()]     //~ WARN: incompatible link kind for `f`
+//! [const@m!]      //~ WARN: unmatched disambiguator `const` and suffix `!`
+//!
+//! [constant@m!()]   //~ WARN: unmatched disambiguator `constant` and suffix `!()`
+//! [constant@m!{}]
+//! [constant@m![]]
+//! [constant@f()]    //~ WARN: incompatible link kind for `f`
+//! [constant@m!]     //~ WARN: unmatched disambiguator `constant` and suffix `!`
+//!
+//! [static@m!()]   //~ WARN: unmatched disambiguator `static` and suffix `!()`
+//! [static@m!{}]
+//! [static@m![]]
+//! [static@f()]    //~ WARN: incompatible link kind for `f`
+//! [static@m!]     //~ WARN: unmatched disambiguator `static` and suffix `!`
+//!
+//! [function@m!()]   //~ WARN: unmatched disambiguator `function` and suffix `!()`
+//! [function@m!{}]
+//! [function@m![]]
+//! [function@f()]
+//! [function@m!]     //~ WARN: unmatched disambiguator `function` and suffix `!`
+//!
+//! [fn@m!()]   //~ WARN: unmatched disambiguator `fn` and suffix `!()`
+//! [fn@m!{}]
+//! [fn@m![]]
+//! [fn@f()]
+//! [fn@m!]     //~ WARN: unmatched disambiguator `fn` and suffix `!`
+//!
+//! [method@m!()]   //~ WARN: unmatched disambiguator `method` and suffix `!()`
+//! [method@m!{}]
+//! [method@m![]]
+//! [method@f()]
+//! [method@m!]     //~ WARN: unmatched disambiguator `method` and suffix `!`
+//!
+//! [derive@m!()]   //~ WARN: incompatible link kind for `m`
+//! [derive@m!{}]   //~ WARN: incompatible link kind for `m`
+//! [derive@m![]]
+//! [derive@f()]    //~ WARN: unmatched disambiguator `derive` and suffix `()`
+//! [derive@m!]     //~ WARN: incompatible link kind for `m`
+//!
+//! [type@m!()]   //~ WARN: unmatched disambiguator `type` and suffix `!()`
+//! [type@m!{}]
+//! [type@m![]]
+//! [type@f()]    //~ WARN: unmatched disambiguator `type` and suffix `()`
+//! [type@m!]     //~ WARN: unmatched disambiguator `type` and suffix `!`
+//!
+//! [value@m!()]   //~ WARN: unmatched disambiguator `value` and suffix `!()`
+//! [value@m!{}]
+//! [value@m![]]
+//! [value@f()]
+//! [value@m!]     //~ WARN: unmatched disambiguator `value` and suffix `!`
+//!
+//! [macro@m!()]
+//! [macro@m!{}]
+//! [macro@m![]]
+//! [macro@f()]    //~ WARN: unmatched disambiguator `macro` and suffix `()`
+//! [macro@m!]
+//!
+//! [prim@m!()]   //~ WARN: unmatched disambiguator `prim` and suffix `!()`
+//! [prim@m!{}]
+//! [prim@m![]]
+//! [prim@f()]    //~ WARN: unmatched disambiguator `prim` and suffix `()`
+//! [prim@m!]     //~ WARN: unmatched disambiguator `prim` and suffix `!`
+//!
+//! [primitive@m!()]   //~ WARN: unmatched disambiguator `primitive` and suffix `!()`
+//! [primitive@m!{}]
+//! [primitive@m![]]
+//! [primitive@f()]    //~ WARN: unmatched disambiguator `primitive` and suffix `()`
+//! [primitive@m!]     //~ WARN: unmatched disambiguator `primitive` and suffix `!`
+
+#[macro_export]
+macro_rules! m {
+    () => {};
+}
+
+pub fn f() {}
diff --git a/tests/rustdoc-ui/disambiguator-endswith-named-suffix.stderr b/tests/rustdoc-ui/disambiguator-endswith-named-suffix.stderr
new file mode 100644
index 00000000000..f4e40a48873
--- /dev/null
+++ b/tests/rustdoc-ui/disambiguator-endswith-named-suffix.stderr
@@ -0,0 +1,395 @@
+warning: unmatched disambiguator `struct` and suffix `!()`
+  --> $DIR/disambiguator-endswith-named-suffix.rs:4:6
+   |
+LL | //! [struct@m!()]
+   |      ^^^^^^
+   |
+   = note: see https://doc.rust-lang.org/$CHANNEL/rustdoc/write-documentation/linking-to-items-by-name.html#namespaces-and-disambiguators for more info about disambiguators
+   = note: `#[warn(rustdoc::broken_intra_doc_links)]` on by default
+
+warning: unmatched disambiguator `struct` and suffix `()`
+  --> $DIR/disambiguator-endswith-named-suffix.rs:7:6
+   |
+LL | //! [struct@f()]
+   |      ^^^^^^
+   |
+   = note: see https://doc.rust-lang.org/$CHANNEL/rustdoc/write-documentation/linking-to-items-by-name.html#namespaces-and-disambiguators for more info about disambiguators
+
+warning: unmatched disambiguator `struct` and suffix `!`
+  --> $DIR/disambiguator-endswith-named-suffix.rs:8:6
+   |
+LL | //! [struct@m!]
+   |      ^^^^^^
+   |
+   = note: see https://doc.rust-lang.org/$CHANNEL/rustdoc/write-documentation/linking-to-items-by-name.html#namespaces-and-disambiguators for more info about disambiguators
+
+warning: unmatched disambiguator `enum` and suffix `!()`
+  --> $DIR/disambiguator-endswith-named-suffix.rs:10:6
+   |
+LL | //! [enum@m!()]
+   |      ^^^^
+   |
+   = note: see https://doc.rust-lang.org/$CHANNEL/rustdoc/write-documentation/linking-to-items-by-name.html#namespaces-and-disambiguators for more info about disambiguators
+
+warning: unmatched disambiguator `enum` and suffix `()`
+  --> $DIR/disambiguator-endswith-named-suffix.rs:13:6
+   |
+LL | //! [enum@f()]
+   |      ^^^^
+   |
+   = note: see https://doc.rust-lang.org/$CHANNEL/rustdoc/write-documentation/linking-to-items-by-name.html#namespaces-and-disambiguators for more info about disambiguators
+
+warning: unmatched disambiguator `enum` and suffix `!`
+  --> $DIR/disambiguator-endswith-named-suffix.rs:14:6
+   |
+LL | //! [enum@m!]
+   |      ^^^^
+   |
+   = note: see https://doc.rust-lang.org/$CHANNEL/rustdoc/write-documentation/linking-to-items-by-name.html#namespaces-and-disambiguators for more info about disambiguators
+
+warning: unmatched disambiguator `trait` and suffix `!()`
+  --> $DIR/disambiguator-endswith-named-suffix.rs:16:6
+   |
+LL | //! [trait@m!()]
+   |      ^^^^^
+   |
+   = note: see https://doc.rust-lang.org/$CHANNEL/rustdoc/write-documentation/linking-to-items-by-name.html#namespaces-and-disambiguators for more info about disambiguators
+
+warning: unmatched disambiguator `trait` and suffix `()`
+  --> $DIR/disambiguator-endswith-named-suffix.rs:19:6
+   |
+LL | //! [trait@f()]
+   |      ^^^^^
+   |
+   = note: see https://doc.rust-lang.org/$CHANNEL/rustdoc/write-documentation/linking-to-items-by-name.html#namespaces-and-disambiguators for more info about disambiguators
+
+warning: unmatched disambiguator `trait` and suffix `!`
+  --> $DIR/disambiguator-endswith-named-suffix.rs:20:6
+   |
+LL | //! [trait@m!]
+   |      ^^^^^
+   |
+   = note: see https://doc.rust-lang.org/$CHANNEL/rustdoc/write-documentation/linking-to-items-by-name.html#namespaces-and-disambiguators for more info about disambiguators
+
+warning: unmatched disambiguator `module` and suffix `!()`
+  --> $DIR/disambiguator-endswith-named-suffix.rs:22:6
+   |
+LL | //! [module@m!()]
+   |      ^^^^^^
+   |
+   = note: see https://doc.rust-lang.org/$CHANNEL/rustdoc/write-documentation/linking-to-items-by-name.html#namespaces-and-disambiguators for more info about disambiguators
+
+warning: unmatched disambiguator `module` and suffix `()`
+  --> $DIR/disambiguator-endswith-named-suffix.rs:25:6
+   |
+LL | //! [module@f()]
+   |      ^^^^^^
+   |
+   = note: see https://doc.rust-lang.org/$CHANNEL/rustdoc/write-documentation/linking-to-items-by-name.html#namespaces-and-disambiguators for more info about disambiguators
+
+warning: unmatched disambiguator `module` and suffix `!`
+  --> $DIR/disambiguator-endswith-named-suffix.rs:26:6
+   |
+LL | //! [module@m!]
+   |      ^^^^^^
+   |
+   = note: see https://doc.rust-lang.org/$CHANNEL/rustdoc/write-documentation/linking-to-items-by-name.html#namespaces-and-disambiguators for more info about disambiguators
+
+warning: unmatched disambiguator `mod` and suffix `!()`
+  --> $DIR/disambiguator-endswith-named-suffix.rs:28:6
+   |
+LL | //! [mod@m!()]
+   |      ^^^
+   |
+   = note: see https://doc.rust-lang.org/$CHANNEL/rustdoc/write-documentation/linking-to-items-by-name.html#namespaces-and-disambiguators for more info about disambiguators
+
+warning: unmatched disambiguator `mod` and suffix `()`
+  --> $DIR/disambiguator-endswith-named-suffix.rs:31:6
+   |
+LL | //! [mod@f()]
+   |      ^^^
+   |
+   = note: see https://doc.rust-lang.org/$CHANNEL/rustdoc/write-documentation/linking-to-items-by-name.html#namespaces-and-disambiguators for more info about disambiguators
+
+warning: unmatched disambiguator `mod` and suffix `!`
+  --> $DIR/disambiguator-endswith-named-suffix.rs:32:6
+   |
+LL | //! [mod@m!]
+   |      ^^^
+   |
+   = note: see https://doc.rust-lang.org/$CHANNEL/rustdoc/write-documentation/linking-to-items-by-name.html#namespaces-and-disambiguators for more info about disambiguators
+
+warning: unmatched disambiguator `const` and suffix `!()`
+  --> $DIR/disambiguator-endswith-named-suffix.rs:34:6
+   |
+LL | //! [const@m!()]
+   |      ^^^^^
+   |
+   = note: see https://doc.rust-lang.org/$CHANNEL/rustdoc/write-documentation/linking-to-items-by-name.html#namespaces-and-disambiguators for more info about disambiguators
+
+warning: incompatible link kind for `f`
+  --> $DIR/disambiguator-endswith-named-suffix.rs:37:6
+   |
+LL | //! [const@f()]
+   |      ^^^^^^^^^ this link resolved to a function, which is not a constant
+   |
+help: to link to the function, add parentheses
+   |
+LL - //! [const@f()]
+LL + //! [f()]
+   |
+
+warning: unmatched disambiguator `const` and suffix `!`
+  --> $DIR/disambiguator-endswith-named-suffix.rs:38:6
+   |
+LL | //! [const@m!]
+   |      ^^^^^
+   |
+   = note: see https://doc.rust-lang.org/$CHANNEL/rustdoc/write-documentation/linking-to-items-by-name.html#namespaces-and-disambiguators for more info about disambiguators
+
+warning: unmatched disambiguator `constant` and suffix `!()`
+  --> $DIR/disambiguator-endswith-named-suffix.rs:40:6
+   |
+LL | //! [constant@m!()]
+   |      ^^^^^^^^
+   |
+   = note: see https://doc.rust-lang.org/$CHANNEL/rustdoc/write-documentation/linking-to-items-by-name.html#namespaces-and-disambiguators for more info about disambiguators
+
+warning: incompatible link kind for `f`
+  --> $DIR/disambiguator-endswith-named-suffix.rs:43:6
+   |
+LL | //! [constant@f()]
+   |      ^^^^^^^^^^^^ this link resolved to a function, which is not a constant
+   |
+help: to link to the function, add parentheses
+   |
+LL - //! [constant@f()]
+LL + //! [f()]
+   |
+
+warning: unmatched disambiguator `constant` and suffix `!`
+  --> $DIR/disambiguator-endswith-named-suffix.rs:44:6
+   |
+LL | //! [constant@m!]
+   |      ^^^^^^^^
+   |
+   = note: see https://doc.rust-lang.org/$CHANNEL/rustdoc/write-documentation/linking-to-items-by-name.html#namespaces-and-disambiguators for more info about disambiguators
+
+warning: unmatched disambiguator `static` and suffix `!()`
+  --> $DIR/disambiguator-endswith-named-suffix.rs:46:6
+   |
+LL | //! [static@m!()]
+   |      ^^^^^^
+   |
+   = note: see https://doc.rust-lang.org/$CHANNEL/rustdoc/write-documentation/linking-to-items-by-name.html#namespaces-and-disambiguators for more info about disambiguators
+
+warning: incompatible link kind for `f`
+  --> $DIR/disambiguator-endswith-named-suffix.rs:49:6
+   |
+LL | //! [static@f()]
+   |      ^^^^^^^^^^ this link resolved to a function, which is not a static
+   |
+help: to link to the function, add parentheses
+   |
+LL - //! [static@f()]
+LL + //! [f()]
+   |
+
+warning: unmatched disambiguator `static` and suffix `!`
+  --> $DIR/disambiguator-endswith-named-suffix.rs:50:6
+   |
+LL | //! [static@m!]
+   |      ^^^^^^
+   |
+   = note: see https://doc.rust-lang.org/$CHANNEL/rustdoc/write-documentation/linking-to-items-by-name.html#namespaces-and-disambiguators for more info about disambiguators
+
+warning: unmatched disambiguator `function` and suffix `!()`
+  --> $DIR/disambiguator-endswith-named-suffix.rs:52:6
+   |
+LL | //! [function@m!()]
+   |      ^^^^^^^^
+   |
+   = note: see https://doc.rust-lang.org/$CHANNEL/rustdoc/write-documentation/linking-to-items-by-name.html#namespaces-and-disambiguators for more info about disambiguators
+
+warning: unmatched disambiguator `function` and suffix `!`
+  --> $DIR/disambiguator-endswith-named-suffix.rs:56:6
+   |
+LL | //! [function@m!]
+   |      ^^^^^^^^
+   |
+   = note: see https://doc.rust-lang.org/$CHANNEL/rustdoc/write-documentation/linking-to-items-by-name.html#namespaces-and-disambiguators for more info about disambiguators
+
+warning: unmatched disambiguator `fn` and suffix `!()`
+  --> $DIR/disambiguator-endswith-named-suffix.rs:58:6
+   |
+LL | //! [fn@m!()]
+   |      ^^
+   |
+   = note: see https://doc.rust-lang.org/$CHANNEL/rustdoc/write-documentation/linking-to-items-by-name.html#namespaces-and-disambiguators for more info about disambiguators
+
+warning: unmatched disambiguator `fn` and suffix `!`
+  --> $DIR/disambiguator-endswith-named-suffix.rs:62:6
+   |
+LL | //! [fn@m!]
+   |      ^^
+   |
+   = note: see https://doc.rust-lang.org/$CHANNEL/rustdoc/write-documentation/linking-to-items-by-name.html#namespaces-and-disambiguators for more info about disambiguators
+
+warning: unmatched disambiguator `method` and suffix `!()`
+  --> $DIR/disambiguator-endswith-named-suffix.rs:64:6
+   |
+LL | //! [method@m!()]
+   |      ^^^^^^
+   |
+   = note: see https://doc.rust-lang.org/$CHANNEL/rustdoc/write-documentation/linking-to-items-by-name.html#namespaces-and-disambiguators for more info about disambiguators
+
+warning: unmatched disambiguator `method` and suffix `!`
+  --> $DIR/disambiguator-endswith-named-suffix.rs:68:6
+   |
+LL | //! [method@m!]
+   |      ^^^^^^
+   |
+   = note: see https://doc.rust-lang.org/$CHANNEL/rustdoc/write-documentation/linking-to-items-by-name.html#namespaces-and-disambiguators for more info about disambiguators
+
+warning: incompatible link kind for `m`
+  --> $DIR/disambiguator-endswith-named-suffix.rs:70:6
+   |
+LL | //! [derive@m!()]
+   |      ^^^^^^^^^^^ this link resolved to a macro, which is not a derive macro
+   |
+help: to link to the macro, add an exclamation mark
+   |
+LL - //! [derive@m!()]
+LL + //! [m!!()]
+   |
+
+warning: incompatible link kind for `m`
+  --> $DIR/disambiguator-endswith-named-suffix.rs:71:6
+   |
+LL | //! [derive@m!{}]
+   |      ^^^^^^^^^^^ this link resolved to a macro, which is not a derive macro
+   |
+help: to link to the macro, add an exclamation mark
+   |
+LL - //! [derive@m!{}]
+LL + //! [m!!{}]
+   |
+
+warning: unmatched disambiguator `derive` and suffix `()`
+  --> $DIR/disambiguator-endswith-named-suffix.rs:73:6
+   |
+LL | //! [derive@f()]
+   |      ^^^^^^
+   |
+   = note: see https://doc.rust-lang.org/$CHANNEL/rustdoc/write-documentation/linking-to-items-by-name.html#namespaces-and-disambiguators for more info about disambiguators
+
+warning: incompatible link kind for `m`
+  --> $DIR/disambiguator-endswith-named-suffix.rs:74:6
+   |
+LL | //! [derive@m!]
+   |      ^^^^^^^^^ this link resolved to a macro, which is not a derive macro
+   |
+help: to link to the macro, add an exclamation mark
+   |
+LL - //! [derive@m!]
+LL + //! [m!!]
+   |
+
+warning: unmatched disambiguator `type` and suffix `!()`
+  --> $DIR/disambiguator-endswith-named-suffix.rs:76:6
+   |
+LL | //! [type@m!()]
+   |      ^^^^
+   |
+   = note: see https://doc.rust-lang.org/$CHANNEL/rustdoc/write-documentation/linking-to-items-by-name.html#namespaces-and-disambiguators for more info about disambiguators
+
+warning: unmatched disambiguator `type` and suffix `()`
+  --> $DIR/disambiguator-endswith-named-suffix.rs:79:6
+   |
+LL | //! [type@f()]
+   |      ^^^^
+   |
+   = note: see https://doc.rust-lang.org/$CHANNEL/rustdoc/write-documentation/linking-to-items-by-name.html#namespaces-and-disambiguators for more info about disambiguators
+
+warning: unmatched disambiguator `type` and suffix `!`
+  --> $DIR/disambiguator-endswith-named-suffix.rs:80:6
+   |
+LL | //! [type@m!]
+   |      ^^^^
+   |
+   = note: see https://doc.rust-lang.org/$CHANNEL/rustdoc/write-documentation/linking-to-items-by-name.html#namespaces-and-disambiguators for more info about disambiguators
+
+warning: unmatched disambiguator `value` and suffix `!()`
+  --> $DIR/disambiguator-endswith-named-suffix.rs:82:6
+   |
+LL | //! [value@m!()]
+   |      ^^^^^
+   |
+   = note: see https://doc.rust-lang.org/$CHANNEL/rustdoc/write-documentation/linking-to-items-by-name.html#namespaces-and-disambiguators for more info about disambiguators
+
+warning: unmatched disambiguator `value` and suffix `!`
+  --> $DIR/disambiguator-endswith-named-suffix.rs:86:6
+   |
+LL | //! [value@m!]
+   |      ^^^^^
+   |
+   = note: see https://doc.rust-lang.org/$CHANNEL/rustdoc/write-documentation/linking-to-items-by-name.html#namespaces-and-disambiguators for more info about disambiguators
+
+warning: unmatched disambiguator `macro` and suffix `()`
+  --> $DIR/disambiguator-endswith-named-suffix.rs:91:6
+   |
+LL | //! [macro@f()]
+   |      ^^^^^
+   |
+   = note: see https://doc.rust-lang.org/$CHANNEL/rustdoc/write-documentation/linking-to-items-by-name.html#namespaces-and-disambiguators for more info about disambiguators
+
+warning: unmatched disambiguator `prim` and suffix `!()`
+  --> $DIR/disambiguator-endswith-named-suffix.rs:94:6
+   |
+LL | //! [prim@m!()]
+   |      ^^^^
+   |
+   = note: see https://doc.rust-lang.org/$CHANNEL/rustdoc/write-documentation/linking-to-items-by-name.html#namespaces-and-disambiguators for more info about disambiguators
+
+warning: unmatched disambiguator `prim` and suffix `()`
+  --> $DIR/disambiguator-endswith-named-suffix.rs:97:6
+   |
+LL | //! [prim@f()]
+   |      ^^^^
+   |
+   = note: see https://doc.rust-lang.org/$CHANNEL/rustdoc/write-documentation/linking-to-items-by-name.html#namespaces-and-disambiguators for more info about disambiguators
+
+warning: unmatched disambiguator `prim` and suffix `!`
+  --> $DIR/disambiguator-endswith-named-suffix.rs:98:6
+   |
+LL | //! [prim@m!]
+   |      ^^^^
+   |
+   = note: see https://doc.rust-lang.org/$CHANNEL/rustdoc/write-documentation/linking-to-items-by-name.html#namespaces-and-disambiguators for more info about disambiguators
+
+warning: unmatched disambiguator `primitive` and suffix `!()`
+  --> $DIR/disambiguator-endswith-named-suffix.rs:100:6
+   |
+LL | //! [primitive@m!()]
+   |      ^^^^^^^^^
+   |
+   = note: see https://doc.rust-lang.org/$CHANNEL/rustdoc/write-documentation/linking-to-items-by-name.html#namespaces-and-disambiguators for more info about disambiguators
+
+warning: unmatched disambiguator `primitive` and suffix `()`
+  --> $DIR/disambiguator-endswith-named-suffix.rs:103:6
+   |
+LL | //! [primitive@f()]
+   |      ^^^^^^^^^
+   |
+   = note: see https://doc.rust-lang.org/$CHANNEL/rustdoc/write-documentation/linking-to-items-by-name.html#namespaces-and-disambiguators for more info about disambiguators
+
+warning: unmatched disambiguator `primitive` and suffix `!`
+  --> $DIR/disambiguator-endswith-named-suffix.rs:104:6
+   |
+LL | //! [primitive@m!]
+   |      ^^^^^^^^^
+   |
+   = note: see https://doc.rust-lang.org/$CHANNEL/rustdoc/write-documentation/linking-to-items-by-name.html#namespaces-and-disambiguators for more info about disambiguators
+
+warning: 46 warnings emitted
+
diff --git a/tests/rustdoc-ui/disambiguator-macro-endswith-exclamatory.rs b/tests/rustdoc-ui/disambiguator-macro-endswith-exclamatory.rs
new file mode 100644
index 00000000000..b955090e894
--- /dev/null
+++ b/tests/rustdoc-ui/disambiguator-macro-endswith-exclamatory.rs
@@ -0,0 +1,11 @@
+//@ check-pass
+
+//! [macro@m!] //~ WARN: unresolved link to `m`
+
+//issue#126986
+
+macro_rules! m {
+    () => {};
+}
+
+fn main() {}
diff --git a/tests/rustdoc-ui/disambiguator-macro-endswith-exclamatory.stderr b/tests/rustdoc-ui/disambiguator-macro-endswith-exclamatory.stderr
new file mode 100644
index 00000000000..2ada7f1a4be
--- /dev/null
+++ b/tests/rustdoc-ui/disambiguator-macro-endswith-exclamatory.stderr
@@ -0,0 +1,11 @@
+warning: unresolved link to `m`
+  --> $DIR/disambiguator-macro-endswith-exclamatory.rs:3:6
+   |
+LL | //! [macro@m!]
+   |      ^^^^^^^^ no item named `m` in scope
+   |
+   = note: `macro_rules` named `m` exists in this crate, but it is not in scope at this link's location
+   = note: `#[warn(rustdoc::broken_intra_doc_links)]` on by default
+
+warning: 1 warning emitted
+