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.
This commit is contained in:
parent
22e241e32e
commit
6c31f6ce12
98 changed files with 755 additions and 253 deletions
|
@ -99,7 +99,7 @@ impl<'tcx> NonConstOp<'tcx> for FnCallNonConst<'tcx> {
|
|||
#[allow(rustc::untranslatable_diagnostic)]
|
||||
fn build_error(&self, ccx: &ConstCx<'_, 'tcx>, _: Span) -> Diag<'tcx> {
|
||||
let FnCallNonConst { caller, callee, args, span, call_source, feature } = *self;
|
||||
let ConstCx { tcx, param_env, .. } = *ccx;
|
||||
let ConstCx { tcx, param_env, body, .. } = *ccx;
|
||||
|
||||
let diag_trait = |err, self_ty: Ty<'_>, trait_id| {
|
||||
let trait_ref = TraitRef::from_method(tcx, trait_id, args);
|
||||
|
@ -297,10 +297,12 @@ impl<'tcx> NonConstOp<'tcx> for FnCallNonConst<'tcx> {
|
|||
ccx.const_kind(),
|
||||
));
|
||||
|
||||
if let Some(feature) = feature
|
||||
&& ccx.tcx.sess.is_nightly_build()
|
||||
{
|
||||
err.help(format!("add `#![feature({feature})]` to the crate attributes to enable",));
|
||||
if let Some(feature) = feature {
|
||||
ccx.tcx.disabled_nightly_features(
|
||||
&mut err,
|
||||
body.source.def_id().as_local().map(|local| ccx.tcx.local_def_id_to_hir_id(local)),
|
||||
[(String::new(), feature)],
|
||||
);
|
||||
}
|
||||
|
||||
if let ConstContext::Static(_) = ccx.const_kind() {
|
||||
|
|
|
@ -16,7 +16,7 @@ use rustc_middle::ty::{
|
|||
self, GenericArgsRef, GenericParamDef, GenericParamDefKind, IsSuggestable, Ty, TyCtxt,
|
||||
};
|
||||
use rustc_session::lint::builtin::LATE_BOUND_LIFETIME_ARGUMENTS;
|
||||
use rustc_span::symbol::kw;
|
||||
use rustc_span::symbol::{kw, sym};
|
||||
use smallvec::SmallVec;
|
||||
|
||||
/// Report an error that a generic argument did not match the generic parameter that was
|
||||
|
@ -41,9 +41,11 @@ fn generic_arg_mismatch_err(
|
|||
if let GenericParamDefKind::Const { .. } = param.kind {
|
||||
if matches!(arg, GenericArg::Type(hir::Ty { kind: hir::TyKind::Infer, .. })) {
|
||||
err.help("const arguments cannot yet be inferred with `_`");
|
||||
if sess.is_nightly_build() {
|
||||
err.help("add `#![feature(generic_arg_infer)]` to the crate attributes to enable");
|
||||
}
|
||||
tcx.disabled_nightly_features(
|
||||
&mut err,
|
||||
param.def_id.as_local().map(|local| tcx.local_def_id_to_hir_id(local)),
|
||||
[(String::new(), sym::generic_arg_infer)],
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -291,12 +291,16 @@ fn default_body_is_unstable(
|
|||
reason: reason_str,
|
||||
});
|
||||
|
||||
let inject_span = item_did
|
||||
.as_local()
|
||||
.and_then(|id| tcx.crate_level_attribute_injection_span(tcx.local_def_id_to_hir_id(id)));
|
||||
rustc_session::parse::add_feature_diagnostics_for_issue(
|
||||
&mut err,
|
||||
&tcx.sess,
|
||||
feature,
|
||||
rustc_feature::GateIssue::Library(issue),
|
||||
false,
|
||||
inject_span,
|
||||
);
|
||||
|
||||
err.emit();
|
||||
|
|
|
@ -999,9 +999,14 @@ fn check_param_wf(tcx: TyCtxt<'_>, param: &hir::GenericParam<'_>) -> Result<(),
|
|||
// Implments `ConstParamTy`, suggest adding the feature to enable.
|
||||
Ok(..) => true,
|
||||
};
|
||||
if may_suggest_feature && tcx.sess.is_nightly_build() {
|
||||
diag.help(
|
||||
"add `#![feature(adt_const_params)]` to the crate attributes to enable more complex and user defined types",
|
||||
if may_suggest_feature {
|
||||
tcx.disabled_nightly_features(
|
||||
&mut diag,
|
||||
Some(param.hir_id),
|
||||
[(
|
||||
" more complex and user defined types".to_string(),
|
||||
sym::adt_const_params,
|
||||
)],
|
||||
);
|
||||
}
|
||||
|
||||
|
|
|
@ -1420,15 +1420,13 @@ impl<'tcx> Pick<'tcx> {
|
|||
}
|
||||
_ => {}
|
||||
}
|
||||
if tcx.sess.is_nightly_build() {
|
||||
for (candidate, feature) in &self.unstable_candidates {
|
||||
lint.help(format!(
|
||||
"add `#![feature({})]` to the crate attributes to enable `{}`",
|
||||
feature,
|
||||
tcx.def_path_str(candidate.item.def_id),
|
||||
));
|
||||
}
|
||||
}
|
||||
tcx.disabled_nightly_features(
|
||||
lint,
|
||||
Some(scope_expr_id),
|
||||
self.unstable_candidates.iter().map(|(candidate, feature)| {
|
||||
(format!(" `{}`", tcx.def_path_str(candidate.item.def_id)), *feature)
|
||||
}),
|
||||
);
|
||||
},
|
||||
);
|
||||
}
|
||||
|
|
|
@ -1078,6 +1078,7 @@ impl<'s, P: LintLevelsProvider> LintLevelsBuilder<'s, P> {
|
|||
feature,
|
||||
GateIssue::Language,
|
||||
lint_from_cli,
|
||||
None,
|
||||
);
|
||||
},
|
||||
);
|
||||
|
|
|
@ -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]
|
||||
|
|
|
@ -155,16 +155,11 @@ impl<'tcx> CheckConstVisitor<'tcx> {
|
|||
//
|
||||
// FIXME(ecstaticmorse): Maybe this could be incorporated into `feature_err`? This
|
||||
// is a pretty narrow case, however.
|
||||
if tcx.sess.is_nightly_build() {
|
||||
for gate in missing_secondary {
|
||||
// FIXME: make this translatable
|
||||
#[allow(rustc::diagnostic_outside_of_impl)]
|
||||
#[allow(rustc::untranslatable_diagnostic)]
|
||||
err.help(format!(
|
||||
"add `#![feature({gate})]` to the crate attributes to enable"
|
||||
));
|
||||
}
|
||||
}
|
||||
tcx.disabled_nightly_features(
|
||||
&mut err,
|
||||
def_id.map(|id| tcx.local_def_id_to_hir_id(id)),
|
||||
missing_secondary.into_iter().map(|gate| (String::new(), *gate)),
|
||||
);
|
||||
|
||||
err.emit();
|
||||
}
|
||||
|
|
|
@ -24,6 +24,9 @@ session_feature_diagnostic_for_issue =
|
|||
session_feature_diagnostic_help =
|
||||
add `#![feature({$feature})]` to the crate attributes to enable
|
||||
|
||||
session_feature_diagnostic_suggestion =
|
||||
add `#![feature({$feature})]` to the crate attributes to enable
|
||||
|
||||
session_feature_suggest_upgrade_compiler =
|
||||
this compiler was built on {$date}; consider upgrading it if it is out of date
|
||||
|
||||
|
|
|
@ -54,6 +54,18 @@ pub struct FeatureDiagnosticHelp {
|
|||
pub feature: Symbol,
|
||||
}
|
||||
|
||||
#[derive(Subdiagnostic)]
|
||||
#[suggestion(
|
||||
session_feature_diagnostic_suggestion,
|
||||
applicability = "maybe-incorrect",
|
||||
code = "#![feature({feature})]\n"
|
||||
)]
|
||||
pub struct FeatureDiagnosticSuggestion {
|
||||
pub feature: Symbol,
|
||||
#[primary_span]
|
||||
pub span: Span,
|
||||
}
|
||||
|
||||
#[derive(Subdiagnostic)]
|
||||
#[help(session_cli_feature_diagnostic_help)]
|
||||
pub struct CliFeatureDiagnosticHelp {
|
||||
|
|
|
@ -3,8 +3,8 @@
|
|||
|
||||
use crate::config::{Cfg, CheckCfg};
|
||||
use crate::errors::{
|
||||
CliFeatureDiagnosticHelp, FeatureDiagnosticForIssue, FeatureDiagnosticHelp, FeatureGateError,
|
||||
SuggestUpgradeCompiler,
|
||||
CliFeatureDiagnosticHelp, FeatureDiagnosticForIssue, FeatureDiagnosticHelp,
|
||||
FeatureDiagnosticSuggestion, FeatureGateError, SuggestUpgradeCompiler,
|
||||
};
|
||||
use crate::lint::{
|
||||
builtin::UNSTABLE_SYNTAX_PRE_EXPANSION, BufferedEarlyLint, BuiltinLintDiag, Lint, LintId,
|
||||
|
@ -112,7 +112,7 @@ pub fn feature_err_issue(
|
|||
}
|
||||
|
||||
let mut err = sess.psess.dcx.create_err(FeatureGateError { span, explain: explain.into() });
|
||||
add_feature_diagnostics_for_issue(&mut err, sess, feature, issue, false);
|
||||
add_feature_diagnostics_for_issue(&mut err, sess, feature, issue, false, None);
|
||||
err
|
||||
}
|
||||
|
||||
|
@ -141,7 +141,7 @@ pub fn feature_warn_issue(
|
|||
explain: &'static str,
|
||||
) {
|
||||
let mut err = sess.psess.dcx.struct_span_warn(span, explain);
|
||||
add_feature_diagnostics_for_issue(&mut err, sess, feature, issue, false);
|
||||
add_feature_diagnostics_for_issue(&mut err, sess, feature, issue, false, None);
|
||||
|
||||
// Decorate this as a future-incompatibility lint as in rustc_middle::lint::lint_level
|
||||
let lint = UNSTABLE_SYNTAX_PRE_EXPANSION;
|
||||
|
@ -160,7 +160,7 @@ pub fn add_feature_diagnostics<G: EmissionGuarantee>(
|
|||
sess: &Session,
|
||||
feature: Symbol,
|
||||
) {
|
||||
add_feature_diagnostics_for_issue(err, sess, feature, GateIssue::Language, false);
|
||||
add_feature_diagnostics_for_issue(err, sess, feature, GateIssue::Language, false, None);
|
||||
}
|
||||
|
||||
/// Adds the diagnostics for a feature to an existing error.
|
||||
|
@ -175,6 +175,7 @@ pub fn add_feature_diagnostics_for_issue<G: EmissionGuarantee>(
|
|||
feature: Symbol,
|
||||
issue: GateIssue,
|
||||
feature_from_cli: bool,
|
||||
inject_span: Option<Span>,
|
||||
) {
|
||||
if let Some(n) = find_feature_issue(feature, issue) {
|
||||
err.subdiagnostic(sess.dcx(), FeatureDiagnosticForIssue { n });
|
||||
|
@ -184,6 +185,8 @@ pub fn add_feature_diagnostics_for_issue<G: EmissionGuarantee>(
|
|||
if sess.psess.unstable_features.is_nightly_build() {
|
||||
if feature_from_cli {
|
||||
err.subdiagnostic(sess.dcx(), CliFeatureDiagnosticHelp { feature });
|
||||
} else if let Some(span) = inject_span {
|
||||
err.subdiagnostic(sess.dcx(), FeatureDiagnosticSuggestion { feature, span });
|
||||
} else {
|
||||
err.subdiagnostic(sess.dcx(), FeatureDiagnosticHelp { feature });
|
||||
}
|
||||
|
|
|
@ -3510,9 +3510,11 @@ impl<'tcx> TypeErrCtxt<'_, 'tcx> {
|
|||
}
|
||||
ObligationCauseCode::TrivialBound => {
|
||||
err.help("see issue #48214");
|
||||
if tcx.sess.opts.unstable_features.is_nightly_build() {
|
||||
err.help("add `#![feature(trivial_bounds)]` to the crate attributes to enable");
|
||||
}
|
||||
tcx.disabled_nightly_features(
|
||||
err,
|
||||
Some(tcx.local_def_id_to_hir_id(body_id)),
|
||||
[(String::new(), sym::trivial_bounds)],
|
||||
);
|
||||
}
|
||||
ObligationCauseCode::OpaqueReturnType(expr_info) => {
|
||||
if let Some((expr_ty, expr_span)) = expr_info {
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue