diff options
| author | Alex Burka <alex@alexburka.com> | 2017-09-08 18:11:30 +0000 |
|---|---|---|
| committer | Alex Burka <alex@alexburka.com> | 2017-09-13 15:07:17 +0000 |
| commit | a12d0d4f6672a9621771433d2f05757f1f79130d (patch) | |
| tree | 311a6bcf852139223a8444c1442d3248fd9e6e24 /src | |
| parent | 824952f48b85806c498d700f183dfc42b516cc7d (diff) | |
| download | rust-a12d0d4f6672a9621771433d2f05757f1f79130d.tar.gz rust-a12d0d4f6672a9621771433d2f05757f1f79130d.zip | |
honor #[rustc_const_unstable] attributes
Diffstat (limited to 'src')
| -rw-r--r-- | src/librustc/ich/impls_syntax.rs | 8 | ||||
| -rw-r--r-- | src/librustc/middle/stability.rs | 1 | ||||
| -rw-r--r-- | src/librustc_mir/transform/qualify_consts.rs | 60 | ||||
| -rw-r--r-- | src/libsyntax/attr.rs | 79 | ||||
| -rw-r--r-- | src/libsyntax/diagnostic_list.rs | 3 | ||||
| -rw-r--r-- | src/libsyntax/feature_gate.rs | 6 | ||||
| -rw-r--r-- | src/test/compile-fail/const-fn-feature-flags.rs | 24 | ||||
| -rw-r--r-- | src/test/compile-fail/feature-gate-rustc_const_unstable.rs | 23 | ||||
| -rw-r--r-- | src/test/compile-fail/stability-attribute-sanity.rs | 7 | ||||
| -rw-r--r-- | src/test/run-pass/const-fn-feature-flags.rs | 25 |
10 files changed, 197 insertions, 39 deletions
diff --git a/src/librustc/ich/impls_syntax.rs b/src/librustc/ich/impls_syntax.rs index b827284271e..e52be70190c 100644 --- a/src/librustc/ich/impls_syntax.rs +++ b/src/librustc/ich/impls_syntax.rs @@ -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 { diff --git a/src/librustc/middle/stability.rs b/src/librustc/middle/stability.rs index 5ca235b2ad3..977102ec1ad 100644 --- a/src/librustc/middle/stability.rs +++ b/src/librustc/middle/stability.rs @@ -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); } diff --git a/src/librustc_mir/transform/qualify_consts.rs b/src/librustc_mir/transform/qualify_consts.rs index f8c26dc99c6..fa6a98224ee 100644 --- a/src/librustc_mir/transform/qualify_consts.rs +++ b/src/librustc_mir/transform/qualify_consts.rs @@ -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 && - - // feature-gate is not enabled, - !self.tcx.sess.features.borrow().const_fn && - - // 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, - "const fns are an unstable feature"); - help!(&mut err, - "in Nightly builds, add `#![feature(const_fn)]` \ - to the crate attributes to enable"); - err.emit(); + 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) { + + // We are in a const or static initializer, + if self.mode != Mode::Fn && + + // 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 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; diff --git a/src/libsyntax/attr.rs b/src/libsyntax/attr.rs index adbbc1b0ac5..03907eed900 100644 --- a/src/libsyntax/attr.rs +++ b/src/libsyntax/attr.rs @@ -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. @@ -660,6 +661,11 @@ pub struct RustcDeprecation { } #[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>, pub note: 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 } diff --git a/src/libsyntax/diagnostic_list.rs b/src/libsyntax/diagnostic_list.rs index 2ea3fe51d30..46dec73c962 100644 --- a/src/libsyntax/diagnostic_list.rs +++ b/src/libsyntax/diagnostic_list.rs @@ -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 } diff --git a/src/libsyntax/feature_gate.rs b/src/libsyntax/feature_gate.rs index 3d4ded2ae81..38e20b9fe40 100644 --- a/src/libsyntax/feature_gate.rs +++ b/src/libsyntax/feature_gate.rs @@ -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 \ diff --git a/src/test/compile-fail/const-fn-feature-flags.rs b/src/test/compile-fail/const-fn-feature-flags.rs new file mode 100644 index 00000000000..823cb89b365 --- /dev/null +++ b/src/test/compile-fail/const-fn-feature-flags.rs @@ -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); +} + diff --git a/src/test/compile-fail/feature-gate-rustc_const_unstable.rs b/src/test/compile-fail/feature-gate-rustc_const_unstable.rs new file mode 100644 index 00000000000..38a3e15fd7e --- /dev/null +++ b/src/test/compile-fail/feature-gate-rustc_const_unstable.rs @@ -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() { +} + diff --git a/src/test/compile-fail/stability-attribute-sanity.rs b/src/test/compile-fail/stability-attribute-sanity.rs index d35f2cbb584..263ac427b76 100644 --- a/src/test/compile-fail/stability-attribute-sanity.rs +++ b/src/test/compile-fail/stability-attribute-sanity.rs @@ -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() { } diff --git a/src/test/run-pass/const-fn-feature-flags.rs b/src/test/run-pass/const-fn-feature-flags.rs new file mode 100644 index 00000000000..1e27a3edac8 --- /dev/null +++ b/src/test/run-pass/const-fn-feature-flags.rs @@ -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); +} + |
