Skip to content

Commit

Permalink
Auto merge of #53604 - oli-obk:min_const_fn, r=Centril,varkor
Browse files Browse the repository at this point in the history
Implement the `min_const_fn` feature gate

cc @RalfJung @eddyb

r? @Centril

implements the feature gate for #53555

I added a hack so the `const_fn` feature gate also enables the `min_const_fn` feature gate. This ensures that nightly users of `const_fn` don't have to touch their code at all.

The `min_const_fn` checks are run first, and if they succeeded, the `const_fn` checks are run additionally to ensure we didn't miss anything.
  • Loading branch information
bors committed Sep 1, 2018
2 parents e6381a7 + 2839f4f commit fea32f1
Show file tree
Hide file tree
Showing 83 changed files with 1,713 additions and 279 deletions.
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

This comment has been minimized.

Copy link
@therealprof

therealprof Sep 1, 2018

Contributor

French docstrings? 😲

This comment has been minimized.

Copy link
@Centril

Centril Sep 2, 2018

Contributor

Pourquoi pas?

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 @@ -2430,6 +2430,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 => {
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 @@ -917,9 +917,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 @@ -1173,8 +1171,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

0 comments on commit fea32f1

Please sign in to comment.