about summary refs log tree commit diff
diff options
context:
space:
mode:
-rw-r--r--src/librustdoc/passes/collect_intra_doc_links.rs29
-rw-r--r--tests/rustdoc-ui/intra-doc/errors.rs16
-rw-r--r--tests/rustdoc-ui/intra-doc/errors.stderr14
3 files changed, 54 insertions, 5 deletions
diff --git a/src/librustdoc/passes/collect_intra_doc_links.rs b/src/librustdoc/passes/collect_intra_doc_links.rs
index 692adcf0a80..62e190b4bd8 100644
--- a/src/librustdoc/passes/collect_intra_doc_links.rs
+++ b/src/librustdoc/passes/collect_intra_doc_links.rs
@@ -297,7 +297,8 @@ impl<'a, 'tcx> LinkCollector<'a, 'tcx> {
         match ty_res {
             Res::Def(DefKind::Enum, did) => match tcx.type_of(did).kind() {
                 ty::Adt(def, _) if def.is_enum() => {
-                    if let Some(field) = def.all_fields().find(|f| f.name == variant_field_name) {
+                    if let Some(variant) = def.variants().iter().find(|v| v.name == variant_name)
+                        && let Some(field) = variant.fields.iter().find(|f| f.name == variant_field_name) {
                         Ok((ty_res, field.did))
                     } else {
                         Err(UnresolvedPath {
@@ -1716,15 +1717,35 @@ fn resolution_failure(
 
                     // Otherwise, it must be an associated item or variant
                     let res = partial_res.expect("None case was handled by `last_found_module`");
-                    let kind = match res {
-                        Res::Def(kind, _) => Some(kind),
+                    let kind_did = match res {
+                        Res::Def(kind, did) => Some((kind, did)),
                         Res::Primitive(_) => None,
                     };
-                    let path_description = if let Some(kind) = kind {
+                    let is_struct_variant = |did| {
+                        if let ty::Adt(def, _) = tcx.type_of(did).kind()
+                        && def.is_enum()
+                        && let Some(variant) = def.variants().iter().find(|v| v.name == res.name(tcx)) {
+                            // ctor is `None` if variant is a struct
+                            variant.ctor.is_none()
+                        } else {
+                            false
+                        }
+                    };
+                    let path_description = if let Some((kind, did)) = kind_did {
                         match kind {
                             Mod | ForeignMod => "inner item",
                             Struct => "field or associated item",
                             Enum | Union => "variant or associated item",
+                            Variant if is_struct_variant(did) => {
+                                let variant = res.name(tcx);
+                                let note = format!("variant `{variant}` has no such field");
+                                if let Some(span) = sp {
+                                    diag.span_label(span, &note);
+                                } else {
+                                    diag.note(&note);
+                                }
+                                return;
+                            }
                             Variant
                             | Field
                             | Closure
diff --git a/tests/rustdoc-ui/intra-doc/errors.rs b/tests/rustdoc-ui/intra-doc/errors.rs
index b29f7c29b5d..95dd2b98e03 100644
--- a/tests/rustdoc-ui/intra-doc/errors.rs
+++ b/tests/rustdoc-ui/intra-doc/errors.rs
@@ -103,3 +103,19 @@ pub trait T {
 macro_rules! m {
     () => {};
 }
+
+///[`TestEnum::Variant1::field_name`]
+//~^ ERROR unresolved link
+//~| NOTE variant `Variant1` has no such field
+pub enum TestEnum {
+    Variant1 {},
+    Variant2 { field_name: u64 },
+}
+
+///[`TestEnumNoFields::Variant1::field_name`]
+//~^ ERROR unresolved link
+//~| NOTE `Variant1` is a variant, not a module or type, and cannot have associated items
+pub enum TestEnumNoFields {
+    Variant1 (),
+    Variant2 {},
+}
diff --git a/tests/rustdoc-ui/intra-doc/errors.stderr b/tests/rustdoc-ui/intra-doc/errors.stderr
index 9a1896fb0cd..1b2416d7da7 100644
--- a/tests/rustdoc-ui/intra-doc/errors.stderr
+++ b/tests/rustdoc-ui/intra-doc/errors.stderr
@@ -142,6 +142,18 @@ error: unresolved link to `T::h`
 LL | /// [T::h!]
    |      ^^^^^ the trait `T` has no macro named `h`
 
+error: unresolved link to `TestEnum::Variant1::field_name`
+  --> $DIR/errors.rs:107:6
+   |
+LL | ///[`TestEnum::Variant1::field_name`]
+   |      ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ variant `Variant1` has no such field
+
+error: unresolved link to `TestEnumNoFields::Variant1::field_name`
+  --> $DIR/errors.rs:115:6
+   |
+LL | ///[`TestEnumNoFields::Variant1::field_name`]
+   |      ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ `Variant1` is a variant, not a module or type, and cannot have associated items
+
 error: unresolved link to `m`
   --> $DIR/errors.rs:98:6
    |
@@ -153,5 +165,5 @@ help: to link to the macro, add an exclamation mark
 LL | /// [m!()]
    |       +
 
-error: aborting due to 20 previous errors
+error: aborting due to 22 previous errors