Enforce syntactical stability of const traits in HIR
This commit is contained in:
parent
8c39ce5b4f
commit
2743df848b
21 changed files with 279 additions and 38 deletions
|
@ -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)
|
||||
}
|
||||
|
|
|
@ -593,9 +593,11 @@ impl<'tcx> MissingStabilityAnnotations<'tcx> {
|
|||
}
|
||||
|
||||
fn check_missing_const_stability(&self, def_id: LocalDefId, span: Span) {
|
||||
let is_const = self.tcx.is_const_fn(def_id.to_def_id());
|
||||
let is_const = self.tcx.is_const_fn(def_id.to_def_id())
|
||||
|| (self.tcx.def_kind(def_id.to_def_id()) == DefKind::Trait
|
||||
&& self.tcx.is_const_trait(def_id.to_def_id()));
|
||||
|
||||
// Reachable const fn must have a stability attribute.
|
||||
// Reachable const fn/trait must have a stability attribute.
|
||||
if is_const
|
||||
&& self.effective_visibilities.is_reachable(def_id)
|
||||
&& self.tcx.lookup_const_stability(def_id).is_none()
|
||||
|
@ -772,7 +774,13 @@ impl<'tcx> Visitor<'tcx> for Checker<'tcx> {
|
|||
// For implementations of traits, check the stability of each item
|
||||
// individually as it's possible to have a stable trait with unstable
|
||||
// items.
|
||||
hir::ItemKind::Impl(hir::Impl { of_trait: Some(ref t), self_ty, items, .. }) => {
|
||||
hir::ItemKind::Impl(hir::Impl {
|
||||
of_trait: Some(ref t),
|
||||
self_ty,
|
||||
items,
|
||||
constness,
|
||||
..
|
||||
}) => {
|
||||
let features = self.tcx.features();
|
||||
if features.staged_api() {
|
||||
let attrs = self.tcx.hir().attrs(item.hir_id());
|
||||
|
@ -814,6 +822,16 @@ impl<'tcx> Visitor<'tcx> for Checker<'tcx> {
|
|||
}
|
||||
}
|
||||
|
||||
match constness {
|
||||
rustc_hir::Constness::Const => {
|
||||
if let Some(def_id) = t.trait_def_id() {
|
||||
// FIXME(const_trait_impl): Improve the span here.
|
||||
self.tcx.check_const_stability(def_id, t.path.span, t.path.span);
|
||||
}
|
||||
}
|
||||
rustc_hir::Constness::NotConst => {}
|
||||
}
|
||||
|
||||
for impl_item_ref in *items {
|
||||
let impl_item = self.tcx.associated_item(impl_item_ref.id.owner_id);
|
||||
|
||||
|
@ -829,6 +847,18 @@ impl<'tcx> Visitor<'tcx> for Checker<'tcx> {
|
|||
intravisit::walk_item(self, item);
|
||||
}
|
||||
|
||||
fn visit_poly_trait_ref(&mut self, t: &'tcx hir::PolyTraitRef<'tcx>) {
|
||||
match t.modifiers.constness {
|
||||
hir::BoundConstness::Always(span) | hir::BoundConstness::Maybe(span) => {
|
||||
if let Some(def_id) = t.trait_ref.trait_def_id() {
|
||||
self.tcx.check_const_stability(def_id, t.trait_ref.path.span, span);
|
||||
}
|
||||
}
|
||||
hir::BoundConstness::Never => {}
|
||||
}
|
||||
intravisit::walk_poly_trait_ref(self, t);
|
||||
}
|
||||
|
||||
fn visit_path(&mut self, path: &hir::Path<'tcx>, id: hir::HirId) {
|
||||
if let Some(def_id) = path.res.opt_def_id() {
|
||||
let method_span = path.segments.last().map(|s| s.ident.span);
|
||||
|
|
|
@ -1031,6 +1031,7 @@ impl<'ra, 'tcx> Resolver<'ra, 'tcx> {
|
|||
is_soft,
|
||||
span,
|
||||
soft_handler,
|
||||
stability::UnstableKind::Regular,
|
||||
);
|
||||
}
|
||||
}
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue