1
Fork 0

Enforce syntactical stability of const traits in HIR

This commit is contained in:
Michael Goulet 2025-01-12 20:52:30 +00:00
parent 8c39ce5b4f
commit 2743df848b
21 changed files with 279 additions and 38 deletions

View file

@ -30,6 +30,14 @@ pub enum StabilityLevel {
Stable,
}
#[derive(Copy, Clone)]
pub enum UnstableKind {
/// Enforcing regular stability of an item
Regular,
/// Enforcing const stability of an item
Const(Span),
}
/// An entry in the `depr_map`.
#[derive(Copy, Clone, HashStable, Debug, Encodable, Decodable)]
pub struct DeprecationEntry {
@ -108,10 +116,16 @@ pub fn report_unstable(
is_soft: bool,
span: Span,
soft_handler: impl FnOnce(&'static Lint, Span, String),
kind: UnstableKind,
) {
let qual = match kind {
UnstableKind::Regular => "",
UnstableKind::Const(_) => " const",
};
let msg = match reason {
Some(r) => format!("use of unstable library feature `{feature}`: {r}"),
None => format!("use of unstable library feature `{feature}`"),
Some(r) => format!("use of unstable{qual} library feature `{feature}`: {r}"),
None => format!("use of unstable{qual} library feature `{feature}`"),
};
if is_soft {
@ -121,6 +135,9 @@ pub fn report_unstable(
if let Some((inner_types, msg, sugg, applicability)) = suggestion {
err.span_suggestion(inner_types, msg, sugg, applicability);
}
if let UnstableKind::Const(kw) = kind {
err.span_label(kw, "trait is not stable as const yet");
}
err.emit();
}
}
@ -587,6 +604,7 @@ impl<'tcx> TyCtxt<'tcx> {
is_soft,
span,
soft_handler,
UnstableKind::Regular,
),
EvalResult::Unmarked => unmarked(span, def_id),
}
@ -594,6 +612,73 @@ impl<'tcx> TyCtxt<'tcx> {
is_allowed
}
/// This function is analogous to `check_optional_stability` but with the logic in
/// `eval_stability_allow_unstable` inlined, and which operating on const stability
/// instead of regular stability.
///
/// This enforces *syntactical* const stability of const traits. In other words,
/// it enforces the ability to name `~const`/`const` traits in trait bounds in various
/// syntax positions in HIR (including in the trait of an impl header).
pub fn check_const_stability(self, def_id: DefId, span: Span, const_kw_span: Span) {
let is_staged_api = self.lookup_stability(def_id.krate.as_def_id()).is_some();
if !is_staged_api {
return;
}
// Only the cross-crate scenario matters when checking unstable APIs
let cross_crate = !def_id.is_local();
if !cross_crate {
return;
}
let stability = self.lookup_const_stability(def_id);
debug!(
"stability: \
inspecting def_id={:?} span={:?} of stability={:?}",
def_id, span, stability
);
match stability {
Some(ConstStability {
level: attr::StabilityLevel::Unstable { reason, issue, is_soft, implied_by, .. },
feature,
..
}) => {
assert!(!is_soft);
if span.allows_unstable(feature) {
debug!("body stability: skipping span={:?} since it is internal", span);
return;
}
if self.features().enabled(feature) {
return;
}
// If this item was previously part of a now-stabilized feature which is still
// enabled (i.e. the user hasn't removed the attribute for the stabilized feature
// yet) then allow use of this item.
if let Some(implied_by) = implied_by
&& self.features().enabled(implied_by)
{
return;
}
report_unstable(
self.sess,
feature,
reason.to_opt_reason(),
issue,
None,
false,
span,
|_, _, _| {},
UnstableKind::Const(const_kw_span),
);
}
Some(_) | None => {}
}
}
pub fn lookup_deprecation(self, id: DefId) -> Option<Deprecation> {
self.lookup_deprecation_entry(id).map(|depr| depr.attr)
}