about summary refs log tree commit diff
path: root/compiler/rustc_middle/src/ty/context.rs
diff options
context:
space:
mode:
authorEsteban Küber <esteban@kuber.com.ar>2024-03-07 22:09:00 +0000
committerEsteban Küber <esteban@kuber.com.ar>2024-03-18 16:08:58 +0000
commit6c31f6ce1211a9f635526652eb85002850620277 (patch)
treef02e2eb926252d1d0c837351bd3eb54200c77306 /compiler/rustc_middle/src/ty/context.rs
parent22e241e32e1331aab358ac2843ec63d4cc4ea9f4 (diff)
downloadrust-6c31f6ce1211a9f635526652eb85002850620277.tar.gz
rust-6c31f6ce1211a9f635526652eb85002850620277.zip
Provide structured suggestion for `#![feature(foo)]`
```
error: `S2<'_>` is forbidden as the type of a const generic parameter
  --> $DIR/lifetime-in-const-param.rs:5:23
   |
LL | struct S<'a, const N: S2>(&'a ());
   |                       ^^
   |
   = note: the only supported types are integers, `bool` and `char`
help: add `#![feature(adt_const_params)]` to the crate attributes to enable more complex and user defined types
   |
LL + #![feature(adt_const_params)]
   |
```

Fix #55941.
Diffstat (limited to 'compiler/rustc_middle/src/ty/context.rs')
-rw-r--r--compiler/rustc_middle/src/ty/context.rs43
1 files changed, 42 insertions, 1 deletions
diff --git a/compiler/rustc_middle/src/ty/context.rs b/compiler/rustc_middle/src/ty/context.rs
index 17ba97c5fd3..10a4da40429 100644
--- a/compiler/rustc_middle/src/ty/context.rs
+++ b/compiler/rustc_middle/src/ty/context.rs
@@ -43,7 +43,9 @@ use rustc_data_structures::sync::{self, FreezeReadGuard, Lock, Lrc, WorkerLocal}
 #[cfg(parallel_compiler)]
 use rustc_data_structures::sync::{DynSend, DynSync};
 use rustc_data_structures::unord::UnordSet;
-use rustc_errors::{Diag, DiagCtxt, DiagMessage, ErrorGuaranteed, LintDiagnostic, MultiSpan};
+use rustc_errors::{
+    Applicability, Diag, DiagCtxt, DiagMessage, ErrorGuaranteed, LintDiagnostic, MultiSpan,
+};
 use rustc_hir as hir;
 use rustc_hir::def::DefKind;
 use rustc_hir::def_id::{CrateNum, DefId, LocalDefId, LOCAL_CRATE};
@@ -2174,6 +2176,45 @@ impl<'tcx> TyCtxt<'tcx> {
         lint_level(self.sess, lint, level, src, Some(span.into()), msg, decorate);
     }
 
+    /// Find the crate root and the appropriate span where `use` and outer attributes can be
+    /// inserted at.
+    pub fn crate_level_attribute_injection_span(self, hir_id: HirId) -> Option<Span> {
+        for (_hir_id, node) in self.hir().parent_iter(hir_id) {
+            if let hir::Node::Crate(m) = node {
+                return Some(m.spans.inject_use_span.shrink_to_lo());
+            }
+        }
+        None
+    }
+
+    pub fn disabled_nightly_features<E: rustc_errors::EmissionGuarantee>(
+        self,
+        diag: &mut Diag<'_, E>,
+        hir_id: Option<HirId>,
+        features: impl IntoIterator<Item = (String, Symbol)>,
+    ) {
+        if !self.sess.is_nightly_build() {
+            return;
+        }
+
+        let span = hir_id.and_then(|id| self.crate_level_attribute_injection_span(id));
+        for (desc, feature) in features {
+            // FIXME: make this string translatable
+            let msg =
+                format!("add `#![feature({feature})]` to the crate attributes to enable{desc}");
+            if let Some(span) = span {
+                diag.span_suggestion_verbose(
+                    span,
+                    msg,
+                    format!("#![feature({feature})]\n"),
+                    Applicability::MachineApplicable,
+                );
+            } else {
+                diag.help(msg);
+            }
+        }
+    }
+
     /// Emit a lint from a lint struct (some type that implements `LintDiagnostic`, typically
     /// generated by `#[derive(LintDiagnostic)]`).
     #[track_caller]