Skip to content

Commit ad9ed40

Browse files
committed
auto merge of #17264 : bkoropoff/rust/issue-17252, r=nick29581
Recursive items are currently detected in the `check_const` pass which runs after type checking. This means a recursive static item used as an array length will cause type checking to blow the stack. This PR separates the recursion check out into a separate pass which is run before type checking. Closes issue #17252 r? @nick29581
2 parents aac078d + 0818955 commit ad9ed40

File tree

5 files changed

+134
-56
lines changed

5 files changed

+134
-56
lines changed

src/librustc/driver/driver.rs

+3
Original file line numberDiff line numberDiff line change
@@ -414,6 +414,9 @@ pub fn phase_3_run_analysis_passes<'tcx>(sess: Session,
414414
let stability_index = time(time_passes, "stability index", (), |_|
415415
stability::Index::build(krate));
416416

417+
time(time_passes, "static item recursion checking", (), |_|
418+
middle::check_static_recursion::check_crate(&sess, krate, &def_map, &ast_map));
419+
417420
let ty_cx = ty::mk_ctxt(sess,
418421
type_arena,
419422
def_map,

src/librustc/lib.rs

+1
Original file line numberDiff line numberDiff line change
@@ -80,6 +80,7 @@ pub mod middle {
8080
pub mod borrowck;
8181
pub mod cfg;
8282
pub mod check_const;
83+
pub mod check_static_recursion;
8384
pub mod check_loop;
8485
pub mod check_match;
8586
pub mod check_rvalues;

src/librustc/middle/check_const.rs

+1-56
Original file line numberDiff line numberDiff line change
@@ -9,15 +9,13 @@
99
// except according to those terms.
1010

1111

12-
use driver::session::Session;
1312
use middle::def::*;
14-
use middle::resolve;
1513
use middle::ty;
1614
use middle::typeck;
1715
use util::ppaux;
1816

1917
use syntax::ast::*;
20-
use syntax::{ast_util, ast_map};
18+
use syntax::ast_util;
2119
use syntax::visit::Visitor;
2220
use syntax::visit;
2321

@@ -63,7 +61,6 @@ fn check_item(v: &mut CheckCrateVisitor, it: &Item) {
6361
match it.node {
6462
ItemStatic(_, _, ref ex) => {
6563
v.inside_const(|v| v.visit_expr(&**ex));
66-
check_item_recursion(&v.tcx.sess, &v.tcx.map, &v.tcx.def_map, it);
6764
}
6865
ItemEnum(ref enum_definition, _) => {
6966
for var in (*enum_definition).variants.iter() {
@@ -214,55 +211,3 @@ fn check_expr(v: &mut CheckCrateVisitor, e: &Expr) {
214211
}
215212
visit::walk_expr(v, e);
216213
}
217-
218-
struct CheckItemRecursionVisitor<'a, 'ast: 'a> {
219-
root_it: &'a Item,
220-
sess: &'a Session,
221-
ast_map: &'a ast_map::Map<'ast>,
222-
def_map: &'a resolve::DefMap,
223-
idstack: Vec<NodeId>
224-
}
225-
226-
// Make sure a const item doesn't recursively refer to itself
227-
// FIXME: Should use the dependency graph when it's available (#1356)
228-
pub fn check_item_recursion<'a>(sess: &'a Session,
229-
ast_map: &'a ast_map::Map,
230-
def_map: &'a resolve::DefMap,
231-
it: &'a Item) {
232-
233-
let mut visitor = CheckItemRecursionVisitor {
234-
root_it: it,
235-
sess: sess,
236-
ast_map: ast_map,
237-
def_map: def_map,
238-
idstack: Vec::new()
239-
};
240-
visitor.visit_item(it);
241-
}
242-
243-
impl<'a, 'ast, 'v> Visitor<'v> for CheckItemRecursionVisitor<'a, 'ast> {
244-
fn visit_item(&mut self, it: &Item) {
245-
if self.idstack.iter().any(|x| x == &(it.id)) {
246-
self.sess.span_fatal(self.root_it.span, "recursive constant");
247-
}
248-
self.idstack.push(it.id);
249-
visit::walk_item(self, it);
250-
self.idstack.pop();
251-
}
252-
253-
fn visit_expr(&mut self, e: &Expr) {
254-
match e.node {
255-
ExprPath(..) => {
256-
match self.def_map.borrow().find(&e.id) {
257-
Some(&DefStatic(def_id, _)) if
258-
ast_util::is_local(def_id) => {
259-
self.visit_item(&*self.ast_map.expect_item(def_id.node));
260-
}
261-
_ => ()
262-
}
263-
},
264-
_ => ()
265-
}
266-
visit::walk_expr(self, e);
267-
}
268-
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,109 @@
1+
// Copyright 2014 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+
// This compiler pass detects static items that refer to themselves
12+
// recursively.
13+
14+
use driver::session::Session;
15+
use middle::resolve;
16+
use middle::def::DefStatic;
17+
18+
use syntax::ast::{Crate, Expr, ExprPath, Item, ItemStatic, NodeId};
19+
use syntax::{ast_util, ast_map};
20+
use syntax::visit::Visitor;
21+
use syntax::visit;
22+
23+
struct CheckCrateVisitor<'a, 'ast: 'a> {
24+
sess: &'a Session,
25+
def_map: &'a resolve::DefMap,
26+
ast_map: &'a ast_map::Map<'ast>
27+
}
28+
29+
impl<'v, 'a, 'ast> Visitor<'v> for CheckCrateVisitor<'a, 'ast> {
30+
fn visit_item(&mut self, i: &Item) {
31+
check_item(self, i);
32+
}
33+
}
34+
35+
pub fn check_crate<'ast>(sess: &Session,
36+
krate: &Crate,
37+
def_map: &resolve::DefMap,
38+
ast_map: &ast_map::Map<'ast>) {
39+
let mut visitor = CheckCrateVisitor {
40+
sess: sess,
41+
def_map: def_map,
42+
ast_map: ast_map
43+
};
44+
visit::walk_crate(&mut visitor, krate);
45+
sess.abort_if_errors();
46+
}
47+
48+
fn check_item(v: &mut CheckCrateVisitor, it: &Item) {
49+
match it.node {
50+
ItemStatic(_, _, ref ex) => {
51+
check_item_recursion(v.sess, v.ast_map, v.def_map, it);
52+
visit::walk_expr(v, &**ex)
53+
},
54+
_ => visit::walk_item(v, it)
55+
}
56+
}
57+
58+
struct CheckItemRecursionVisitor<'a, 'ast: 'a> {
59+
root_it: &'a Item,
60+
sess: &'a Session,
61+
ast_map: &'a ast_map::Map<'ast>,
62+
def_map: &'a resolve::DefMap,
63+
idstack: Vec<NodeId>
64+
}
65+
66+
// Make sure a const item doesn't recursively refer to itself
67+
// FIXME: Should use the dependency graph when it's available (#1356)
68+
pub fn check_item_recursion<'a>(sess: &'a Session,
69+
ast_map: &'a ast_map::Map,
70+
def_map: &'a resolve::DefMap,
71+
it: &'a Item) {
72+
73+
let mut visitor = CheckItemRecursionVisitor {
74+
root_it: it,
75+
sess: sess,
76+
ast_map: ast_map,
77+
def_map: def_map,
78+
idstack: Vec::new()
79+
};
80+
visitor.visit_item(it);
81+
}
82+
83+
impl<'a, 'ast, 'v> Visitor<'v> for CheckItemRecursionVisitor<'a, 'ast> {
84+
fn visit_item(&mut self, it: &Item) {
85+
if self.idstack.iter().any(|x| x == &(it.id)) {
86+
self.sess.span_err(self.root_it.span, "recursive constant");
87+
return;
88+
}
89+
self.idstack.push(it.id);
90+
visit::walk_item(self, it);
91+
self.idstack.pop();
92+
}
93+
94+
fn visit_expr(&mut self, e: &Expr) {
95+
match e.node {
96+
ExprPath(..) => {
97+
match self.def_map.borrow().find(&e.id) {
98+
Some(&DefStatic(def_id, _)) if
99+
ast_util::is_local(def_id) => {
100+
self.visit_item(&*self.ast_map.expect_item(def_id.node));
101+
}
102+
_ => ()
103+
}
104+
},
105+
_ => ()
106+
}
107+
visit::walk_expr(self, e);
108+
}
109+
}

src/test/compile-fail/issue-17252.rs

+20
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,20 @@
1+
// Copyright 2014 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 FOO: uint = FOO; //~ ERROR recursive constant
12+
13+
fn main() {
14+
let _x: [u8, ..FOO]; // caused stack overflow prior to fix
15+
let _y: uint = 1 + {
16+
static BAR: uint = BAR; //~ ERROR recursive constant
17+
let _z: [u8, ..BAR]; // caused stack overflow prior to fix
18+
1
19+
};
20+
}

0 commit comments

Comments
 (0)