Auto merge of #77118 - exrook:stability-generic-parameters-2, r=varkor
Stability annotations on generic parameters (take 2.5) Rebase of #72314 + more tests Implements rust-lang/wg-allocators#2.
This commit is contained in:
commit
d902752866
9 changed files with 1171 additions and 34 deletions
|
@ -1822,6 +1822,9 @@ impl EncodeContext<'a, 'tcx> {
|
|||
EntryKind::TypeParam,
|
||||
default.is_some(),
|
||||
);
|
||||
if default.is_some() {
|
||||
self.encode_stability(def_id.to_def_id());
|
||||
}
|
||||
}
|
||||
GenericParamKind::Const { .. } => {
|
||||
self.encode_info_for_generic_param(
|
||||
|
@ -1829,6 +1832,7 @@ impl EncodeContext<'a, 'tcx> {
|
|||
EntryKind::ConstParam,
|
||||
true,
|
||||
);
|
||||
// FIXME(const_generics:defaults)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -392,9 +392,27 @@ impl<'tcx> TyCtxt<'tcx> {
|
|||
/// If the item defined by `def_id` is unstable and the corresponding `#![feature]` does not
|
||||
/// exist, emits an error.
|
||||
///
|
||||
/// Additionally, this function will also check if the item is deprecated. If so, and `id` is
|
||||
/// not `None`, a deprecated lint attached to `id` will be emitted.
|
||||
/// This function will also check if the item is deprecated.
|
||||
/// If so, and `id` is not `None`, a deprecated lint attached to `id` will be emitted.
|
||||
pub fn check_stability(self, def_id: DefId, id: Option<HirId>, span: Span) {
|
||||
self.check_optional_stability(def_id, id, span, |span, def_id| {
|
||||
// The API could be uncallable for other reasons, for example when a private module
|
||||
// was referenced.
|
||||
self.sess.delay_span_bug(span, &format!("encountered unmarked API: {:?}", def_id));
|
||||
})
|
||||
}
|
||||
|
||||
/// Like `check_stability`, except that we permit items to have custom behaviour for
|
||||
/// missing stability attributes (not necessarily just emit a `bug!`). This is necessary
|
||||
/// for default generic parameters, which only have stability attributes if they were
|
||||
/// added after the type on which they're defined.
|
||||
pub fn check_optional_stability(
|
||||
self,
|
||||
def_id: DefId,
|
||||
id: Option<HirId>,
|
||||
span: Span,
|
||||
unmarked: impl FnOnce(Span, DefId) -> (),
|
||||
) {
|
||||
let soft_handler = |lint, span, msg: &_| {
|
||||
self.struct_span_lint_hir(lint, id.unwrap_or(hir::CRATE_HIR_ID), span, |lint| {
|
||||
lint.build(msg).emit()
|
||||
|
@ -405,11 +423,7 @@ impl<'tcx> TyCtxt<'tcx> {
|
|||
EvalResult::Deny { feature, reason, issue, is_soft } => {
|
||||
report_unstable(self.sess, feature, reason, issue, is_soft, span, soft_handler)
|
||||
}
|
||||
EvalResult::Unmarked => {
|
||||
// The API could be uncallable for other reasons, for example when a private module
|
||||
// was referenced.
|
||||
self.sess.delay_span_bug(span, &format!("encountered unmarked API: {:?}", def_id));
|
||||
}
|
||||
EvalResult::Unmarked => unmarked(span, def_id),
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -37,6 +37,24 @@ enum AnnotationKind {
|
|||
Container,
|
||||
}
|
||||
|
||||
/// Whether to inherit deprecation flags for nested items. In most cases, we do want to inherit
|
||||
/// deprecation, because nested items rarely have individual deprecation attributes, and so
|
||||
/// should be treated as deprecated if their parent is. However, default generic parameters
|
||||
/// have separate deprecation attributes from their parents, so we do not wish to inherit
|
||||
/// deprecation in this case. For example, inheriting deprecation for `T` in `Foo<T>`
|
||||
/// would cause a duplicate warning arising from both `Foo` and `T` being deprecated.
|
||||
#[derive(Clone)]
|
||||
enum InheritDeprecation {
|
||||
Yes,
|
||||
No,
|
||||
}
|
||||
|
||||
impl InheritDeprecation {
|
||||
fn yes(&self) -> bool {
|
||||
matches!(self, InheritDeprecation::Yes)
|
||||
}
|
||||
}
|
||||
|
||||
// A private tree-walker for producing an Index.
|
||||
struct Annotator<'a, 'tcx> {
|
||||
tcx: TyCtxt<'tcx>,
|
||||
|
@ -56,6 +74,7 @@ impl<'a, 'tcx> Annotator<'a, 'tcx> {
|
|||
attrs: &[Attribute],
|
||||
item_sp: Span,
|
||||
kind: AnnotationKind,
|
||||
inherit_deprecation: InheritDeprecation,
|
||||
visit_children: F,
|
||||
) where
|
||||
F: FnOnce(&mut Self),
|
||||
|
@ -63,7 +82,7 @@ impl<'a, 'tcx> Annotator<'a, 'tcx> {
|
|||
debug!("annotate(id = {:?}, attrs = {:?})", hir_id, attrs);
|
||||
let mut did_error = false;
|
||||
if !self.tcx.features().staged_api {
|
||||
did_error = self.forbid_staged_api_attrs(hir_id, attrs);
|
||||
did_error = self.forbid_staged_api_attrs(hir_id, attrs, inherit_deprecation.clone());
|
||||
}
|
||||
|
||||
let depr =
|
||||
|
@ -80,9 +99,11 @@ impl<'a, 'tcx> Annotator<'a, 'tcx> {
|
|||
let depr_entry = DeprecationEntry::local(depr.clone(), hir_id);
|
||||
self.index.depr_map.insert(hir_id, depr_entry);
|
||||
} else if let Some(parent_depr) = self.parent_depr.clone() {
|
||||
is_deprecated = true;
|
||||
info!("tagging child {:?} as deprecated from parent", hir_id);
|
||||
self.index.depr_map.insert(hir_id, parent_depr);
|
||||
if inherit_deprecation.yes() {
|
||||
is_deprecated = true;
|
||||
info!("tagging child {:?} as deprecated from parent", hir_id);
|
||||
self.index.depr_map.insert(hir_id, parent_depr);
|
||||
}
|
||||
}
|
||||
|
||||
if self.tcx.features().staged_api {
|
||||
|
@ -186,7 +207,7 @@ impl<'a, 'tcx> Annotator<'a, 'tcx> {
|
|||
if stab.is_none() {
|
||||
debug!("annotate: stab not found, parent = {:?}", self.parent_stab);
|
||||
if let Some(stab) = self.parent_stab {
|
||||
if stab.level.is_unstable() {
|
||||
if inherit_deprecation.yes() && stab.level.is_unstable() {
|
||||
self.index.stab_map.insert(hir_id, stab);
|
||||
}
|
||||
}
|
||||
|
@ -237,7 +258,12 @@ impl<'a, 'tcx> Annotator<'a, 'tcx> {
|
|||
}
|
||||
|
||||
// returns true if an error occurred, used to suppress some spurious errors
|
||||
fn forbid_staged_api_attrs(&mut self, hir_id: HirId, attrs: &[Attribute]) -> bool {
|
||||
fn forbid_staged_api_attrs(
|
||||
&mut self,
|
||||
hir_id: HirId,
|
||||
attrs: &[Attribute],
|
||||
inherit_deprecation: InheritDeprecation,
|
||||
) -> bool {
|
||||
// Emit errors for non-staged-api crates.
|
||||
let unstable_attrs = [
|
||||
sym::unstable,
|
||||
|
@ -265,7 +291,7 @@ impl<'a, 'tcx> Annotator<'a, 'tcx> {
|
|||
// 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 stab.level.is_unstable() {
|
||||
if inherit_deprecation.yes() && stab.level.is_unstable() {
|
||||
self.index.stab_map.insert(hir_id, stab);
|
||||
}
|
||||
}
|
||||
|
@ -301,54 +327,119 @@ impl<'a, 'tcx> Visitor<'tcx> for Annotator<'a, 'tcx> {
|
|||
}
|
||||
hir::ItemKind::Struct(ref sd, _) => {
|
||||
if let Some(ctor_hir_id) = sd.ctor_hir_id() {
|
||||
self.annotate(ctor_hir_id, &i.attrs, i.span, AnnotationKind::Required, |_| {})
|
||||
self.annotate(
|
||||
ctor_hir_id,
|
||||
&i.attrs,
|
||||
i.span,
|
||||
AnnotationKind::Required,
|
||||
InheritDeprecation::Yes,
|
||||
|_| {},
|
||||
)
|
||||
}
|
||||
}
|
||||
_ => {}
|
||||
}
|
||||
|
||||
self.annotate(i.hir_id, &i.attrs, i.span, kind, |v| intravisit::walk_item(v, i));
|
||||
self.annotate(i.hir_id, &i.attrs, i.span, kind, InheritDeprecation::Yes, |v| {
|
||||
intravisit::walk_item(v, i)
|
||||
});
|
||||
self.in_trait_impl = orig_in_trait_impl;
|
||||
}
|
||||
|
||||
fn visit_trait_item(&mut self, ti: &'tcx hir::TraitItem<'tcx>) {
|
||||
self.annotate(ti.hir_id, &ti.attrs, ti.span, AnnotationKind::Required, |v| {
|
||||
intravisit::walk_trait_item(v, ti);
|
||||
});
|
||||
self.annotate(
|
||||
ti.hir_id,
|
||||
&ti.attrs,
|
||||
ti.span,
|
||||
AnnotationKind::Required,
|
||||
InheritDeprecation::Yes,
|
||||
|v| {
|
||||
intravisit::walk_trait_item(v, ti);
|
||||
},
|
||||
);
|
||||
}
|
||||
|
||||
fn visit_impl_item(&mut self, ii: &'tcx hir::ImplItem<'tcx>) {
|
||||
let kind =
|
||||
if self.in_trait_impl { AnnotationKind::Prohibited } else { AnnotationKind::Required };
|
||||
self.annotate(ii.hir_id, &ii.attrs, ii.span, kind, |v| {
|
||||
self.annotate(ii.hir_id, &ii.attrs, ii.span, kind, InheritDeprecation::Yes, |v| {
|
||||
intravisit::walk_impl_item(v, ii);
|
||||
});
|
||||
}
|
||||
|
||||
fn visit_variant(&mut self, var: &'tcx Variant<'tcx>, g: &'tcx Generics<'tcx>, item_id: HirId) {
|
||||
self.annotate(var.id, &var.attrs, var.span, AnnotationKind::Required, |v| {
|
||||
if let Some(ctor_hir_id) = var.data.ctor_hir_id() {
|
||||
v.annotate(ctor_hir_id, &var.attrs, var.span, AnnotationKind::Required, |_| {});
|
||||
}
|
||||
self.annotate(
|
||||
var.id,
|
||||
&var.attrs,
|
||||
var.span,
|
||||
AnnotationKind::Required,
|
||||
InheritDeprecation::Yes,
|
||||
|v| {
|
||||
if let Some(ctor_hir_id) = var.data.ctor_hir_id() {
|
||||
v.annotate(
|
||||
ctor_hir_id,
|
||||
&var.attrs,
|
||||
var.span,
|
||||
AnnotationKind::Required,
|
||||
InheritDeprecation::Yes,
|
||||
|_| {},
|
||||
);
|
||||
}
|
||||
|
||||
intravisit::walk_variant(v, var, g, item_id)
|
||||
})
|
||||
intravisit::walk_variant(v, var, g, item_id)
|
||||
},
|
||||
)
|
||||
}
|
||||
|
||||
fn visit_struct_field(&mut self, s: &'tcx StructField<'tcx>) {
|
||||
self.annotate(s.hir_id, &s.attrs, s.span, AnnotationKind::Required, |v| {
|
||||
intravisit::walk_struct_field(v, s);
|
||||
});
|
||||
self.annotate(
|
||||
s.hir_id,
|
||||
&s.attrs,
|
||||
s.span,
|
||||
AnnotationKind::Required,
|
||||
InheritDeprecation::Yes,
|
||||
|v| {
|
||||
intravisit::walk_struct_field(v, s);
|
||||
},
|
||||
);
|
||||
}
|
||||
|
||||
fn visit_foreign_item(&mut self, i: &'tcx hir::ForeignItem<'tcx>) {
|
||||
self.annotate(i.hir_id, &i.attrs, i.span, AnnotationKind::Required, |v| {
|
||||
intravisit::walk_foreign_item(v, i);
|
||||
});
|
||||
self.annotate(
|
||||
i.hir_id,
|
||||
&i.attrs,
|
||||
i.span,
|
||||
AnnotationKind::Required,
|
||||
InheritDeprecation::Yes,
|
||||
|v| {
|
||||
intravisit::walk_foreign_item(v, i);
|
||||
},
|
||||
);
|
||||
}
|
||||
|
||||
fn visit_macro_def(&mut self, md: &'tcx hir::MacroDef<'tcx>) {
|
||||
self.annotate(md.hir_id, &md.attrs, md.span, AnnotationKind::Required, |_| {});
|
||||
self.annotate(
|
||||
md.hir_id,
|
||||
&md.attrs,
|
||||
md.span,
|
||||
AnnotationKind::Required,
|
||||
InheritDeprecation::Yes,
|
||||
|_| {},
|
||||
);
|
||||
}
|
||||
|
||||
fn visit_generic_param(&mut self, p: &'tcx hir::GenericParam<'tcx>) {
|
||||
let kind = match &p.kind {
|
||||
// FIXME(const_generics:defaults)
|
||||
hir::GenericParamKind::Type { default, .. } if default.is_some() => {
|
||||
AnnotationKind::Container
|
||||
}
|
||||
_ => AnnotationKind::Prohibited,
|
||||
};
|
||||
|
||||
self.annotate(p.hir_id, &p.attrs, p.span, kind, InheritDeprecation::No, |v| {
|
||||
intravisit::walk_generic_param(v, p);
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -422,6 +513,10 @@ impl<'tcx> Visitor<'tcx> for MissingStabilityAnnotations<'tcx> {
|
|||
fn visit_macro_def(&mut self, md: &'tcx hir::MacroDef<'tcx>) {
|
||||
self.check_missing_stability(md.hir_id, md.span);
|
||||
}
|
||||
|
||||
// Note that we don't need to `check_missing_stability` for default generic parameters,
|
||||
// as we assume that any default generic parameters without attributes are automatically
|
||||
// stable (assuming they have not inherited instability from their parent).
|
||||
}
|
||||
|
||||
fn new_index(tcx: TyCtxt<'tcx>) -> Index<'tcx> {
|
||||
|
@ -484,6 +579,7 @@ fn new_index(tcx: TyCtxt<'tcx>) -> Index<'tcx> {
|
|||
&krate.item.attrs,
|
||||
krate.item.span,
|
||||
AnnotationKind::Required,
|
||||
InheritDeprecation::Yes,
|
||||
|v| intravisit::walk_crate(v, krate),
|
||||
);
|
||||
}
|
||||
|
|
|
@ -360,7 +360,21 @@ impl<'o, 'tcx> dyn AstConv<'tcx> + 'o {
|
|||
(GenericParamDefKind::Lifetime, GenericArg::Lifetime(lt)) => {
|
||||
self.ast_region_to_region(<, Some(param)).into()
|
||||
}
|
||||
(GenericParamDefKind::Type { .. }, GenericArg::Type(ty)) => {
|
||||
(GenericParamDefKind::Type { has_default, .. }, GenericArg::Type(ty)) => {
|
||||
if *has_default {
|
||||
tcx.check_optional_stability(
|
||||
param.def_id,
|
||||
Some(arg.id()),
|
||||
arg.span(),
|
||||
|_, _| {
|
||||
// Default generic parameters may not be marked
|
||||
// with stability attributes, i.e. when the
|
||||
// default parameter was defined at the same time
|
||||
// as the rest of the type. As such, we ignore missing
|
||||
// stability attributes.
|
||||
},
|
||||
)
|
||||
}
|
||||
if let (hir::TyKind::Infer, false) = (&ty.kind, self.allow_ty_infer()) {
|
||||
inferred_params.push(ty.span);
|
||||
tcx.ty_error().into()
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue