Skip to content

Commit 6784ba3

Browse files
authored
Auto merge of #36458 - mikhail-m1:stack-overflow, r=arielb1
fix stack overflow by enum and const fixes #36163
2 parents 3210fd5 + 60891c9 commit 6784ba3

File tree

2 files changed

+92
-52
lines changed

2 files changed

+92
-52
lines changed

src/librustc_passes/static_recursion.rs

+66-52
Original file line numberDiff line numberDiff line change
@@ -15,7 +15,7 @@ use rustc::dep_graph::DepNode;
1515
use rustc::hir::map as ast_map;
1616
use rustc::session::{CompileResult, Session};
1717
use rustc::hir::def::{Def, CtorKind, DefMap};
18-
use rustc::util::nodemap::NodeMap;
18+
use rustc::util::nodemap::{NodeMap, NodeSet};
1919

2020
use syntax::ast;
2121
use syntax::feature_gate::{GateIssue, emit_feature_err};
@@ -34,6 +34,7 @@ struct CheckCrateVisitor<'a, 'ast: 'a> {
3434
// each one. If the variant uses the default values (starting from `0`),
3535
// then `None` is stored.
3636
discriminant_map: RefCell<NodeMap<Option<&'ast hir::Expr>>>,
37+
detected_recursive_ids: NodeSet,
3738
}
3839

3940
impl<'a, 'ast: 'a> Visitor<'ast> for CheckCrateVisitor<'a, 'ast> {
@@ -98,38 +99,43 @@ pub fn check_crate<'ast>(sess: &Session,
9899
def_map: def_map,
99100
ast_map: ast_map,
100101
discriminant_map: RefCell::new(NodeMap()),
102+
detected_recursive_ids: NodeSet(),
101103
};
102104
sess.track_errors(|| {
103105
ast_map.krate().visit_all_items(&mut visitor);
104106
})
105107
}
106108

107-
struct CheckItemRecursionVisitor<'a, 'ast: 'a> {
108-
root_span: &'a Span,
109-
sess: &'a Session,
110-
ast_map: &'a ast_map::Map<'ast>,
111-
def_map: &'a DefMap,
109+
struct CheckItemRecursionVisitor<'a, 'b: 'a, 'ast: 'b> {
110+
root_span: &'b Span,
111+
sess: &'b Session,
112+
ast_map: &'b ast_map::Map<'ast>,
113+
def_map: &'b DefMap,
112114
discriminant_map: &'a RefCell<NodeMap<Option<&'ast hir::Expr>>>,
113115
idstack: Vec<ast::NodeId>,
116+
detected_recursive_ids: &'a mut NodeSet,
114117
}
115118

116-
impl<'a, 'ast: 'a> CheckItemRecursionVisitor<'a, 'ast> {
117-
fn new(v: &'a CheckCrateVisitor<'a, 'ast>,
118-
span: &'a Span)
119-
-> CheckItemRecursionVisitor<'a, 'ast> {
119+
impl<'a, 'b: 'a, 'ast: 'b> CheckItemRecursionVisitor<'a, 'b, 'ast> {
120+
fn new(v: &'a mut CheckCrateVisitor<'b, 'ast>, span: &'b Span) -> Self {
120121
CheckItemRecursionVisitor {
121122
root_span: span,
122123
sess: v.sess,
123124
ast_map: v.ast_map,
124125
def_map: v.def_map,
125126
discriminant_map: &v.discriminant_map,
126127
idstack: Vec::new(),
128+
detected_recursive_ids: &mut v.detected_recursive_ids,
127129
}
128130
}
129131
fn with_item_id_pushed<F>(&mut self, id: ast::NodeId, f: F, span: Span)
130132
where F: Fn(&mut Self)
131133
{
132134
if self.idstack.iter().any(|&x| x == id) {
135+
if self.detected_recursive_ids.contains(&id) {
136+
return;
137+
}
138+
self.detected_recursive_ids.insert(id);
133139
let any_static = self.idstack.iter().any(|&x| {
134140
if let ast_map::NodeItem(item) = self.ast_map.get(x) {
135141
if let hir::ItemStatic(..) = item.node {
@@ -156,6 +162,7 @@ impl<'a, 'ast: 'a> CheckItemRecursionVisitor<'a, 'ast> {
156162
}
157163
return;
158164
}
165+
159166
self.idstack.push(id);
160167
f(self);
161168
self.idstack.pop();
@@ -201,9 +208,51 @@ impl<'a, 'ast: 'a> CheckItemRecursionVisitor<'a, 'ast> {
201208
discriminant_map.insert(*id, None);
202209
}
203210
}
211+
212+
fn process_def(&mut self, id: ast::NodeId, span: Span) {
213+
match self.def_map.get(&id).map(|d| d.base_def) {
214+
Some(Def::Static(def_id, _)) |
215+
Some(Def::AssociatedConst(def_id)) |
216+
Some(Def::Const(def_id)) => {
217+
if let Some(node_id) = self.ast_map.as_local_node_id(def_id) {
218+
match self.ast_map.get(node_id) {
219+
ast_map::NodeItem(item) => self.visit_item(item),
220+
ast_map::NodeTraitItem(item) => self.visit_trait_item(item),
221+
ast_map::NodeImplItem(item) => self.visit_impl_item(item),
222+
ast_map::NodeForeignItem(_) => {}
223+
_ => {
224+
span_bug!(span,
225+
"expected item, found {}",
226+
self.ast_map.node_to_string(node_id));
227+
}
228+
}
229+
}
230+
}
231+
// For variants, we only want to check expressions that
232+
// affect the specific variant used, but we need to check
233+
// the whole enum definition to see what expression that
234+
// might be (if any).
235+
Some(Def::VariantCtor(variant_id, CtorKind::Const)) => {
236+
if let Some(variant_id) = self.ast_map.as_local_node_id(variant_id) {
237+
let variant = self.ast_map.expect_variant(variant_id);
238+
let enum_id = self.ast_map.get_parent(variant_id);
239+
let enum_item = self.ast_map.expect_item(enum_id);
240+
if let hir::ItemEnum(ref enum_def, ref generics) = enum_item.node {
241+
self.populate_enum_discriminants(enum_def);
242+
self.visit_variant(variant, generics, enum_id);
243+
} else {
244+
span_bug!(span,
245+
"`check_static_recursion` found \
246+
non-enum in Def::VariantCtor");
247+
}
248+
}
249+
}
250+
_ => (),
251+
}
252+
}
204253
}
205254

206-
impl<'a, 'ast: 'a> Visitor<'ast> for CheckItemRecursionVisitor<'a, 'ast> {
255+
impl<'a, 'b: 'a, 'ast: 'b> Visitor<'ast> for CheckItemRecursionVisitor<'a, 'b, 'ast> {
207256
fn visit_item(&mut self, it: &'ast hir::Item) {
208257
self.with_item_id_pushed(it.id, |v| intravisit::walk_item(v, it), it.span);
209258
}
@@ -249,49 +298,14 @@ impl<'a, 'ast: 'a> Visitor<'ast> for CheckItemRecursionVisitor<'a, 'ast> {
249298

250299
fn visit_expr(&mut self, e: &'ast hir::Expr) {
251300
match e.node {
252-
hir::ExprPath(..) => {
253-
match self.def_map.get(&e.id).map(|d| d.base_def) {
254-
Some(Def::Static(def_id, _)) |
255-
Some(Def::AssociatedConst(def_id)) |
256-
Some(Def::Const(def_id)) => {
257-
if let Some(node_id) = self.ast_map.as_local_node_id(def_id) {
258-
match self.ast_map.get(node_id) {
259-
ast_map::NodeItem(item) => self.visit_item(item),
260-
ast_map::NodeTraitItem(item) => self.visit_trait_item(item),
261-
ast_map::NodeImplItem(item) => self.visit_impl_item(item),
262-
ast_map::NodeForeignItem(_) => {}
263-
_ => {
264-
span_bug!(e.span,
265-
"expected item, found {}",
266-
self.ast_map.node_to_string(node_id));
267-
}
268-
}
269-
}
270-
}
271-
// For variants, we only want to check expressions that
272-
// affect the specific variant used, but we need to check
273-
// the whole enum definition to see what expression that
274-
// might be (if any).
275-
Some(Def::VariantCtor(variant_id, CtorKind::Const)) => {
276-
if let Some(variant_id) = self.ast_map.as_local_node_id(variant_id) {
277-
let variant = self.ast_map.expect_variant(variant_id);
278-
let enum_id = self.ast_map.get_parent(variant_id);
279-
let enum_item = self.ast_map.expect_item(enum_id);
280-
if let hir::ItemEnum(ref enum_def, ref generics) = enum_item.node {
281-
self.populate_enum_discriminants(enum_def);
282-
self.visit_variant(variant, generics, enum_id);
283-
} else {
284-
span_bug!(e.span,
285-
"`check_static_recursion` found \
286-
non-enum in Def::VariantCtor");
287-
}
288-
}
289-
}
290-
_ => (),
291-
}
292-
}
301+
hir::ExprPath(..) => self.process_def(e.id, e.span),
293302
_ => (),
294303
}
295304
intravisit::walk_expr(self, e);
296305
}
306+
307+
fn visit_path(&mut self, path: &'ast hir::Path, id: ast::NodeId) {
308+
self.process_def(id, path.span);
309+
intravisit::walk_path(self, path);
310+
}
297311
}

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

+26
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,26 @@
1+
// Copyright 2012 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+
const A: i32 = Foo::B; //~ ERROR E0265
12+
//~^ NOTE recursion not allowed in constant
13+
14+
enum Foo {
15+
B = A, //~ ERROR E0265
16+
//~^ NOTE recursion not allowed in constant
17+
}
18+
19+
enum Bar {
20+
C = Bar::C, //~ ERROR E0265
21+
//~^ NOTE recursion not allowed in constant
22+
}
23+
24+
const D: i32 = A;
25+
26+
fn main() {}

0 commit comments

Comments
 (0)