Rollup merge of #67781 - cjgillot:passes-const, r=oli-obk
Move `is_min_const_fn` query to librustc_mir. The only two uses of the associated methods are in `librustc_mir` and `librustdoc`. Please tell me if there is a better choice. cc #65031
This commit is contained in:
commit
b85b1dd465
|
@ -1,156 +0,0 @@
|
|||
use crate::hir::map::blocks::FnLikeNode;
|
||||
use crate::ty::query::Providers;
|
||||
use crate::ty::TyCtxt;
|
||||
use rustc_hir as hir;
|
||||
use rustc_hir::def_id::DefId;
|
||||
use rustc_span::symbol::Symbol;
|
||||
use rustc_target::spec::abi::Abi;
|
||||
use syntax::attr;
|
||||
|
||||
impl<'tcx> TyCtxt<'tcx> {
|
||||
/// Whether the `def_id` counts as const fn in your current crate, considering all active
|
||||
/// feature gates
|
||||
pub fn is_const_fn(self, def_id: DefId) -> bool {
|
||||
self.is_const_fn_raw(def_id)
|
||||
&& match self.is_unstable_const_fn(def_id) {
|
||||
Some(feature_name) => {
|
||||
// has a `rustc_const_unstable` attribute, check whether the user enabled the
|
||||
// corresponding feature gate.
|
||||
self.features()
|
||||
.declared_lib_features
|
||||
.iter()
|
||||
.any(|&(sym, _)| sym == feature_name)
|
||||
}
|
||||
// functions without const stability are either stable user written
|
||||
// const fn or the user is using feature gates and we thus don't
|
||||
// care what they do
|
||||
None => true,
|
||||
}
|
||||
}
|
||||
|
||||
/// 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) {
|
||||
let const_stab = self.lookup_const_stability(def_id)?;
|
||||
if const_stab.level.is_unstable() { Some(const_stab.feature) } else { None }
|
||||
} else {
|
||||
None
|
||||
}
|
||||
}
|
||||
|
||||
/// Returns `true` if this function must conform to `min_const_fn`
|
||||
pub fn is_min_const_fn(self, def_id: DefId) -> bool {
|
||||
// Bail out if the signature doesn't contain `const`
|
||||
if !self.is_const_fn_raw(def_id) {
|
||||
return false;
|
||||
}
|
||||
|
||||
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_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 {
|
||||
// users enabling the `const_fn` feature gate can do what they want
|
||||
!self.features().const_fn
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
pub fn provide(providers: &mut Providers<'_>) {
|
||||
/// Const evaluability whitelist is here to check evaluability at the
|
||||
/// top level beforehand.
|
||||
fn is_const_intrinsic(tcx: TyCtxt<'_>, def_id: DefId) -> Option<bool> {
|
||||
match tcx.fn_sig(def_id).abi() {
|
||||
Abi::RustIntrinsic | Abi::PlatformIntrinsic => {
|
||||
Some(tcx.lookup_const_stability(def_id).is_some())
|
||||
}
|
||||
_ => None,
|
||||
}
|
||||
}
|
||||
|
||||
/// Checks whether the function has a `const` modifier or, in case it is an intrinsic, whether
|
||||
/// said intrinsic is on the whitelist for being const callable.
|
||||
fn is_const_fn_raw(tcx: TyCtxt<'_>, def_id: DefId) -> bool {
|
||||
let hir_id = tcx
|
||||
.hir()
|
||||
.as_local_hir_id(def_id)
|
||||
.expect("Non-local call to local provider is_const_fn");
|
||||
|
||||
let node = tcx.hir().get(hir_id);
|
||||
|
||||
if let Some(whitelisted) = is_const_intrinsic(tcx, def_id) {
|
||||
whitelisted
|
||||
} else if let Some(fn_like) = FnLikeNode::from_node(node) {
|
||||
fn_like.constness() == hir::Constness::Const
|
||||
} else if let hir::Node::Ctor(_) = node {
|
||||
true
|
||||
} else {
|
||||
false
|
||||
}
|
||||
}
|
||||
|
||||
fn is_promotable_const_fn(tcx: TyCtxt<'_>, def_id: DefId) -> bool {
|
||||
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);
|
||||
assert_eq!(
|
||||
sig.unsafety(),
|
||||
hir::Unsafety::Normal,
|
||||
"don't mark const unsafe fns as promotable",
|
||||
// https://github.com/rust-lang/rust/pull/53851#issuecomment-418760682
|
||||
);
|
||||
}
|
||||
stab.promotable
|
||||
}
|
||||
None => false,
|
||||
}
|
||||
}
|
||||
|
||||
fn const_fn_is_allowed_fn_ptr(tcx: TyCtxt<'_>, def_id: DefId) -> bool {
|
||||
tcx.is_const_fn(def_id)
|
||||
&& tcx
|
||||
.lookup_const_stability(def_id)
|
||||
.map(|stab| stab.allow_const_fn_ptr)
|
||||
.unwrap_or(false)
|
||||
}
|
||||
|
||||
*providers = Providers {
|
||||
is_const_fn_raw,
|
||||
is_promotable_const_fn,
|
||||
const_fn_is_allowed_fn_ptr,
|
||||
..*providers
|
||||
};
|
||||
}
|
|
@ -97,7 +97,6 @@ pub mod cast;
|
|||
#[macro_use]
|
||||
pub mod codec;
|
||||
pub mod _match;
|
||||
mod constness;
|
||||
mod erase_regions;
|
||||
pub mod error;
|
||||
pub mod fast_reject;
|
||||
|
@ -3318,7 +3317,6 @@ pub fn provide(providers: &mut ty::query::Providers<'_>) {
|
|||
context::provide(providers);
|
||||
erase_regions::provide(providers);
|
||||
layout::provide(providers);
|
||||
constness::provide(providers);
|
||||
*providers = ty::query::Providers {
|
||||
asyncness,
|
||||
associated_item,
|
||||
|
|
|
@ -9,10 +9,12 @@ use crate::interpret::{intern_const_alloc_recursive, ConstValue, InterpCx};
|
|||
|
||||
mod error;
|
||||
mod eval_queries;
|
||||
mod fn_queries;
|
||||
mod machine;
|
||||
|
||||
pub use error::*;
|
||||
pub use eval_queries::*;
|
||||
pub use fn_queries::*;
|
||||
pub use machine::*;
|
||||
|
||||
/// Extracts a field of a (variant of a) const.
|
||||
|
|
|
@ -0,0 +1,151 @@
|
|||
use rustc::hir::map::blocks::FnLikeNode;
|
||||
use rustc::ty::query::Providers;
|
||||
use rustc::ty::TyCtxt;
|
||||
use rustc_hir as hir;
|
||||
use rustc_hir::def_id::DefId;
|
||||
use rustc_span::symbol::Symbol;
|
||||
use rustc_target::spec::abi::Abi;
|
||||
use syntax::attr;
|
||||
|
||||
/// Whether the `def_id` counts as const fn in your current crate, considering all active
|
||||
/// feature gates
|
||||
pub fn is_const_fn(tcx: TyCtxt<'_>, def_id: DefId) -> bool {
|
||||
tcx.is_const_fn_raw(def_id)
|
||||
&& match is_unstable_const_fn(tcx, def_id) {
|
||||
Some(feature_name) => {
|
||||
// has a `rustc_const_unstable` attribute, check whether the user enabled the
|
||||
// corresponding feature gate.
|
||||
tcx.features().declared_lib_features.iter().any(|&(sym, _)| sym == feature_name)
|
||||
}
|
||||
// functions without const stability are either stable user written
|
||||
// const fn or the user is using feature gates and we thus don't
|
||||
// care what they do
|
||||
None => true,
|
||||
}
|
||||
}
|
||||
|
||||
/// Whether the `def_id` is an unstable const fn and what feature gate is necessary to enable it
|
||||
pub fn is_unstable_const_fn(tcx: TyCtxt<'_>, def_id: DefId) -> Option<Symbol> {
|
||||
if tcx.is_const_fn_raw(def_id) {
|
||||
let const_stab = tcx.lookup_const_stability(def_id)?;
|
||||
if const_stab.level.is_unstable() { Some(const_stab.feature) } else { None }
|
||||
} else {
|
||||
None
|
||||
}
|
||||
}
|
||||
|
||||
/// Returns `true` if this function must conform to `min_const_fn`
|
||||
pub fn is_min_const_fn(tcx: TyCtxt<'_>, def_id: DefId) -> bool {
|
||||
// Bail out if the signature doesn't contain `const`
|
||||
if !tcx.is_const_fn_raw(def_id) {
|
||||
return false;
|
||||
}
|
||||
|
||||
if tcx.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 tcx.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) = tcx.lookup_stability(def_id) {
|
||||
if stab.level.is_stable() {
|
||||
tcx.sess.span_err(
|
||||
tcx.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 {
|
||||
// users enabling the `const_fn` feature gate can do what they want
|
||||
!tcx.features().const_fn
|
||||
}
|
||||
}
|
||||
|
||||
pub fn provide(providers: &mut Providers<'_>) {
|
||||
/// Const evaluability whitelist is here to check evaluability at the
|
||||
/// top level beforehand.
|
||||
fn is_const_intrinsic(tcx: TyCtxt<'_>, def_id: DefId) -> Option<bool> {
|
||||
match tcx.fn_sig(def_id).abi() {
|
||||
Abi::RustIntrinsic | Abi::PlatformIntrinsic => {
|
||||
Some(tcx.lookup_const_stability(def_id).is_some())
|
||||
}
|
||||
_ => None,
|
||||
}
|
||||
}
|
||||
|
||||
/// Checks whether the function has a `const` modifier or, in case it is an intrinsic, whether
|
||||
/// said intrinsic is on the whitelist for being const callable.
|
||||
fn is_const_fn_raw(tcx: TyCtxt<'_>, def_id: DefId) -> bool {
|
||||
let hir_id = tcx
|
||||
.hir()
|
||||
.as_local_hir_id(def_id)
|
||||
.expect("Non-local call to local provider is_const_fn");
|
||||
|
||||
let node = tcx.hir().get(hir_id);
|
||||
|
||||
if let Some(whitelisted) = is_const_intrinsic(tcx, def_id) {
|
||||
whitelisted
|
||||
} else if let Some(fn_like) = FnLikeNode::from_node(node) {
|
||||
fn_like.constness() == hir::Constness::Const
|
||||
} else if let hir::Node::Ctor(_) = node {
|
||||
true
|
||||
} else {
|
||||
false
|
||||
}
|
||||
}
|
||||
|
||||
fn is_promotable_const_fn(tcx: TyCtxt<'_>, def_id: DefId) -> bool {
|
||||
is_const_fn(tcx, def_id)
|
||||
&& match tcx.lookup_const_stability(def_id) {
|
||||
Some(stab) => {
|
||||
if cfg!(debug_assertions) && stab.promotable {
|
||||
let sig = tcx.fn_sig(def_id);
|
||||
assert_eq!(
|
||||
sig.unsafety(),
|
||||
hir::Unsafety::Normal,
|
||||
"don't mark const unsafe fns as promotable",
|
||||
// https://github.com/rust-lang/rust/pull/53851#issuecomment-418760682
|
||||
);
|
||||
}
|
||||
stab.promotable
|
||||
}
|
||||
None => false,
|
||||
}
|
||||
}
|
||||
|
||||
fn const_fn_is_allowed_fn_ptr(tcx: TyCtxt<'_>, def_id: DefId) -> bool {
|
||||
is_const_fn(tcx, def_id)
|
||||
&& tcx
|
||||
.lookup_const_stability(def_id)
|
||||
.map(|stab| stab.allow_const_fn_ptr)
|
||||
.unwrap_or(false)
|
||||
}
|
||||
|
||||
*providers = Providers {
|
||||
is_const_fn_raw,
|
||||
is_promotable_const_fn,
|
||||
const_fn_is_allowed_fn_ptr,
|
||||
..*providers
|
||||
};
|
||||
}
|
|
@ -52,6 +52,7 @@ use rustc::ty::query::Providers;
|
|||
|
||||
pub fn provide(providers: &mut Providers<'_>) {
|
||||
borrow_check::provide(providers);
|
||||
const_eval::provide(providers);
|
||||
shim::provide(providers);
|
||||
transform::provide(providers);
|
||||
monomorphize::partitioning::provide(providers);
|
||||
|
|
|
@ -21,6 +21,7 @@ use super::ops::{self, NonConstOp};
|
|||
use super::qualifs::{self, HasMutInterior, NeedsDrop};
|
||||
use super::resolver::FlowSensitiveAnalysis;
|
||||
use super::{is_lang_panic_fn, ConstKind, Item, Qualif};
|
||||
use crate::const_eval::{is_const_fn, is_unstable_const_fn};
|
||||
use crate::dataflow::{self as old_dataflow, generic as dataflow};
|
||||
|
||||
pub type IndirectlyMutableResults<'mir, 'tcx> =
|
||||
|
@ -173,7 +174,7 @@ impl Validator<'a, 'mir, 'tcx> {
|
|||
let Item { tcx, body, def_id, const_kind, .. } = *self.item;
|
||||
|
||||
let use_min_const_fn_checks = (const_kind == Some(ConstKind::ConstFn)
|
||||
&& tcx.is_min_const_fn(def_id))
|
||||
&& crate::const_eval::is_min_const_fn(tcx, def_id))
|
||||
&& !tcx.sess.opts.debugging_opts.unleash_the_miri_inside_of_you;
|
||||
|
||||
if use_min_const_fn_checks {
|
||||
|
@ -560,13 +561,13 @@ impl Visitor<'tcx> for Validator<'_, 'mir, 'tcx> {
|
|||
};
|
||||
|
||||
// At this point, we are calling a function whose `DefId` is known...
|
||||
if self.tcx.is_const_fn(def_id) {
|
||||
if is_const_fn(self.tcx, def_id) {
|
||||
return;
|
||||
}
|
||||
|
||||
if is_lang_panic_fn(self.tcx, def_id) {
|
||||
self.check_op(ops::Panic);
|
||||
} else if let Some(feature) = self.tcx.is_unstable_const_fn(def_id) {
|
||||
} else if let Some(feature) = is_unstable_const_fn(self.tcx, def_id) {
|
||||
// Exempt unstable const fns inside of macros with
|
||||
// `#[allow_internal_unstable]`.
|
||||
if !self.span.allows_unstable(feature) {
|
||||
|
|
|
@ -14,6 +14,7 @@ use rustc_span::symbol::{sym, Symbol};
|
|||
|
||||
use std::ops::Bound;
|
||||
|
||||
use crate::const_eval::{is_const_fn, is_min_const_fn};
|
||||
use crate::util;
|
||||
|
||||
use rustc_error_codes::*;
|
||||
|
@ -523,7 +524,7 @@ fn unsafety_check_result(tcx: TyCtxt<'_>, def_id: DefId) -> UnsafetyCheckResult
|
|||
let id = tcx.hir().as_local_hir_id(def_id).unwrap();
|
||||
let (const_context, min_const_fn) = match tcx.hir().body_owner_kind(id) {
|
||||
hir::BodyOwnerKind::Closure => (false, false),
|
||||
hir::BodyOwnerKind::Fn => (tcx.is_const_fn(def_id), tcx.is_min_const_fn(def_id)),
|
||||
hir::BodyOwnerKind::Fn => (is_const_fn(tcx, def_id), is_min_const_fn(tcx, def_id)),
|
||||
hir::BodyOwnerKind::Const | hir::BodyOwnerKind::Static(_) => (true, false),
|
||||
};
|
||||
let mut checker = UnsafetyChecker::new(const_context, min_const_fn, body, tcx, param_env);
|
||||
|
|
|
@ -29,6 +29,7 @@ use rustc_target::spec::abi::Abi;
|
|||
use std::cell::Cell;
|
||||
use std::{iter, mem, usize};
|
||||
|
||||
use crate::const_eval::{is_const_fn, is_unstable_const_fn};
|
||||
use crate::transform::check_consts::{is_lang_panic_fn, qualifs, ConstKind, Item};
|
||||
use crate::transform::{MirPass, MirSource};
|
||||
|
||||
|
@ -702,8 +703,8 @@ impl<'tcx> Validator<'_, 'tcx> {
|
|||
|
||||
let is_const_fn = match fn_ty.kind {
|
||||
ty::FnDef(def_id, _) => {
|
||||
self.tcx.is_const_fn(def_id)
|
||||
|| self.tcx.is_unstable_const_fn(def_id).is_some()
|
||||
is_const_fn(self.tcx, def_id)
|
||||
|| is_unstable_const_fn(self.tcx, def_id).is_some()
|
||||
|| is_lang_panic_fn(self.tcx, self.def_id)
|
||||
}
|
||||
_ => false,
|
||||
|
|
|
@ -327,7 +327,7 @@ fn check_terminator(
|
|||
TerminatorKind::Call { func, args, from_hir_call: _, destination: _, cleanup: _ } => {
|
||||
let fn_ty = func.ty(body, tcx);
|
||||
if let ty::FnDef(def_id, _) = fn_ty.kind {
|
||||
if !tcx.is_min_const_fn(def_id) {
|
||||
if !crate::const_eval::is_min_const_fn(tcx, def_id) {
|
||||
return Err((
|
||||
span,
|
||||
format!(
|
||||
|
|
|
@ -9,6 +9,7 @@ use rustc_hir::def::{CtorKind, DefKind, Res};
|
|||
use rustc_hir::def_id::DefId;
|
||||
use rustc_hir::Mutability;
|
||||
use rustc_metadata::creader::LoadedMacro;
|
||||
use rustc_mir::const_eval::is_min_const_fn;
|
||||
use rustc_span::hygiene::MacroKind;
|
||||
use rustc_span::symbol::sym;
|
||||
use rustc_span::Span;
|
||||
|
@ -212,7 +213,7 @@ fn build_external_function(cx: &DocContext<'_>, did: DefId) -> clean::Function {
|
|||
let sig = cx.tcx.fn_sig(did);
|
||||
|
||||
let constness =
|
||||
if cx.tcx.is_min_const_fn(did) { hir::Constness::Const } else { hir::Constness::NotConst };
|
||||
if is_min_const_fn(cx.tcx, did) { hir::Constness::Const } else { hir::Constness::NotConst };
|
||||
let asyncness = cx.tcx.asyncness(did);
|
||||
let predicates = cx.tcx.predicates_of(did);
|
||||
let (generics, decl) = clean::enter_impl_trait(cx, || {
|
||||
|
|
|
@ -21,6 +21,7 @@ use rustc_hir as hir;
|
|||
use rustc_hir::def::{CtorKind, DefKind, Res};
|
||||
use rustc_hir::def_id::{CrateNum, DefId, CRATE_DEF_INDEX};
|
||||
use rustc_index::vec::{Idx, IndexVec};
|
||||
use rustc_mir::const_eval::is_min_const_fn;
|
||||
use rustc_span::hygiene::MacroKind;
|
||||
use rustc_span::symbol::{kw, sym};
|
||||
use rustc_span::{self, Pos};
|
||||
|
@ -895,7 +896,7 @@ impl Clean<Item> for doctree::Function<'_> {
|
|||
enter_impl_trait(cx, || (self.generics.clean(cx), (self.decl, self.body).clean(cx)));
|
||||
|
||||
let did = cx.tcx.hir().local_def_id(self.id);
|
||||
let constness = if cx.tcx.is_min_const_fn(did) {
|
||||
let constness = if is_min_const_fn(cx.tcx, did) {
|
||||
hir::Constness::Const
|
||||
} else {
|
||||
hir::Constness::NotConst
|
||||
|
@ -1187,7 +1188,7 @@ impl Clean<Item> for ty::AssocItem {
|
|||
};
|
||||
let (all_types, ret_types) = get_all_types(&generics, &decl, cx);
|
||||
if provided {
|
||||
let constness = if cx.tcx.is_min_const_fn(self.def_id) {
|
||||
let constness = if is_min_const_fn(cx.tcx, self.def_id) {
|
||||
hir::Constness::Const
|
||||
} else {
|
||||
hir::Constness::NotConst
|
||||
|
|
|
@ -32,6 +32,7 @@ extern crate rustc_interface;
|
|||
extern crate rustc_lexer;
|
||||
extern crate rustc_lint;
|
||||
extern crate rustc_metadata;
|
||||
extern crate rustc_mir;
|
||||
extern crate rustc_parse;
|
||||
extern crate rustc_resolve;
|
||||
extern crate rustc_span as rustc_span;
|
||||
|
|
Loading…
Reference in New Issue