Auto merge of #67136 - oli-obk:const_stability, r=Centril
Require stable/unstable annotations for the constness of all stable fns with a const modifier r? @RalfJung @Centril Every `#[stable]` const fn now needs either a `#[rustc_const_unstable]` attribute or a `#[rustc_const_stable]` attribute. You can't silently stabilize the constness of a function anymore.
This commit is contained in:
commit
c8ea4ace92
66 changed files with 717 additions and 181 deletions
|
|
@ -19,7 +19,7 @@ use syntax_pos::{Span, MultiSpan};
|
|||
use syntax::ast::{Attribute, CRATE_NODE_ID};
|
||||
use syntax::errors::Applicability;
|
||||
use syntax::feature_gate::{feature_err, feature_err_issue};
|
||||
use syntax::attr::{self, Stability, Deprecation, RustcDeprecation};
|
||||
use syntax::attr::{self, Stability, Deprecation, RustcDeprecation, ConstStability};
|
||||
use crate::ty::{self, TyCtxt};
|
||||
use crate::util::nodemap::{FxHashSet, FxHashMap};
|
||||
|
||||
|
|
@ -91,6 +91,7 @@ pub struct Index<'tcx> {
|
|||
/// This is mostly a cache, except the stabilities of local items
|
||||
/// are filled by the annotator.
|
||||
stab_map: FxHashMap<HirId, &'tcx Stability>,
|
||||
const_stab_map: FxHashMap<HirId, &'tcx ConstStability>,
|
||||
depr_map: FxHashMap<HirId, DeprecationEntry>,
|
||||
|
||||
/// Maps for each crate whether it is part of the staged API.
|
||||
|
|
@ -123,8 +124,14 @@ impl<'a, 'tcx> Annotator<'a, 'tcx> {
|
|||
self.tcx.sess.span_err(item_sp, "`#[deprecated]` cannot be used in staged API; \
|
||||
use `#[rustc_deprecated]` instead");
|
||||
}
|
||||
if let Some(mut stab) = attr::find_stability(&self.tcx.sess.parse_sess,
|
||||
attrs, item_sp) {
|
||||
let (stab, const_stab) = attr::find_stability(
|
||||
&self.tcx.sess.parse_sess, attrs, item_sp,
|
||||
);
|
||||
if let Some(const_stab) = const_stab {
|
||||
let const_stab = self.tcx.intern_const_stability(const_stab);
|
||||
self.index.const_stab_map.insert(hir_id, const_stab);
|
||||
}
|
||||
if let Some(mut stab) = stab {
|
||||
// Error if prohibited, or can't inherit anything from a container.
|
||||
if kind == AnnotationKind::Prohibited ||
|
||||
(kind == AnnotationKind::Container &&
|
||||
|
|
@ -189,9 +196,15 @@ impl<'a, 'tcx> Annotator<'a, 'tcx> {
|
|||
}
|
||||
} else {
|
||||
// Emit errors for non-staged-api crates.
|
||||
let unstable_attrs = [
|
||||
sym::unstable, sym::stable,
|
||||
sym::rustc_deprecated,
|
||||
sym::rustc_const_unstable,
|
||||
sym::rustc_const_stable,
|
||||
];
|
||||
for attr in attrs {
|
||||
let name = attr.name_or_empty();
|
||||
if [sym::unstable, sym::stable, sym::rustc_deprecated].contains(&name) {
|
||||
if unstable_attrs.contains(&name) {
|
||||
attr::mark_used(attr);
|
||||
struct_span_err!(
|
||||
self.tcx.sess,
|
||||
|
|
@ -399,6 +412,7 @@ impl<'tcx> Index<'tcx> {
|
|||
let mut index = Index {
|
||||
staged_api,
|
||||
stab_map: Default::default(),
|
||||
const_stab_map: Default::default(),
|
||||
depr_map: Default::default(),
|
||||
active_features: Default::default(),
|
||||
};
|
||||
|
|
@ -440,9 +454,6 @@ impl<'tcx> Index<'tcx> {
|
|||
},
|
||||
feature: sym::rustc_private,
|
||||
rustc_depr: None,
|
||||
const_stability: None,
|
||||
promotable: false,
|
||||
allow_const_fn_ptr: false,
|
||||
});
|
||||
annotator.parent_stab = Some(stability);
|
||||
}
|
||||
|
|
@ -460,6 +471,10 @@ impl<'tcx> Index<'tcx> {
|
|||
self.stab_map.get(&id).cloned()
|
||||
}
|
||||
|
||||
pub fn local_const_stability(&self, id: HirId) -> Option<&'tcx ConstStability> {
|
||||
self.const_stab_map.get(&id).cloned()
|
||||
}
|
||||
|
||||
pub fn local_deprecation_entry(&self, id: HirId) -> Option<DeprecationEntry> {
|
||||
self.depr_map.get(&id).cloned()
|
||||
}
|
||||
|
|
|
|||
|
|
@ -533,6 +533,7 @@ rustc_queries! {
|
|||
eval_always
|
||||
}
|
||||
query lookup_stability(_: DefId) -> Option<&'tcx attr::Stability> {}
|
||||
query lookup_const_stability(_: DefId) -> Option<&'tcx attr::ConstStability> {}
|
||||
query lookup_deprecation_entry(_: DefId) -> Option<DeprecationEntry> {}
|
||||
query item_attrs(_: DefId) -> Lrc<[ast::Attribute]> {}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -30,7 +30,12 @@ impl<'tcx> TyCtxt<'tcx> {
|
|||
/// Whether the `def_id` is an unstable const fn and what feature gate is necessary to enable it
|
||||
pub fn is_unstable_const_fn(self, def_id: DefId) -> Option<Symbol> {
|
||||
if self.is_const_fn_raw(def_id) {
|
||||
self.lookup_stability(def_id)?.const_stability
|
||||
let const_stab = self.lookup_const_stability(def_id)?;
|
||||
if const_stab.level.is_unstable() {
|
||||
Some(const_stab.feature)
|
||||
} else {
|
||||
None
|
||||
}
|
||||
} else {
|
||||
None
|
||||
}
|
||||
|
|
@ -83,15 +88,36 @@ impl<'tcx> TyCtxt<'tcx> {
|
|||
}
|
||||
|
||||
if self.features().staged_api {
|
||||
// in order for a libstd function to be considered min_const_fn
|
||||
// it needs to be stable and have no `rustc_const_unstable` attribute
|
||||
match self.lookup_stability(def_id) {
|
||||
// stable functions with unstable const fn aren't `min_const_fn`
|
||||
Some(&attr::Stability { const_stability: Some(_), .. }) => false,
|
||||
// unstable functions don't need to conform
|
||||
Some(&attr::Stability { ref level, .. }) if level.is_unstable() => false,
|
||||
// everything else needs to conform, because it would be callable from
|
||||
// other `min_const_fn` functions
|
||||
// In order for a libstd function to be considered min_const_fn
|
||||
// it needs to be stable and have no `rustc_const_unstable` attribute.
|
||||
match self.lookup_const_stability(def_id) {
|
||||
// `rustc_const_unstable` functions don't need to conform.
|
||||
Some(&attr::ConstStability { ref level, .. }) if level.is_unstable() => false,
|
||||
None => if let Some(stab) = self.lookup_stability(def_id) {
|
||||
if stab.level.is_stable() {
|
||||
self.sess.span_err(
|
||||
self.def_span(def_id),
|
||||
"stable const functions must have either `rustc_const_stable` or \
|
||||
`rustc_const_unstable` attribute",
|
||||
);
|
||||
// While we errored above, because we don't know if we need to conform, we
|
||||
// err on the "safe" side and require min_const_fn.
|
||||
true
|
||||
} else {
|
||||
// Unstable functions need not conform to min_const_fn.
|
||||
false
|
||||
}
|
||||
} else {
|
||||
// Internal functions are forced to conform to min_const_fn.
|
||||
// Annotate the internal function with a const stability attribute if
|
||||
// you need to use unstable features.
|
||||
// Note: this is an arbitrary choice that does not affect stability or const
|
||||
// safety or anything, it just changes whether we need to annotate some
|
||||
// internal functions with `rustc_const_stable` or with `rustc_const_unstable`
|
||||
true
|
||||
},
|
||||
// Everything else needs to conform, because it would be callable from
|
||||
// other `min_const_fn` functions.
|
||||
_ => true,
|
||||
}
|
||||
} else {
|
||||
|
|
@ -188,7 +214,7 @@ pub fn provide(providers: &mut Providers<'_>) {
|
|||
}
|
||||
|
||||
fn is_promotable_const_fn(tcx: TyCtxt<'_>, def_id: DefId) -> bool {
|
||||
tcx.is_const_fn(def_id) && match tcx.lookup_stability(def_id) {
|
||||
tcx.is_const_fn(def_id) && match tcx.lookup_const_stability(def_id) {
|
||||
Some(stab) => {
|
||||
if cfg!(debug_assertions) && stab.promotable {
|
||||
let sig = tcx.fn_sig(def_id);
|
||||
|
|
@ -207,7 +233,7 @@ pub fn provide(providers: &mut Providers<'_>) {
|
|||
|
||||
fn const_fn_is_allowed_fn_ptr(tcx: TyCtxt<'_>, def_id: DefId) -> bool {
|
||||
tcx.is_const_fn(def_id) &&
|
||||
tcx.lookup_stability(def_id)
|
||||
tcx.lookup_const_stability(def_id)
|
||||
.map(|stab| stab.allow_const_fn_ptr).unwrap_or(false)
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -1066,8 +1066,12 @@ pub struct GlobalCtxt<'tcx> {
|
|||
/// Data layout specification for the current target.
|
||||
pub data_layout: TargetDataLayout,
|
||||
|
||||
/// `#[stable]` and `#[unstable]` attributes
|
||||
stability_interner: ShardedHashMap<&'tcx attr::Stability, ()>,
|
||||
|
||||
/// `#[rustc_const_stable]` and `#[rustc_const_unstable]` attributes
|
||||
const_stability_interner: ShardedHashMap<&'tcx attr::ConstStability, ()>,
|
||||
|
||||
/// Stores the value of constants (and deduplicates the actual memory)
|
||||
allocation_interner: ShardedHashMap<&'tcx Allocation, ()>,
|
||||
|
||||
|
|
@ -1129,6 +1133,12 @@ impl<'tcx> TyCtxt<'tcx> {
|
|||
})
|
||||
}
|
||||
|
||||
pub fn intern_const_stability(self, stab: attr::ConstStability) -> &'tcx attr::ConstStability {
|
||||
self.const_stability_interner.intern(stab, |stab| {
|
||||
self.arena.alloc(stab)
|
||||
})
|
||||
}
|
||||
|
||||
pub fn intern_layout(self, layout: LayoutDetails) -> &'tcx LayoutDetails {
|
||||
self.layout_interner.intern(layout, |layout| {
|
||||
self.arena.alloc(layout)
|
||||
|
|
@ -1269,6 +1279,7 @@ impl<'tcx> TyCtxt<'tcx> {
|
|||
data_layout,
|
||||
layout_interner: Default::default(),
|
||||
stability_interner: Default::default(),
|
||||
const_stability_interner: Default::default(),
|
||||
allocation_interner: Default::default(),
|
||||
alloc_map: Lock::new(interpret::AllocMap::new()),
|
||||
output_filenames: Arc::new(output_filenames.clone()),
|
||||
|
|
@ -2058,6 +2069,7 @@ impl<'tcx> TyCtxt<'tcx> {
|
|||
println!("InternalSubsts interner: #{}", self.interners.substs.len());
|
||||
println!("Region interner: #{}", self.interners.region.len());
|
||||
println!("Stability interner: #{}", self.stability_interner.len());
|
||||
println!("Const Stability interner: #{}", self.const_stability_interner.len());
|
||||
println!("Allocation interner: #{}", self.allocation_interner.len());
|
||||
println!("Layout interner: #{}", self.layout_interner.len());
|
||||
}
|
||||
|
|
@ -2992,6 +3004,11 @@ pub fn provide(providers: &mut ty::query::Providers<'_>) {
|
|||
let id = tcx.hir().definitions().def_index_to_hir_id(id.index);
|
||||
tcx.stability().local_stability(id)
|
||||
};
|
||||
providers.lookup_const_stability = |tcx, id| {
|
||||
assert_eq!(id.krate, LOCAL_CRATE);
|
||||
let id = tcx.hir().definitions().def_index_to_hir_id(id.index);
|
||||
tcx.stability().local_const_stability(id)
|
||||
};
|
||||
providers.lookup_deprecation_entry = |tcx, id| {
|
||||
assert_eq!(id.krate, LOCAL_CRATE);
|
||||
let id = tcx.hir().definitions().def_index_to_hir_id(id.index);
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue