Skip to content

Commit

Permalink
Rollup merge of rust-lang#67781 - cjgillot:passes-const, r=oli-obk
Browse files Browse the repository at this point in the history
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 rust-lang#65031
  • Loading branch information
JohnTitor authored Jan 8, 2020
2 parents 9f8f97b + c1c09be commit b85b1dd
Show file tree
Hide file tree
Showing 12 changed files with 170 additions and 168 deletions.
156 changes: 0 additions & 156 deletions src/librustc/ty/constness.rs

This file was deleted.

2 changes: 0 additions & 2 deletions src/librustc/ty/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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;
Expand Down Expand Up @@ -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,
Expand Down
2 changes: 2 additions & 0 deletions src/librustc_mir/const_eval.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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.
Expand Down
151 changes: 151 additions & 0 deletions src/librustc_mir/const_eval/fn_queries.rs
Original file line number Diff line number Diff line change
@@ -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
};
}
1 change: 1 addition & 0 deletions src/librustc_mir/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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);
Expand Down
7 changes: 4 additions & 3 deletions src/librustc_mir/transform/check_consts/validation.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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> =
Expand Down Expand Up @@ -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 {
Expand Down Expand Up @@ -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) {
Expand Down
3 changes: 2 additions & 1 deletion src/librustc_mir/transform/check_unsafety.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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::*;
Expand Down Expand Up @@ -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);
Expand Down
Loading

0 comments on commit b85b1dd

Please sign in to comment.