diff --git a/src/librustc/middle/check_static_recursion.rs b/src/librustc/middle/check_static_recursion.rs index 822106c52692e..55a9a91930045 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(&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 8c6855036f6e9..ee895fb1a96eb 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(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 0000000000000..29b5689fa93fd --- /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 or the MIT license +// , 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 edb0678cd7838..171aef522d41a 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() {