use rustc_hir::def_id::{LocalDefId, CRATE_DEF_ID};
use rustc_hir::hir_id::CRATE_HIR_ID;
use rustc_hir::intravisit::{self, Visitor};
-use rustc_hir::{FieldDef, Generics, HirId, Item, TraitRef, Ty, TyKind, Variant};
+use rustc_hir::{FieldDef, Generics, HirId, Item, ItemKind, TraitRef, Ty, TyKind, Variant};
use rustc_middle::hir::nested_filter;
use rustc_middle::middle::privacy::AccessLevels;
-use rustc_middle::middle::stability::{DeprecationEntry, Index};
+use rustc_middle::middle::stability::{AllowUnstable, DeprecationEntry, Index};
use rustc_middle::ty::{self, query::Providers, TyCtxt};
use rustc_session::lint;
use rustc_session::lint::builtin::{INEFFECTIVE_UNSTABLE_TRAIT_IMPL, USELESS_DEPRECATED};
.span_suggestion_short(
*span,
"remove the unnecessary deprecation attribute",
- String::new(),
+ "",
rustc_errors::Applicability::MachineApplicable,
)
.emit();
// Propagate unstability. This can happen even for non-staged-api crates in case
// -Zforce-unstable-if-unmarked is set.
if let Some(stab) = self.parent_stab {
- if inherit_deprecation.yes() && stab.level.is_unstable() {
+ if inherit_deprecation.yes() && stab.is_unstable() {
self.index.stab_map.insert(def_id, stab);
}
}
if const_stab.is_none() {
debug!("annotate: const_stab not found, parent = {:?}", self.parent_const_stab);
if let Some(parent) = self.parent_const_stab {
- if parent.level.is_unstable() {
+ if parent.is_const_unstable() {
self.index.const_stab_map.insert(def_id, parent);
}
}
if stab.is_none() {
debug!("annotate: stab not found, parent = {:?}", self.parent_stab);
if let Some(stab) = self.parent_stab {
- if inherit_deprecation.yes() && stab.level.is_unstable()
- || inherit_from_parent.yes()
- {
+ if inherit_deprecation.yes() && stab.is_unstable() || inherit_from_parent.yes() {
self.index.stab_map.insert(def_id, stab);
}
}
return;
}
- 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.is_const_trait_impl_raw(def_id.to_def_id());
let is_stable = self
.tcx
.lookup_stability(def_id)
/// Cross-references the feature names of unstable APIs with enabled
/// features and possibly prints errors.
fn check_mod_unstable_api_usage(tcx: TyCtxt<'_>, module_def_id: LocalDefId) {
- tcx.hir().visit_item_likes_in_module(module_def_id, &mut Checker { tcx }.as_deep_visitor());
+ tcx.hir().deep_visit_item_likes_in_module(module_def_id, &mut Checker { tcx });
}
pub(crate) fn provide(providers: &mut Providers) {
// 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, .. }) => {
- if self.tcx.features().staged_api {
+ 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());
+ let (stab, const_stab) = attr::find_stability(&self.tcx.sess, attrs, item.span);
+
// If this impl block has an #[unstable] attribute, give an
// error if all involved types and traits are stable, because
// it will have no effect.
// See: https://github.com/rust-lang/rust/issues/55436
- let attrs = self.tcx.hir().attrs(item.hir_id());
- if let (Some((Stability { level: attr::Unstable { .. }, .. }, span)), _) =
- attr::find_stability(&self.tcx.sess, attrs, item.span)
- {
+ if let Some((Stability { level: attr::Unstable { .. }, .. }, span)) = stab {
let mut c = CheckTraitImplStable { tcx: self.tcx, fully_stable: true };
c.visit_ty(self_ty);
c.visit_trait_ref(t);
);
}
}
+
+ // `#![feature(const_trait_impl)]` is unstable, so any impl declared stable
+ // needs to have an error emitted.
+ if features.const_trait_impl
+ && *constness == hir::Constness::Const
+ && const_stab.map_or(false, |(stab, _)| stab.is_const_stable())
+ {
+ self.tcx
+ .sess
+ .struct_span_err(item.span, "trait implementations cannot be const stable yet")
+ .note("see issue #67792 <https://github.com/rust-lang/rust/issues/67792> for more information")
+ .emit();
+ }
}
for impl_item_ref in *items {
fn visit_path(&mut self, path: &'tcx 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);
- self.tcx.check_stability(def_id, Some(id), path.span, method_span)
+ self.tcx.check_stability_allow_unstable(
+ def_id,
+ Some(id),
+ path.span,
+ method_span,
+ if is_unstable_reexport(self.tcx, id) {
+ AllowUnstable::Yes
+ } else {
+ AllowUnstable::No
+ },
+ )
}
intravisit::walk_path(self, path)
}
}
+/// Check whether a path is a `use` item that has been marked as unstable.
+///
+/// See issue #94972 for details on why this is a special case
+fn is_unstable_reexport<'tcx>(tcx: TyCtxt<'tcx>, id: hir::HirId) -> bool {
+ // Get the LocalDefId so we can lookup the item to check the kind.
+ let Some(def_id) = tcx.hir().opt_local_def_id(id) else { return false; };
+
+ let Some(stab) = tcx.stability().local_stability(def_id) else {
+ return false;
+ };
+
+ if stab.level.is_stable() {
+ // The re-export is not marked as unstable, don't override
+ return false;
+ }
+
+ // If this is a path that isn't a use, we don't need to do anything special
+ if !matches!(tcx.hir().item(hir::ItemId { def_id }).kind, ItemKind::Use(..)) {
+ return false;
+ }
+
+ true
+}
+
struct CheckTraitImplStable<'tcx> {
tcx: TyCtxt<'tcx>,
fully_stable: bool,
let mut missing = MissingStabilityAnnotations { tcx, access_levels };
missing.check_missing_stability(CRATE_DEF_ID, tcx.hir().span(CRATE_HIR_ID));
tcx.hir().walk_toplevel_module(&mut missing);
- tcx.hir().visit_all_item_likes(&mut missing.as_deep_visitor());
+ tcx.hir().deep_visit_all_item_likes(&mut missing);
}
let declared_lang_features = &tcx.features().declared_lang_features;