Add static_recursion feature gate.

This commit is contained in:
Eli Friedman 2015-07-02 14:07:42 -07:00
parent 8ebf95257b
commit 742e1242d9
4 changed files with 50 additions and 4 deletions

View File

@ -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) => {

View File

@ -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")
}
}

View File

@ -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)); }
}

View File

@ -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() {