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:
bors 2019-12-14 10:21:32 +00:00
commit c8ea4ace92
66 changed files with 717 additions and 181 deletions

View file

@ -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()
}

View file

@ -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]> {}
}

View file

@ -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)
}

View file

@ -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);