Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Implement the min_const_fn feature gate #53604

Merged
merged 6 commits into from
Sep 1, 2018
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
3 changes: 2 additions & 1 deletion src/liballoc/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -88,7 +88,8 @@
#![feature(box_syntax)]
#![feature(cfg_target_has_atomic)]
#![feature(coerce_unsized)]
#![feature(const_fn)]
#![cfg_attr(stage0, feature(const_fn))]
#![cfg_attr(not(stage0), feature(min_const_fn))]
#![feature(core_intrinsics)]
#![feature(custom_attribute)]
#![feature(dropck_eyepatch)]
Expand Down
3 changes: 2 additions & 1 deletion src/liballoc/tests/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,8 @@
#![feature(allocator_api)]
#![feature(alloc_system)]
#![feature(box_syntax)]
#![feature(const_fn)]
#![cfg_attr(stage0, feature(const_fn))]
#![cfg_attr(not(stage0), feature(min_const_fn))]
#![feature(drain_filter)]
#![feature(exact_size_is_empty)]
#![feature(pattern)]
Expand Down
28 changes: 28 additions & 0 deletions src/libcore/mem.rs
Original file line number Diff line number Diff line change
Expand Up @@ -285,6 +285,15 @@ pub fn forget<T>(t: T) {
/// [alignment]: ./fn.align_of.html
#[inline]
#[stable(feature = "rust1", since = "1.0.0")]
#[cfg(not(stage0))]
pub const fn size_of<T>() -> usize {
intrinsics::size_of::<T>()
}

#[inline]
#[stable(feature = "rust1", since = "1.0.0")]
#[cfg(stage0)]
/// Ceci n'est pas la documentation
pub const fn size_of<T>() -> usize {
unsafe { intrinsics::size_of::<T>() }
}
Expand Down Expand Up @@ -334,6 +343,16 @@ pub fn size_of_val<T: ?Sized>(val: &T) -> usize {
#[inline]
#[stable(feature = "rust1", since = "1.0.0")]
#[rustc_deprecated(reason = "use `align_of` instead", since = "1.2.0")]
#[cfg(not(stage0))]
pub fn min_align_of<T>() -> usize {
intrinsics::min_align_of::<T>()
}

#[inline]
#[stable(feature = "rust1", since = "1.0.0")]
#[rustc_deprecated(reason = "use `align_of` instead", since = "1.2.0")]
#[cfg(stage0)]
/// Ceci n'est pas la documentation
pub fn min_align_of<T>() -> usize {
unsafe { intrinsics::min_align_of::<T>() }
}
Expand Down Expand Up @@ -376,6 +395,15 @@ pub fn min_align_of_val<T: ?Sized>(val: &T) -> usize {
/// ```
#[inline]
#[stable(feature = "rust1", since = "1.0.0")]
#[cfg(not(stage0))]
pub const fn align_of<T>() -> usize {
intrinsics::min_align_of::<T>()
}

#[inline]
#[stable(feature = "rust1", since = "1.0.0")]
#[cfg(stage0)]
/// Ceci n'est pas la documentation
pub const fn align_of<T>() -> usize {
unsafe { intrinsics::min_align_of::<T>() }
}
Expand Down
1 change: 1 addition & 0 deletions src/librustc/ich/impls_mir.rs
Original file line number Diff line number Diff line change
Expand Up @@ -65,6 +65,7 @@ for mir::UnsafetyViolationKind {

match *self {
mir::UnsafetyViolationKind::General => {}
mir::UnsafetyViolationKind::MinConstFn => {}
mir::UnsafetyViolationKind::ExternStatic(lint_node_id) |
mir::UnsafetyViolationKind::BorrowPacked(lint_node_id) => {
lint_node_id.hash_stable(hcx, hasher);
Expand Down
3 changes: 1 addition & 2 deletions src/librustc/ich/impls_syntax.rs
Original file line number Diff line number Diff line change
Expand Up @@ -130,7 +130,7 @@ impl_stable_hash_for!(struct ::syntax::attr::Stability {
level,
feature,
rustc_depr,
rustc_const_unstable
const_stability
});

impl<'a> HashStable<StableHashingContext<'a>>
Expand Down Expand Up @@ -161,7 +161,6 @@ for ::syntax::attr::StabilityLevel {
}

impl_stable_hash_for!(struct ::syntax::attr::RustcDeprecation { since, reason });
impl_stable_hash_for!(struct ::syntax::attr::RustcConstUnstable { feature });


impl_stable_hash_for!(enum ::syntax::attr::IntType {
Expand Down
3 changes: 2 additions & 1 deletion src/librustc/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -42,7 +42,8 @@

#![feature(box_patterns)]
#![feature(box_syntax)]
#![feature(const_fn)]
#![cfg_attr(stage0, feature(const_fn))]
#![cfg_attr(not(stage0), feature(min_const_fn))]
#![feature(core_intrinsics)]
#![feature(drain_filter)]
#![cfg_attr(windows, feature(libc))]
Expand Down
2 changes: 1 addition & 1 deletion src/librustc/middle/stability.rs
Original file line number Diff line number Diff line change
Expand Up @@ -440,7 +440,7 @@ impl<'a, 'tcx> Index<'tcx> {
},
feature: Symbol::intern("rustc_private"),
rustc_depr: None,
rustc_const_unstable: None,
const_stability: None,
});
annotator.parent_stab = Some(stability);
}
Expand Down
2 changes: 2 additions & 0 deletions src/librustc/mir/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -2394,6 +2394,8 @@ impl Location {
#[derive(Copy, Clone, Debug, PartialEq, Eq, Hash, RustcEncodable, RustcDecodable)]
pub enum UnsafetyViolationKind {
General,
/// unsafety is not allowed at all in min const fn
MinConstFn,
ExternStatic(ast::NodeId),
BorrowPacked(ast::NodeId),
}
Expand Down
31 changes: 31 additions & 0 deletions src/librustc/ty/context.rs
Original file line number Diff line number Diff line change
Expand Up @@ -1099,6 +1099,37 @@ impl<'a, 'gcx, 'tcx> TyCtxt<'a, 'gcx, 'tcx> {
local as usize == global as usize
}

/// Returns true if this function must conform to `min_const_fn`
pub fn is_min_const_fn(self, def_id: DefId) -> bool {
if self.features().staged_api {
// some intrinsics are waved through if called inside the
// standard library. Users never need to call them directly
if let abi::Abi::RustIntrinsic = self.fn_sig(def_id).abi() {
assert!(!self.is_const_fn(def_id));
match &self.item_name(def_id).as_str()[..] {
| "size_of"
| "min_align_of"
=> return true,
_ => {},
}
}
// 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
_ => true,
}
} else {
// users enabling the `const_fn` can do what they want
!self.sess.features_untracked().const_fn
}
}

/// Create a type context and call the closure with a `TyCtxt` reference
/// to the context. The closure enforces that the type context and any interned
/// value (types, substs, etc.) can only be used while `ty::tls` has a valid
Expand Down
8 changes: 2 additions & 6 deletions src/librustc_mir/hair/cx/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -18,7 +18,6 @@ use hair::*;

use rustc_data_structures::indexed_vec::Idx;
use rustc::hir::def_id::{DefId, LOCAL_CRATE};
use rustc::hir::map::blocks::FnLikeNode;
use rustc::hir::Node;
use rustc::middle::region;
use rustc::infer::InferCtxt;
Expand Down Expand Up @@ -67,10 +66,7 @@ impl<'a, 'gcx, 'tcx> Cx<'a, 'gcx, 'tcx> {
let constness = match body_owner_kind {
hir::BodyOwnerKind::Const |
hir::BodyOwnerKind::Static(_) => hir::Constness::Const,
hir::BodyOwnerKind::Fn => {
let fn_like = FnLikeNode::from_node(infcx.tcx.hir.get(src_id));
fn_like.map_or(hir::Constness::NotConst, |f| f.constness())
}
hir::BodyOwnerKind::Fn => hir::Constness::NotConst,
};

let attrs = tcx.hir.attrs(src_id);
Expand All @@ -83,7 +79,7 @@ impl<'a, 'gcx, 'tcx> Cx<'a, 'gcx, 'tcx> {
// Respect -C overflow-checks.
check_overflow |= tcx.sess.overflow_checks();

// Constants and const fn's always need overflow checks.
// Constants always need overflow checks.
check_overflow |= constness == hir::Constness::Const;

let lint_level = lint_level_for_hir_id(tcx, src_id);
Expand Down
1 change: 0 additions & 1 deletion src/librustc_mir/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -23,7 +23,6 @@ Rust MIR: a lowered representation of Rust. Also: an experiment!
#![feature(box_patterns)]
#![feature(box_syntax)]
#![feature(crate_visibility_modifier)]
#![feature(const_fn)]
#![feature(core_intrinsics)]
#![feature(decl_macro)]
#![cfg_attr(stage0, feature(macro_vis_matcher))]
Expand Down
33 changes: 28 additions & 5 deletions src/librustc_mir/transform/check_unsafety.rs
Original file line number Diff line number Diff line change
Expand Up @@ -28,6 +28,7 @@ use util;

pub struct UnsafetyChecker<'a, 'tcx: 'a> {
mir: &'a Mir<'tcx>,
min_const_fn: bool,
source_scope_local_data: &'a IndexVec<SourceScope, SourceScopeLocalData>,
violations: Vec<UnsafetyViolation>,
source_info: SourceInfo,
Expand All @@ -38,12 +39,16 @@ pub struct UnsafetyChecker<'a, 'tcx: 'a> {
}

impl<'a, 'gcx, 'tcx> UnsafetyChecker<'a, 'tcx> {
fn new(mir: &'a Mir<'tcx>,
source_scope_local_data: &'a IndexVec<SourceScope, SourceScopeLocalData>,
tcx: TyCtxt<'a, 'tcx, 'tcx>,
param_env: ty::ParamEnv<'tcx>) -> Self {
fn new(
min_const_fn: bool,
mir: &'a Mir<'tcx>,
source_scope_local_data: &'a IndexVec<SourceScope, SourceScopeLocalData>,
tcx: TyCtxt<'a, 'tcx, 'tcx>,
param_env: ty::ParamEnv<'tcx>,
) -> Self {
Self {
mir,
min_const_fn,
source_scope_local_data,
violations: vec![],
source_info: SourceInfo {
Expand Down Expand Up @@ -269,14 +274,22 @@ impl<'a, 'tcx> UnsafetyChecker<'a, 'tcx> {
fn register_violations(&mut self,
violations: &[UnsafetyViolation],
unsafe_blocks: &[(ast::NodeId, bool)]) {
if self.min_const_fn {
for violation in violations {
let mut violation = violation.clone();
violation.kind = UnsafetyViolationKind::MinConstFn;
if !self.violations.contains(&violation) {
self.violations.push(violation)
}
}
}
let within_unsafe = match self.source_scope_local_data[self.source_info.scope].safety {
Safety::Safe => {
for violation in violations {
if !self.violations.contains(violation) {
self.violations.push(violation.clone())
}
}

false
}
Safety::BuiltinUnsafe | Safety::FnUnsafe => true,
Expand Down Expand Up @@ -369,6 +382,7 @@ fn unsafety_check_result<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>, def_id: DefId)

let param_env = tcx.param_env(def_id);
let mut checker = UnsafetyChecker::new(
tcx.is_const_fn(def_id) && tcx.is_min_const_fn(def_id),
mir, source_scope_local_data, tcx, param_env);
checker.visit_mir(mir);

Expand Down Expand Up @@ -478,6 +492,15 @@ pub fn check_unsafety<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>, def_id: DefId) {
.note(&details.as_str()[..])
.emit();
}
UnsafetyViolationKind::MinConstFn => {
Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

fun side effect: the two cases below which are future compat lints are hard errors inside const fns

tcx.sess.struct_span_err(
source_info.span,
&format!("{} is unsafe and unsafe operations \
are not allowed in const fn", description))
.span_label(source_info.span, &description.as_str()[..])
.note(&details.as_str()[..])
.emit();
}
UnsafetyViolationKind::ExternStatic(lint_node_id) => {
tcx.lint_node_note(SAFE_EXTERN_STATICS,
lint_node_id,
Expand Down
1 change: 1 addition & 0 deletions src/librustc_mir/transform/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -36,6 +36,7 @@ pub mod elaborate_drops;
pub mod add_call_guards;
pub mod promote_consts;
pub mod qualify_consts;
mod qualify_min_const_fn;
pub mod remove_noop_landing_pads;
pub mod dump_mir;
pub mod deaggregator;
Expand Down
20 changes: 15 additions & 5 deletions src/librustc_mir/transform/qualify_consts.rs
Original file line number Diff line number Diff line change
Expand Up @@ -916,9 +916,7 @@ impl<'a, 'tcx> Visitor<'tcx> for Qualifier<'a, 'tcx, 'tcx> {
);
}
} else if let Some(&attr::Stability {
rustc_const_unstable: Some(attr::RustcConstUnstable {
feature: ref feature_name
}),
const_stability: Some(ref feature_name),
.. }) = self.tcx.lookup_stability(def_id) {
if
// feature-gate is not enabled,
Expand Down Expand Up @@ -1175,8 +1173,20 @@ impl MirPass for QualifyAndPromoteConstants {
let (temps, candidates) = {
let mut qualifier = Qualifier::new(tcx, def_id, mir, mode);
if mode == Mode::ConstFn {
// Enforce a constant-like CFG for `const fn`.
qualifier.qualify_const();
if tcx.is_min_const_fn(def_id) {
// enforce `min_const_fn` for stable const fns
use super::qualify_min_const_fn::is_min_const_fn;
if let Err((span, err)) = is_min_const_fn(tcx, def_id, mir) {
tcx.sess.span_err(span, &err);
} else {
// this should not produce any errors, but better safe than sorry
// FIXME(#53819)
qualifier.qualify_const();
}
} else {
// Enforce a constant-like CFG for `const fn`.
qualifier.qualify_const();
}
} else {
while let Some((bb, data)) = qualifier.rpo.next() {
qualifier.visit_basic_block_data(bb, data);
Expand Down
Loading