about summary refs log tree commit diff
path: root/src
diff options
context:
space:
mode:
authorAlex Burka <alex@alexburka.com>2017-09-08 18:11:30 +0000
committerAlex Burka <alex@alexburka.com>2017-09-13 15:07:17 +0000
commita12d0d4f6672a9621771433d2f05757f1f79130d (patch)
tree311a6bcf852139223a8444c1442d3248fd9e6e24 /src
parent824952f48b85806c498d700f183dfc42b516cc7d (diff)
downloadrust-a12d0d4f6672a9621771433d2f05757f1f79130d.tar.gz
rust-a12d0d4f6672a9621771433d2f05757f1f79130d.zip
honor #[rustc_const_unstable] attributes
Diffstat (limited to 'src')
-rw-r--r--src/librustc/ich/impls_syntax.rs8
-rw-r--r--src/librustc/middle/stability.rs1
-rw-r--r--src/librustc_mir/transform/qualify_consts.rs60
-rw-r--r--src/libsyntax/attr.rs79
-rw-r--r--src/libsyntax/diagnostic_list.rs3
-rw-r--r--src/libsyntax/feature_gate.rs6
-rw-r--r--src/test/compile-fail/const-fn-feature-flags.rs24
-rw-r--r--src/test/compile-fail/feature-gate-rustc_const_unstable.rs23
-rw-r--r--src/test/compile-fail/stability-attribute-sanity.rs7
-rw-r--r--src/test/run-pass/const-fn-feature-flags.rs25
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);
+}
+