about summary refs log tree commit diff
diff options
context:
space:
mode:
-rw-r--r--src/librustc/middle/check_static_recursion.rs30
-rw-r--r--src/libsyntax/feature_gate.rs6
-rw-r--r--src/test/compile-fail/static-recursion-gate.rs16
-rw-r--r--src/test/run-pass/static-recursive.rs2
4 files changed, 50 insertions, 4 deletions
diff --git a/src/librustc/middle/check_static_recursion.rs b/src/librustc/middle/check_static_recursion.rs
index 822106c5269..55a9a919300 100644
--- a/src/librustc/middle/check_static_recursion.rs
+++ b/src/librustc/middle/check_static_recursion.rs
@@ -8,16 +8,17 @@
 // option. This file may not be copied, modified, or distributed
 // except according to those terms.
 
-// This compiler pass detects static items that refer to themselves
+// This compiler pass detects constants that refer to themselves
 // recursively.
 
 use ast_map;
 use session::Session;
-use middle::def::{DefConst, DefAssociatedConst, DefVariant, DefMap};
+use middle::def::{DefStatic, DefConst, DefAssociatedConst, DefVariant, DefMap};
 use util::nodemap::NodeMap;
 
 use syntax::{ast, ast_util};
 use syntax::codemap::Span;
+use syntax::feature_gate::emit_feature_err;
 use syntax::visit::Visitor;
 use syntax::visit;
 
@@ -37,6 +38,7 @@ struct CheckCrateVisitor<'a, 'ast: 'a> {
 impl<'a, 'ast: 'a> Visitor<'ast> for CheckCrateVisitor<'a, 'ast> {
     fn visit_item(&mut self, it: &'ast ast::Item) {
         match it.node {
+            ast::ItemStatic(..) |
             ast::ItemConst(..) => {
                 let mut recursion_visitor =
                     CheckItemRecursionVisitor::new(self, &it.span);
@@ -124,8 +126,27 @@ impl<'a, 'ast: 'a> CheckItemRecursionVisitor<'a, 'ast> {
     }
     fn with_item_id_pushed<F>(&mut self, id: ast::NodeId, f: F)
           where F: Fn(&mut Self) {
-        if self.idstack.iter().any(|x| *x == id) {
-            span_err!(self.sess, *self.root_span, E0265, "recursive constant");
+        if self.idstack.iter().any(|&x| x == id) {
+            let any_static = self.idstack.iter().any(|&x| {
+                if let ast_map::NodeItem(item) = self.ast_map.get(x) {
+                    if let ast::ItemStatic(..) = item.node {
+                        true
+                    } else {
+                        false
+                    }
+                } else {
+                    false
+                }
+            });
+            if any_static {
+                if !self.sess.features.borrow().static_recursion {
+                    emit_feature_err(&self.sess.parse_sess.span_diagnostic,
+                                     "static_recursion",
+                                     *self.root_span, "recursive static");
+                }
+            } else {
+                span_err!(self.sess, *self.root_span, E0265, "recursive constant");
+            }
             return;
         }
         self.idstack.push(id);
@@ -216,6 +237,7 @@ impl<'a, 'ast: 'a> Visitor<'ast> for CheckItemRecursionVisitor<'a, 'ast> {
         match e.node {
             ast::ExprPath(..) => {
                 match self.def_map.borrow().get(&e.id).map(|d| d.base_def) {
+                    Some(DefStatic(def_id, _)) |
                     Some(DefAssociatedConst(def_id, _)) |
                     Some(DefConst(def_id))
                            if ast_util::is_local(def_id) => {
diff --git a/src/libsyntax/feature_gate.rs b/src/libsyntax/feature_gate.rs
index 8c6855036f6..ee895fb1a96 100644
--- a/src/libsyntax/feature_gate.rs
+++ b/src/libsyntax/feature_gate.rs
@@ -160,6 +160,9 @@ const KNOWN_FEATURES: &'static [(&'static str, &'static str, Status)] = &[
 
     // Allows using #[prelude_import] on glob `use` items.
     ("prelude_import", "1.2.0", Active),
+
+    // Allows the definition recursive static items.
+    ("static_recursion", "1.3.0", Active),
 ];
 // (changing above list without updating src/doc/reference.md makes @cmr sad)
 
@@ -338,6 +341,7 @@ pub struct Features {
     /// #![feature] attrs for non-language (library) features
     pub declared_lib_features: Vec<(InternedString, Span)>,
     pub const_fn: bool,
+    pub static_recursion: bool
 }
 
 impl Features {
@@ -362,6 +366,7 @@ impl Features {
             declared_stable_lang_features: Vec::new(),
             declared_lib_features: Vec::new(),
             const_fn: false,
+            static_recursion: false
         }
     }
 }
@@ -859,6 +864,7 @@ fn check_crate_inner<F>(cm: &CodeMap, span_handler: &SpanHandler,
         declared_stable_lang_features: accepted_features,
         declared_lib_features: unknown_features,
         const_fn: cx.has_feature("const_fn"),
+        static_recursion: cx.has_feature("static_recursion")
     }
 }
 
diff --git a/src/test/compile-fail/static-recursion-gate.rs b/src/test/compile-fail/static-recursion-gate.rs
new file mode 100644
index 00000000000..29b5689fa93
--- /dev/null
+++ b/src/test/compile-fail/static-recursion-gate.rs
@@ -0,0 +1,16 @@
+// 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.
+
+static mut S: *const u8 = unsafe { &S as *const *const u8 as *const u8 };
+//~^ ERROR recursive static
+
+pub fn main() {
+    unsafe { assert_eq!(S, *(S as *const *const u8)); }
+}
diff --git a/src/test/run-pass/static-recursive.rs b/src/test/run-pass/static-recursive.rs
index edb0678cd78..171aef522d4 100644
--- a/src/test/run-pass/static-recursive.rs
+++ b/src/test/run-pass/static-recursive.rs
@@ -8,6 +8,8 @@
 // option. This file may not be copied, modified, or distributed
 // except according to those terms.
 
+#![feature(static_recursion)]
+
 static mut S: *const u8 = unsafe { &S as *const *const u8 as *const u8 };
 
 pub fn main() {