honor #[rustc_const_unstable] attributes
This commit is contained in:
parent
824952f48b
commit
a12d0d4f66
|
@ -81,7 +81,12 @@ impl_stable_hash_for!(enum ::syntax::abi::Abi {
|
|||
});
|
||||
|
||||
impl_stable_hash_for!(struct ::syntax::attr::Deprecation { since, note });
|
||||
impl_stable_hash_for!(struct ::syntax::attr::Stability { level, feature, rustc_depr });
|
||||
impl_stable_hash_for!(struct ::syntax::attr::Stability {
|
||||
level,
|
||||
feature,
|
||||
rustc_depr,
|
||||
rustc_const_unstable
|
||||
});
|
||||
|
||||
impl<'a, 'gcx, 'tcx> HashStable<StableHashingContext<'a, 'gcx, 'tcx>>
|
||||
for ::syntax::attr::StabilityLevel {
|
||||
|
@ -102,6 +107,7 @@ 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 {
|
||||
|
|
|
@ -427,6 +427,7 @@ impl<'a, 'tcx> Index<'tcx> {
|
|||
},
|
||||
feature: Symbol::intern("rustc_private"),
|
||||
rustc_depr: None,
|
||||
rustc_const_unstable: None,
|
||||
});
|
||||
annotator.parent_stab = Some(stability);
|
||||
}
|
||||
|
|
|
@ -30,6 +30,7 @@ use rustc::mir::transform::{MirPass, MirSource};
|
|||
use rustc::mir::visit::{LvalueContext, Visitor};
|
||||
use rustc::middle::lang_items;
|
||||
use syntax::abi::Abi;
|
||||
use syntax::attr;
|
||||
use syntax::feature_gate::UnstableFeatures;
|
||||
use syntax_pos::{Span, DUMMY_SP};
|
||||
|
||||
|
@ -713,14 +714,14 @@ impl<'a, 'tcx> Visitor<'tcx> for Qualifier<'a, 'tcx, 'tcx> {
|
|||
self.visit_operand(func, location);
|
||||
|
||||
let fn_ty = func.ty(self.mir, self.tcx);
|
||||
let (mut is_shuffle, mut is_const_fn) = (false, false);
|
||||
let (mut is_shuffle, mut is_const_fn) = (false, None);
|
||||
if let ty::TyFnDef(def_id, _) = fn_ty.sty {
|
||||
match self.tcx.fn_sig(def_id).abi() {
|
||||
Abi::RustIntrinsic |
|
||||
Abi::PlatformIntrinsic => {
|
||||
assert!(!self.tcx.is_const_fn(def_id));
|
||||
match &self.tcx.item_name(def_id)[..] {
|
||||
"size_of" | "min_align_of" => is_const_fn = true,
|
||||
"size_of" | "min_align_of" => is_const_fn = Some(def_id),
|
||||
|
||||
name if name.starts_with("simd_shuffle") => {
|
||||
is_shuffle = true;
|
||||
|
@ -730,7 +731,9 @@ impl<'a, 'tcx> Visitor<'tcx> for Qualifier<'a, 'tcx, 'tcx> {
|
|||
}
|
||||
}
|
||||
_ => {
|
||||
is_const_fn = self.tcx.is_const_fn(def_id);
|
||||
if self.tcx.is_const_fn(def_id) {
|
||||
is_const_fn = Some(def_id);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -751,25 +754,38 @@ impl<'a, 'tcx> Visitor<'tcx> for Qualifier<'a, 'tcx, 'tcx> {
|
|||
}
|
||||
|
||||
// Const fn calls.
|
||||
if is_const_fn {
|
||||
// We are in a const or static initializer,
|
||||
if self.mode != Mode::Fn &&
|
||||
if let Some(def_id) = is_const_fn {
|
||||
// find corresponding rustc_const_unstable feature
|
||||
if let Some(&attr::Stability {
|
||||
rustc_const_unstable: Some(attr::RustcConstUnstable {
|
||||
feature: ref feature_name
|
||||
}),
|
||||
.. }) = self.tcx.lookup_stability(def_id) {
|
||||
|
||||
// feature-gate is not enabled,
|
||||
!self.tcx.sess.features.borrow().const_fn &&
|
||||
// We are in a const or static initializer,
|
||||
if self.mode != Mode::Fn &&
|
||||
|
||||
// this doesn't come from a crate with the feature-gate enabled,
|
||||
self.def_id.is_local() &&
|
||||
// feature-gate is not enabled,
|
||||
!self.tcx.sess.features.borrow()
|
||||
.declared_lib_features
|
||||
.iter()
|
||||
.any(|&(ref sym, _)| sym == feature_name) &&
|
||||
|
||||
// this doesn't come from a macro that has #[allow_internal_unstable]
|
||||
!self.span.allows_unstable()
|
||||
{
|
||||
let mut err = self.tcx.sess.struct_span_err(self.span,
|
||||
"const fns are an unstable feature");
|
||||
help!(&mut err,
|
||||
"in Nightly builds, add `#![feature(const_fn)]` \
|
||||
to the crate attributes to enable");
|
||||
err.emit();
|
||||
// this doesn't come from a crate with the feature-gate enabled,
|
||||
self.def_id.is_local() &&
|
||||
|
||||
// this doesn't come from a macro that has #[allow_internal_unstable]
|
||||
!self.span.allows_unstable()
|
||||
{
|
||||
let mut err = self.tcx.sess.struct_span_err(self.span,
|
||||
&format!("`{}` is not yet stable as a const fn",
|
||||
self.tcx.item_path_str(def_id)));
|
||||
help!(&mut err,
|
||||
"in Nightly builds, add `#![feature({})]` \
|
||||
to the crate attributes to enable",
|
||||
feature_name);
|
||||
err.emit();
|
||||
}
|
||||
}
|
||||
} else {
|
||||
self.qualif = Qualif::NOT_CONST;
|
||||
|
|
|
@ -637,12 +637,13 @@ pub fn eval_condition<F>(cfg: &ast::MetaItem, sess: &ParseSess, eval: &mut F)
|
|||
}
|
||||
}
|
||||
|
||||
/// Represents the #[stable], #[unstable] and #[rustc_deprecated] attributes.
|
||||
/// Represents the #[stable], #[unstable], #[rustc_{deprecated,const_unstable}] attributes.
|
||||
#[derive(RustcEncodable, RustcDecodable, Clone, Debug, PartialEq, Eq, Hash)]
|
||||
pub struct Stability {
|
||||
pub level: StabilityLevel,
|
||||
pub feature: Symbol,
|
||||
pub rustc_depr: Option<RustcDeprecation>,
|
||||
pub rustc_const_unstable: Option<RustcConstUnstable>,
|
||||
}
|
||||
|
||||
/// The available stability levels.
|
||||
|
@ -659,6 +660,11 @@ pub struct RustcDeprecation {
|
|||
pub reason: Symbol,
|
||||
}
|
||||
|
||||
#[derive(RustcEncodable, RustcDecodable, PartialEq, PartialOrd, Clone, Debug, Eq, Hash)]
|
||||
pub struct RustcConstUnstable {
|
||||
pub feature: Symbol,
|
||||
}
|
||||
|
||||
#[derive(RustcEncodable, RustcDecodable, PartialEq, PartialOrd, Clone, Debug, Eq, Hash)]
|
||||
pub struct Deprecation {
|
||||
pub since: Option<Symbol>,
|
||||
|
@ -678,9 +684,15 @@ fn find_stability_generic<'a, I>(diagnostic: &Handler,
|
|||
{
|
||||
let mut stab: Option<Stability> = None;
|
||||
let mut rustc_depr: Option<RustcDeprecation> = None;
|
||||
let mut rustc_const_unstable: Option<RustcConstUnstable> = None;
|
||||
|
||||
'outer: for attr in attrs_iter {
|
||||
if attr.path != "rustc_deprecated" && attr.path != "unstable" && attr.path != "stable" {
|
||||
if ![
|
||||
"rustc_deprecated",
|
||||
"rustc_const_unstable",
|
||||
"unstable",
|
||||
"stable",
|
||||
].iter().any(|&s| attr.path == s) {
|
||||
continue // not a stability level
|
||||
}
|
||||
|
||||
|
@ -703,21 +715,18 @@ fn find_stability_generic<'a, I>(diagnostic: &Handler,
|
|||
}
|
||||
};
|
||||
|
||||
match &*meta.name.as_str() {
|
||||
"rustc_deprecated" => {
|
||||
if rustc_depr.is_some() {
|
||||
span_err!(diagnostic, item_sp, E0540,
|
||||
"multiple rustc_deprecated attributes");
|
||||
break
|
||||
}
|
||||
|
||||
let mut since = None;
|
||||
let mut reason = None;
|
||||
macro_rules! get_meta {
|
||||
($($name:ident),+) => {
|
||||
$(
|
||||
let mut $name = None;
|
||||
)+
|
||||
for meta in metas {
|
||||
if let Some(mi) = meta.meta_item() {
|
||||
match &*mi.name().as_str() {
|
||||
"since" => if !get(mi, &mut since) { continue 'outer },
|
||||
"reason" => if !get(mi, &mut reason) { continue 'outer },
|
||||
$(
|
||||
stringify!($name)
|
||||
=> if !get(mi, &mut $name) { continue 'outer },
|
||||
)+
|
||||
_ => {
|
||||
handle_errors(diagnostic, mi.span,
|
||||
AttrError::UnknownMetaItem(mi.name()));
|
||||
|
@ -729,6 +738,18 @@ fn find_stability_generic<'a, I>(diagnostic: &Handler,
|
|||
continue 'outer
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
match &*meta.name.as_str() {
|
||||
"rustc_deprecated" => {
|
||||
if rustc_depr.is_some() {
|
||||
span_err!(diagnostic, item_sp, E0540,
|
||||
"multiple rustc_deprecated attributes");
|
||||
continue 'outer
|
||||
}
|
||||
|
||||
get_meta!(since, reason);
|
||||
|
||||
match (since, reason) {
|
||||
(Some(since), Some(reason)) => {
|
||||
|
@ -747,6 +768,23 @@ fn find_stability_generic<'a, I>(diagnostic: &Handler,
|
|||
}
|
||||
}
|
||||
}
|
||||
"rustc_const_unstable" => {
|
||||
if rustc_const_unstable.is_some() {
|
||||
span_err!(diagnostic, item_sp, E0553,
|
||||
"multiple rustc_const_unstable attributes");
|
||||
continue 'outer
|
||||
}
|
||||
|
||||
get_meta!(feature);
|
||||
if let Some(feature) = feature {
|
||||
rustc_const_unstable = Some(RustcConstUnstable {
|
||||
feature
|
||||
});
|
||||
} else {
|
||||
span_err!(diagnostic, attr.span(), E0629, "missing 'feature'");
|
||||
continue
|
||||
}
|
||||
}
|
||||
"unstable" => {
|
||||
if stab.is_some() {
|
||||
handle_errors(diagnostic, attr.span(), AttrError::MultipleStabilityLevels);
|
||||
|
@ -791,6 +829,7 @@ fn find_stability_generic<'a, I>(diagnostic: &Handler,
|
|||
},
|
||||
feature,
|
||||
rustc_depr: None,
|
||||
rustc_const_unstable: None,
|
||||
})
|
||||
}
|
||||
(None, _, _) => {
|
||||
|
@ -836,6 +875,7 @@ fn find_stability_generic<'a, I>(diagnostic: &Handler,
|
|||
},
|
||||
feature,
|
||||
rustc_depr: None,
|
||||
rustc_const_unstable: None,
|
||||
})
|
||||
}
|
||||
(None, _) => {
|
||||
|
@ -867,6 +907,17 @@ fn find_stability_generic<'a, I>(diagnostic: &Handler,
|
|||
}
|
||||
}
|
||||
|
||||
// Merge the const-unstable info into the stability info
|
||||
if let Some(rustc_const_unstable) = rustc_const_unstable {
|
||||
if let Some(ref mut stab) = stab {
|
||||
stab.rustc_const_unstable = Some(rustc_const_unstable);
|
||||
} else {
|
||||
span_err!(diagnostic, item_sp, E0630,
|
||||
"rustc_const_unstable attribute must be paired with \
|
||||
either stable or unstable attribute");
|
||||
}
|
||||
}
|
||||
|
||||
stab
|
||||
}
|
||||
|
||||
|
|
|
@ -357,8 +357,11 @@ register_diagnostics! {
|
|||
E0549, // rustc_deprecated attribute must be paired with either stable or unstable attribute
|
||||
E0550, // multiple deprecated attributes
|
||||
E0551, // incorrect meta item
|
||||
E0553, // multiple rustc_const_unstable attributes
|
||||
E0555, // malformed feature attribute, expected #![feature(...)]
|
||||
E0556, // malformed feature, expected just one word
|
||||
E0584, // file for module `..` found at both .. and ..
|
||||
E0589, // invalid `repr(align)` attribute
|
||||
E0629, // missing 'feature' (rustc_const_unstable)
|
||||
E0630, // rustc_const_unstable attribute must be paired with stable/unstable attribute
|
||||
}
|
||||
|
|
|
@ -137,6 +137,7 @@ declare_features! (
|
|||
|
||||
// rustc internal
|
||||
(active, rustc_diagnostic_macros, "1.0.0", None),
|
||||
(active, rustc_const_unstable, "1.0.0", None),
|
||||
(active, advanced_slice_patterns, "1.0.0", Some(23121)),
|
||||
(active, box_syntax, "1.0.0", Some(27779)),
|
||||
(active, placement_in_syntax, "1.0.0", Some(27779)),
|
||||
|
@ -622,6 +623,11 @@ pub const BUILTIN_ATTRIBUTES: &'static [(&'static str, AttributeType, AttributeG
|
|||
"the `#[rustc_on_unimplemented]` attribute \
|
||||
is an experimental feature",
|
||||
cfg_fn!(on_unimplemented))),
|
||||
("rustc_const_unstable", Normal, Gated(Stability::Unstable,
|
||||
"rustc_const_unstable",
|
||||
"the `#[rustc_const_unstable]` attribute \
|
||||
is an internal feature",
|
||||
cfg_fn!(rustc_const_unstable))),
|
||||
("global_allocator", Normal, Gated(Stability::Unstable,
|
||||
"global_allocator",
|
||||
"the `#[global_allocator]` attribute is \
|
||||
|
|
|
@ -0,0 +1,24 @@
|
|||
// Copyright 2015 The Rust Project Developers. See the COPYRIGHT
|
||||
// file at the top-level directory of this distribution and at
|
||||
// http://rust-lang.org/COPYRIGHT.
|
||||
//
|
||||
// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
|
||||
// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
|
||||
// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
|
||||
// option. This file may not be copied, modified, or distributed
|
||||
// except according to those terms.
|
||||
|
||||
// Test use of const fns in std using individual feature gates.
|
||||
|
||||
use std::cell::Cell;
|
||||
|
||||
const CELL: Cell<i32> = Cell::new(42); //~ERROR not yet stable as a const fn
|
||||
//~^HELP #![feature(const_cell_new)]
|
||||
|
||||
fn main() {
|
||||
let v = CELL.get();
|
||||
CELL.set(v+1);
|
||||
|
||||
assert_eq!(CELL.get(), v);
|
||||
}
|
||||
|
|
@ -0,0 +1,23 @@
|
|||
// Copyright 2015 The Rust Project Developers. See the COPYRIGHT
|
||||
// file at the top-level directory of this distribution and at
|
||||
// http://rust-lang.org/COPYRIGHT.
|
||||
//
|
||||
// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
|
||||
// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
|
||||
// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
|
||||
// option. This file may not be copied, modified, or distributed
|
||||
// except according to those terms.
|
||||
|
||||
// Test internal const fn feature gate.
|
||||
|
||||
#![feature(staged_api)]
|
||||
#![feature(const_fn)]
|
||||
//#![feature(rustc_const_unstable)]
|
||||
|
||||
#[stable(feature="zing", since="1.0.0")]
|
||||
#[rustc_const_unstable(feature="fzzzzzt")] //~ERROR internal feature
|
||||
pub const fn bazinga() {}
|
||||
|
||||
fn main() {
|
||||
}
|
||||
|
|
@ -10,7 +10,7 @@
|
|||
|
||||
// Various checks that stability attributes are used correctly, per RFC 507
|
||||
|
||||
#![feature(staged_api)]
|
||||
#![feature(const_fn, staged_api, rustc_const_unstable)]
|
||||
|
||||
#![stable(feature = "rust1", since = "1.0.0")]
|
||||
|
||||
|
@ -88,8 +88,11 @@ fn multiple3() { }
|
|||
#[stable(feature = "a", since = "b")]
|
||||
#[rustc_deprecated(since = "b", reason = "text")]
|
||||
#[rustc_deprecated(since = "b", reason = "text")]
|
||||
fn multiple4() { } //~ ERROR multiple rustc_deprecated attributes [E0540]
|
||||
#[rustc_const_unstable(feature = "a")]
|
||||
#[rustc_const_unstable(feature = "b")]
|
||||
pub const fn multiple4() { } //~ ERROR multiple rustc_deprecated attributes [E0540]
|
||||
//~^ ERROR Invalid stability or deprecation version found
|
||||
//~| ERROR multiple rustc_const_unstable attributes
|
||||
|
||||
#[rustc_deprecated(since = "a", reason = "text")]
|
||||
fn deprecated_without_unstable_or_stable() { }
|
||||
|
|
|
@ -0,0 +1,25 @@
|
|||
// Copyright 2015 The Rust Project Developers. See the COPYRIGHT
|
||||
// file at the top-level directory of this distribution and at
|
||||
// http://rust-lang.org/COPYRIGHT.
|
||||
//
|
||||
// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
|
||||
// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
|
||||
// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
|
||||
// option. This file may not be copied, modified, or distributed
|
||||
// except according to those terms.
|
||||
|
||||
// Test use of const fns in std using individual feature gates.
|
||||
|
||||
#![feature(const_cell_new)]
|
||||
|
||||
use std::cell::Cell;
|
||||
|
||||
const CELL: Cell<i32> = Cell::new(42);
|
||||
|
||||
fn main() {
|
||||
let v = CELL.get();
|
||||
CELL.set(v+1);
|
||||
|
||||
assert_eq!(CELL.get(), v);
|
||||
}
|
||||
|
Loading…
Reference in New Issue