about summary refs log tree commit diff
path: root/compiler/rustc_resolve/src
diff options
context:
space:
mode:
authorbors <bors@rust-lang.org>2025-08-02 05:09:31 +0000
committerbors <bors@rust-lang.org>2025-08-02 05:09:31 +0000
commit889701db1ff614160314734fe4138c2f820a95bb (patch)
tree73cf71993bf2f50f9f20e0013c86c41a969d947b /compiler/rustc_resolve/src
parentc23f07d8c56c51b5e634bda55daca2b073306340 (diff)
parent4b24c4bf23df8ae5c53669e3209b9f3074769b69 (diff)
downloadrust-889701db1ff614160314734fe4138c2f820a95bb.tar.gz
rust-889701db1ff614160314734fe4138c2f820a95bb.zip
Auto merge of #129183 - estebank:cfg-visitor, r=davidtwco
Detect more `cfg`d out items in resolution errors

Use a visitor to collect *all* items (including those nested) that were stripped behind a `cfg` condition.

```
error[E0425]: cannot find function `f` in this scope
  --> $DIR/nested-cfg-attrs.rs:4:13
   |
LL | fn main() { f() }
   |             ^ not found in this scope
   |
note: found an item that was configured out
  --> $DIR/nested-cfg-attrs.rs:2:4
   |
LL | fn f() {}
   |    ^
note: the item is gated here
  --> $DIR/nested-cfg-attrs.rs:1:35
   |
LL | #[cfg_attr(all(), cfg_attr(all(), cfg(FALSE)))]
   |                                   ^^^^^^^^^^
```
Diffstat (limited to 'compiler/rustc_resolve/src')
-rw-r--r--compiler/rustc_resolve/src/diagnostics.rs25
-rw-r--r--compiler/rustc_resolve/src/errors.rs52
-rw-r--r--compiler/rustc_resolve/src/late.rs10
-rw-r--r--compiler/rustc_resolve/src/late/diagnostics.rs5
4 files changed, 55 insertions, 37 deletions
diff --git a/compiler/rustc_resolve/src/diagnostics.rs b/compiler/rustc_resolve/src/diagnostics.rs
index b14a6edb791..3b57f6e883a 100644
--- a/compiler/rustc_resolve/src/diagnostics.rs
+++ b/compiler/rustc_resolve/src/diagnostics.rs
@@ -801,10 +801,12 @@ impl<'ra, 'tcx> Resolver<'ra, 'tcx> {
                     }
                     err.multipart_suggestion(msg, suggestions, applicability);
                 }
-                if let Some(ModuleOrUniformRoot::Module(module)) = module
-                    && let Some(module) = module.opt_def_id()
-                    && let Some(segment) = segment
-                {
+
+                if let Some(segment) = segment {
+                    let module = match module {
+                        Some(ModuleOrUniformRoot::Module(m)) if let Some(id) = m.opt_def_id() => id,
+                        _ => CRATE_DEF_ID.to_def_id(),
+                    };
                     self.find_cfg_stripped(&mut err, &segment, module);
                 }
 
@@ -2839,16 +2841,13 @@ impl<'ra, 'tcx> Resolver<'ra, 'tcx> {
                 continue;
             }
 
-            let note = errors::FoundItemConfigureOut { span: ident.span };
-            err.subdiagnostic(note);
-
-            if let CfgEntry::NameValue { value: Some((feature, _)), .. } = cfg.0 {
-                let note = errors::ItemWasBehindFeature { feature, span: cfg.1 };
-                err.subdiagnostic(note);
+            let item_was = if let CfgEntry::NameValue { value: Some((feature, _)), .. } = cfg.0 {
+                errors::ItemWas::BehindFeature { feature, span: cfg.1 }
             } else {
-                let note = errors::ItemWasCfgOut { span: cfg.1 };
-                err.subdiagnostic(note);
-            }
+                errors::ItemWas::CfgOut { span: cfg.1 }
+            };
+            let note = errors::FoundItemConfigureOut { span: ident.span, item_was };
+            err.subdiagnostic(note);
         }
     }
 }
diff --git a/compiler/rustc_resolve/src/errors.rs b/compiler/rustc_resolve/src/errors.rs
index d6b1e4de6ea..2747ba135ed 100644
--- a/compiler/rustc_resolve/src/errors.rs
+++ b/compiler/rustc_resolve/src/errors.rs
@@ -1,10 +1,13 @@
 use rustc_errors::codes::*;
-use rustc_errors::{Applicability, ElidedLifetimeInPathSubdiag, MultiSpan};
+use rustc_errors::{
+    Applicability, Diag, ElidedLifetimeInPathSubdiag, EmissionGuarantee, IntoDiagArg, MultiSpan,
+    Subdiagnostic,
+};
 use rustc_macros::{Diagnostic, Subdiagnostic};
 use rustc_span::{Ident, Span, Symbol};
 
-use crate::Res;
 use crate::late::PatternSource;
+use crate::{Res, fluent_generated as fluent};
 
 #[derive(Diagnostic)]
 #[diag(resolve_generic_params_from_outer_item, code = E0401)]
@@ -1201,26 +1204,35 @@ pub(crate) struct IdentInScopeButItIsDesc<'a> {
     pub(crate) imported_ident_desc: &'a str,
 }
 
-#[derive(Subdiagnostic)]
-#[note(resolve_found_an_item_configured_out)]
 pub(crate) struct FoundItemConfigureOut {
-    #[primary_span]
-    pub(crate) span: Span,
-}
-
-#[derive(Subdiagnostic)]
-#[note(resolve_item_was_behind_feature)]
-pub(crate) struct ItemWasBehindFeature {
-    pub(crate) feature: Symbol,
-    #[primary_span]
-    pub(crate) span: Span,
-}
-
-#[derive(Subdiagnostic)]
-#[note(resolve_item_was_cfg_out)]
-pub(crate) struct ItemWasCfgOut {
-    #[primary_span]
     pub(crate) span: Span,
+    pub(crate) item_was: ItemWas,
+}
+
+pub(crate) enum ItemWas {
+    BehindFeature { feature: Symbol, span: Span },
+    CfgOut { span: Span },
+}
+
+impl Subdiagnostic for FoundItemConfigureOut {
+    fn add_to_diag<G: EmissionGuarantee>(self, diag: &mut Diag<'_, G>) {
+        let mut multispan: MultiSpan = self.span.into();
+        match self.item_was {
+            ItemWas::BehindFeature { feature, span } => {
+                let key = "feature".into();
+                let value = feature.into_diag_arg(&mut None);
+                let msg = diag.dcx.eagerly_translate_to_string(
+                    fluent::resolve_item_was_behind_feature,
+                    [(&key, &value)].into_iter(),
+                );
+                multispan.push_span_label(span, msg);
+            }
+            ItemWas::CfgOut { span } => {
+                multispan.push_span_label(span, fluent::resolve_item_was_cfg_out);
+            }
+        }
+        diag.span_note(multispan, fluent::resolve_found_an_item_configured_out);
+    }
 }
 
 #[derive(Diagnostic)]
diff --git a/compiler/rustc_resolve/src/late.rs b/compiler/rustc_resolve/src/late.rs
index 261d099abdc..163e4b5b7a9 100644
--- a/compiler/rustc_resolve/src/late.rs
+++ b/compiler/rustc_resolve/src/late.rs
@@ -4231,13 +4231,21 @@ impl<'a, 'ast, 'ra, 'tcx> LateResolutionVisitor<'a, 'ast, 'ra, 'tcx> {
                 //
                 // And that's what happens below - we're just mixing both messages
                 // into a single one.
+                let failed_to_resolve = match parent_err.node {
+                    ResolutionError::FailedToResolve { .. } => true,
+                    _ => false,
+                };
                 let mut parent_err = this.r.into_struct_error(parent_err.span, parent_err.node);
 
                 // overwrite all properties with the parent's error message
                 err.messages = take(&mut parent_err.messages);
                 err.code = take(&mut parent_err.code);
                 swap(&mut err.span, &mut parent_err.span);
-                err.children = take(&mut parent_err.children);
+                if failed_to_resolve {
+                    err.children = take(&mut parent_err.children);
+                } else {
+                    err.children.append(&mut parent_err.children);
+                }
                 err.sort_span = parent_err.sort_span;
                 err.is_lint = parent_err.is_lint.clone();
 
diff --git a/compiler/rustc_resolve/src/late/diagnostics.rs b/compiler/rustc_resolve/src/late/diagnostics.rs
index 98e48664e68..236b1404eeb 100644
--- a/compiler/rustc_resolve/src/late/diagnostics.rs
+++ b/compiler/rustc_resolve/src/late/diagnostics.rs
@@ -525,9 +525,8 @@ impl<'ast, 'ra, 'tcx> LateResolutionVisitor<'_, 'ast, 'ra, 'tcx> {
         }
         self.err_code_special_cases(&mut err, source, path, span);
 
-        if let Some(module) = base_error.module {
-            self.r.find_cfg_stripped(&mut err, &path.last().unwrap().ident.name, module);
-        }
+        let module = base_error.module.unwrap_or_else(|| CRATE_DEF_ID.to_def_id());
+        self.r.find_cfg_stripped(&mut err, &path.last().unwrap().ident.name, module);
 
         (err, candidates)
     }