Skip to content

Commit

Permalink
Add static_recursion feature gate.
Browse files Browse the repository at this point in the history
  • Loading branch information
eefriedman committed Jul 25, 2015
1 parent 8ebf952 commit 742e124
Show file tree
Hide file tree
Showing 4 changed files with 50 additions and 4 deletions.
30 changes: 26 additions & 4 deletions src/librustc/middle/check_static_recursion.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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;

Expand All @@ -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);
Expand Down Expand Up @@ -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);
Expand Down Expand Up @@ -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) => {
Expand Down
6 changes: 6 additions & 0 deletions src/libsyntax/feature_gate.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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)

Expand Down Expand Up @@ -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 {
Expand All @@ -362,6 +366,7 @@ impl Features {
declared_stable_lang_features: Vec::new(),
declared_lib_features: Vec::new(),
const_fn: false,
static_recursion: false
}
}
}
Expand Down Expand Up @@ -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")
}
}

Expand Down
16 changes: 16 additions & 0 deletions src/test/compile-fail/static-recursion-gate.rs
Original file line number Diff line number Diff line change
@@ -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)); }
}
2 changes: 2 additions & 0 deletions src/test/run-pass/static-recursive.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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() {
Expand Down

0 comments on commit 742e124

Please sign in to comment.