Skip to content

Commit 742e124

Browse files
committed
Add static_recursion feature gate.
1 parent 8ebf952 commit 742e124

File tree

4 files changed

+50
-4
lines changed

4 files changed

+50
-4
lines changed

src/librustc/middle/check_static_recursion.rs

Lines changed: 26 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -8,16 +8,17 @@
88
// option. This file may not be copied, modified, or distributed
99
// except according to those terms.
1010

11-
// This compiler pass detects static items that refer to themselves
11+
// This compiler pass detects constants that refer to themselves
1212
// recursively.
1313

1414
use ast_map;
1515
use session::Session;
16-
use middle::def::{DefConst, DefAssociatedConst, DefVariant, DefMap};
16+
use middle::def::{DefStatic, DefConst, DefAssociatedConst, DefVariant, DefMap};
1717
use util::nodemap::NodeMap;
1818

1919
use syntax::{ast, ast_util};
2020
use syntax::codemap::Span;
21+
use syntax::feature_gate::emit_feature_err;
2122
use syntax::visit::Visitor;
2223
use syntax::visit;
2324

@@ -37,6 +38,7 @@ struct CheckCrateVisitor<'a, 'ast: 'a> {
3738
impl<'a, 'ast: 'a> Visitor<'ast> for CheckCrateVisitor<'a, 'ast> {
3839
fn visit_item(&mut self, it: &'ast ast::Item) {
3940
match it.node {
41+
ast::ItemStatic(..) |
4042
ast::ItemConst(..) => {
4143
let mut recursion_visitor =
4244
CheckItemRecursionVisitor::new(self, &it.span);
@@ -124,8 +126,27 @@ impl<'a, 'ast: 'a> CheckItemRecursionVisitor<'a, 'ast> {
124126
}
125127
fn with_item_id_pushed<F>(&mut self, id: ast::NodeId, f: F)
126128
where F: Fn(&mut Self) {
127-
if self.idstack.iter().any(|x| *x == id) {
128-
span_err!(self.sess, *self.root_span, E0265, "recursive constant");
129+
if self.idstack.iter().any(|&x| x == id) {
130+
let any_static = self.idstack.iter().any(|&x| {
131+
if let ast_map::NodeItem(item) = self.ast_map.get(x) {
132+
if let ast::ItemStatic(..) = item.node {
133+
true
134+
} else {
135+
false
136+
}
137+
} else {
138+
false
139+
}
140+
});
141+
if any_static {
142+
if !self.sess.features.borrow().static_recursion {
143+
emit_feature_err(&self.sess.parse_sess.span_diagnostic,
144+
"static_recursion",
145+
*self.root_span, "recursive static");
146+
}
147+
} else {
148+
span_err!(self.sess, *self.root_span, E0265, "recursive constant");
149+
}
129150
return;
130151
}
131152
self.idstack.push(id);
@@ -216,6 +237,7 @@ impl<'a, 'ast: 'a> Visitor<'ast> for CheckItemRecursionVisitor<'a, 'ast> {
216237
match e.node {
217238
ast::ExprPath(..) => {
218239
match self.def_map.borrow().get(&e.id).map(|d| d.base_def) {
240+
Some(DefStatic(def_id, _)) |
219241
Some(DefAssociatedConst(def_id, _)) |
220242
Some(DefConst(def_id))
221243
if ast_util::is_local(def_id) => {

src/libsyntax/feature_gate.rs

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -160,6 +160,9 @@ const KNOWN_FEATURES: &'static [(&'static str, &'static str, Status)] = &[
160160

161161
// Allows using #[prelude_import] on glob `use` items.
162162
("prelude_import", "1.2.0", Active),
163+
164+
// Allows the definition recursive static items.
165+
("static_recursion", "1.3.0", Active),
163166
];
164167
// (changing above list without updating src/doc/reference.md makes @cmr sad)
165168

@@ -338,6 +341,7 @@ pub struct Features {
338341
/// #![feature] attrs for non-language (library) features
339342
pub declared_lib_features: Vec<(InternedString, Span)>,
340343
pub const_fn: bool,
344+
pub static_recursion: bool
341345
}
342346

343347
impl Features {
@@ -362,6 +366,7 @@ impl Features {
362366
declared_stable_lang_features: Vec::new(),
363367
declared_lib_features: Vec::new(),
364368
const_fn: false,
369+
static_recursion: false
365370
}
366371
}
367372
}
@@ -859,6 +864,7 @@ fn check_crate_inner<F>(cm: &CodeMap, span_handler: &SpanHandler,
859864
declared_stable_lang_features: accepted_features,
860865
declared_lib_features: unknown_features,
861866
const_fn: cx.has_feature("const_fn"),
867+
static_recursion: cx.has_feature("static_recursion")
862868
}
863869
}
864870

Lines changed: 16 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,16 @@
1+
// Copyright 2015 The Rust Project Developers. See the COPYRIGHT
2+
// file at the top-level directory of this distribution and at
3+
// http://rust-lang.org/COPYRIGHT.
4+
//
5+
// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
6+
// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
7+
// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
8+
// option. This file may not be copied, modified, or distributed
9+
// except according to those terms.
10+
11+
static mut S: *const u8 = unsafe { &S as *const *const u8 as *const u8 };
12+
//~^ ERROR recursive static
13+
14+
pub fn main() {
15+
unsafe { assert_eq!(S, *(S as *const *const u8)); }
16+
}

src/test/run-pass/static-recursive.rs

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -8,6 +8,8 @@
88
// option. This file may not be copied, modified, or distributed
99
// except according to those terms.
1010

11+
#![feature(static_recursion)]
12+
1113
static mut S: *const u8 = unsafe { &S as *const *const u8 as *const u8 };
1214

1315
pub fn main() {

0 commit comments

Comments
 (0)