Skip to content

Commit a2f4017

Browse files
Add ensure_sufficient_stack to recursive algorithms
The ensure_sufficient_stack function executes its callback in a dynamically allocated stack when the current stack is low on space. Using it in recursive algorithms such as visitors prevents the compiler from overflowing its stack when compiling modules with a high recursion_limit.
1 parent c95346b commit a2f4017

File tree

20 files changed

+507
-469
lines changed

20 files changed

+507
-469
lines changed

Cargo.lock

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -3818,6 +3818,7 @@ version = "0.0.0"
38183818
dependencies = [
38193819
"rustc_ast",
38203820
"rustc_ast_pretty",
3821+
"rustc_data_structures",
38213822
"rustc_hir",
38223823
"rustc_span",
38233824
"rustc_target",

compiler/rustc_ast/src/visit.rs

Lines changed: 7 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -16,6 +16,7 @@
1616
use crate::ast::*;
1717
use crate::token;
1818

19+
use rustc_data_structures::stack::ensure_sufficient_stack;
1920
use rustc_span::symbol::{Ident, Symbol};
2021
use rustc_span::Span;
2122

@@ -411,7 +412,7 @@ pub fn walk_pat_field<'a, V: Visitor<'a>>(visitor: &mut V, fp: &'a PatField) {
411412
}
412413

413414
pub fn walk_ty<'a, V: Visitor<'a>>(visitor: &mut V, typ: &'a Ty) {
414-
match typ.kind {
415+
ensure_sufficient_stack(|| match typ.kind {
415416
TyKind::Slice(ref ty) | TyKind::Paren(ref ty) => visitor.visit_ty(ty),
416417
TyKind::Ptr(ref mutable_type) => visitor.visit_ty(&mutable_type.ty),
417418
TyKind::Rptr(ref opt_lifetime, ref mutable_type) => {
@@ -445,7 +446,7 @@ pub fn walk_ty<'a, V: Visitor<'a>>(visitor: &mut V, typ: &'a Ty) {
445446
TyKind::Infer | TyKind::ImplicitSelf | TyKind::Err => {}
446447
TyKind::MacCall(ref mac) => visitor.visit_mac_call(mac),
447448
TyKind::Never | TyKind::CVarArgs => {}
448-
}
449+
})
449450
}
450451

451452
pub fn walk_path<'a, V: Visitor<'a>>(visitor: &mut V, path: &'a Path) {
@@ -721,7 +722,7 @@ pub fn walk_block<'a, V: Visitor<'a>>(visitor: &mut V, block: &'a Block) {
721722
}
722723

723724
pub fn walk_stmt<'a, V: Visitor<'a>>(visitor: &mut V, statement: &'a Stmt) {
724-
match statement.kind {
725+
ensure_sufficient_stack(|| match statement.kind {
725726
StmtKind::Local(ref local) => visitor.visit_local(local),
726727
StmtKind::Item(ref item) => visitor.visit_item(item),
727728
StmtKind::Expr(ref expr) | StmtKind::Semi(ref expr) => visitor.visit_expr(expr),
@@ -733,7 +734,7 @@ pub fn walk_stmt<'a, V: Visitor<'a>>(visitor: &mut V, statement: &'a Stmt) {
733734
visitor.visit_attribute(attr);
734735
}
735736
}
736-
}
737+
})
737738
}
738739

739740
pub fn walk_mac<'a, V: Visitor<'a>>(visitor: &mut V, mac: &'a MacCall) {
@@ -773,7 +774,7 @@ pub fn walk_inline_asm_sym<'a, V: Visitor<'a>>(visitor: &mut V, sym: &'a InlineA
773774
pub fn walk_expr<'a, V: Visitor<'a>>(visitor: &mut V, expression: &'a Expr) {
774775
walk_list!(visitor, visit_attribute, expression.attrs.iter());
775776

776-
match expression.kind {
777+
ensure_sufficient_stack(|| match expression.kind {
777778
ExprKind::Box(ref subexpression) => visitor.visit_expr(subexpression),
778779
ExprKind::Array(ref subexpressions) => {
779780
walk_list!(visitor, visit_expr, subexpressions);
@@ -902,7 +903,7 @@ pub fn walk_expr<'a, V: Visitor<'a>>(visitor: &mut V, expression: &'a Expr) {
902903
ExprKind::Try(ref subexpression) => visitor.visit_expr(subexpression),
903904
ExprKind::TryBlock(ref body) => visitor.visit_block(body),
904905
ExprKind::Lit(_) | ExprKind::Err => {}
905-
}
906+
});
906907

907908
visitor.visit_expr_post(expression)
908909
}

compiler/rustc_ast_lowering/src/lib.rs

Lines changed: 121 additions & 118 deletions
Original file line numberDiff line numberDiff line change
@@ -48,6 +48,7 @@ use rustc_data_structures::fingerprint::Fingerprint;
4848
use rustc_data_structures::fx::{FxHashMap, FxHashSet};
4949
use rustc_data_structures::sorted_map::SortedMap;
5050
use rustc_data_structures::stable_hasher::{HashStable, StableHasher};
51+
use rustc_data_structures::stack::ensure_sufficient_stack;
5152
use rustc_data_structures::sync::Lrc;
5253
use rustc_errors::struct_span_err;
5354
use rustc_hir as hir;
@@ -1166,13 +1167,14 @@ impl<'a, 'hir> LoweringContext<'a, 'hir> {
11661167
}
11671168

11681169
fn lower_ty_direct(&mut self, t: &Ty, mut itctx: ImplTraitContext<'_, 'hir>) -> hir::Ty<'hir> {
1169-
let kind = match t.kind {
1170-
TyKind::Infer => hir::TyKind::Infer,
1171-
TyKind::Err => hir::TyKind::Err,
1172-
TyKind::Slice(ref ty) => hir::TyKind::Slice(self.lower_ty(ty, itctx)),
1173-
TyKind::Ptr(ref mt) => hir::TyKind::Ptr(self.lower_mt(mt, itctx)),
1174-
TyKind::Rptr(ref region, ref mt) => {
1175-
let region = region.unwrap_or_else(|| {
1170+
ensure_sufficient_stack(|| {
1171+
let kind = match t.kind {
1172+
TyKind::Infer => hir::TyKind::Infer,
1173+
TyKind::Err => hir::TyKind::Err,
1174+
TyKind::Slice(ref ty) => hir::TyKind::Slice(self.lower_ty(ty, itctx)),
1175+
TyKind::Ptr(ref mt) => hir::TyKind::Ptr(self.lower_mt(mt, itctx)),
1176+
TyKind::Rptr(ref region, ref mt) => {
1177+
let region = region.unwrap_or_else(|| {
11761178
let Some(LifetimeRes::ElidedAnchor { start, end }) = self.resolver.get_lifetime_res(t.id) else {
11771179
panic!()
11781180
};
@@ -1183,56 +1185,53 @@ impl<'a, 'hir> LoweringContext<'a, 'hir> {
11831185
id: start,
11841186
}
11851187
});
1186-
let lifetime = self.lower_lifetime(&region);
1187-
hir::TyKind::Rptr(lifetime, self.lower_mt(mt, itctx))
1188-
}
1189-
TyKind::BareFn(ref f) => self.with_lifetime_binder(t.id, |this| {
1190-
hir::TyKind::BareFn(this.arena.alloc(hir::BareFnTy {
1191-
generic_params: this.lower_generic_params(
1192-
&f.generic_params,
1193-
ImplTraitContext::Disallowed(ImplTraitPosition::Generic),
1194-
),
1195-
unsafety: this.lower_unsafety(f.unsafety),
1196-
abi: this.lower_extern(f.ext),
1197-
decl: this.lower_fn_decl(&f.decl, None, FnDeclKind::Pointer, None),
1198-
param_names: this.lower_fn_params_to_names(&f.decl),
1199-
}))
1200-
}),
1201-
TyKind::Never => hir::TyKind::Never,
1202-
TyKind::Tup(ref tys) => {
1203-
hir::TyKind::Tup(self.arena.alloc_from_iter(
1188+
let lifetime = self.lower_lifetime(&region);
1189+
hir::TyKind::Rptr(lifetime, self.lower_mt(mt, itctx))
1190+
}
1191+
TyKind::BareFn(ref f) => self.with_lifetime_binder(t.id, |this| {
1192+
hir::TyKind::BareFn(this.arena.alloc(hir::BareFnTy {
1193+
generic_params: this.lower_generic_params(
1194+
&f.generic_params,
1195+
ImplTraitContext::Disallowed(ImplTraitPosition::Generic),
1196+
),
1197+
unsafety: this.lower_unsafety(f.unsafety),
1198+
abi: this.lower_extern(f.ext),
1199+
decl: this.lower_fn_decl(&f.decl, None, FnDeclKind::Pointer, None),
1200+
param_names: this.lower_fn_params_to_names(&f.decl),
1201+
}))
1202+
}),
1203+
TyKind::Never => hir::TyKind::Never,
1204+
TyKind::Tup(ref tys) => hir::TyKind::Tup(self.arena.alloc_from_iter(
12041205
tys.iter().map(|ty| self.lower_ty_direct(ty, itctx.reborrow())),
1205-
))
1206-
}
1207-
TyKind::Paren(ref ty) => {
1208-
return self.lower_ty_direct(ty, itctx);
1209-
}
1210-
TyKind::Path(ref qself, ref path) => {
1211-
return self.lower_path_ty(t, qself, path, ParamMode::Explicit, itctx);
1212-
}
1213-
TyKind::ImplicitSelf => {
1214-
let res = self.expect_full_res(t.id);
1215-
let res = self.lower_res(res);
1216-
hir::TyKind::Path(hir::QPath::Resolved(
1217-
None,
1218-
self.arena.alloc(hir::Path {
1219-
res,
1220-
segments: arena_vec![self; hir::PathSegment::from_ident(
1221-
Ident::with_dummy_span(kw::SelfUpper)
1222-
)],
1223-
span: self.lower_span(t.span),
1224-
}),
1225-
))
1226-
}
1227-
TyKind::Array(ref ty, ref length) => {
1228-
hir::TyKind::Array(self.lower_ty(ty, itctx), self.lower_array_length(length))
1229-
}
1230-
TyKind::Typeof(ref expr) => hir::TyKind::Typeof(self.lower_anon_const(expr)),
1231-
TyKind::TraitObject(ref bounds, kind) => {
1232-
let mut lifetime_bound = None;
1233-
let (bounds, lifetime_bound) = self.with_dyn_type_scope(true, |this| {
1234-
let bounds =
1235-
this.arena.alloc_from_iter(bounds.iter().filter_map(
1206+
)),
1207+
TyKind::Paren(ref ty) => {
1208+
return self.lower_ty_direct(ty, itctx);
1209+
}
1210+
TyKind::Path(ref qself, ref path) => {
1211+
return self.lower_path_ty(t, qself, path, ParamMode::Explicit, itctx);
1212+
}
1213+
TyKind::ImplicitSelf => {
1214+
let res = self.expect_full_res(t.id);
1215+
let res = self.lower_res(res);
1216+
hir::TyKind::Path(hir::QPath::Resolved(
1217+
None,
1218+
self.arena.alloc(hir::Path {
1219+
res,
1220+
segments: arena_vec![self; hir::PathSegment::from_ident(
1221+
Ident::with_dummy_span(kw::SelfUpper)
1222+
)],
1223+
span: self.lower_span(t.span),
1224+
}),
1225+
))
1226+
}
1227+
TyKind::Array(ref ty, ref length) => {
1228+
hir::TyKind::Array(self.lower_ty(ty, itctx), self.lower_array_length(length))
1229+
}
1230+
TyKind::Typeof(ref expr) => hir::TyKind::Typeof(self.lower_anon_const(expr)),
1231+
TyKind::TraitObject(ref bounds, kind) => {
1232+
let mut lifetime_bound = None;
1233+
let (bounds, lifetime_bound) = self.with_dyn_type_scope(true, |this| {
1234+
let bounds = this.arena.alloc_from_iter(bounds.iter().filter_map(
12361235
|bound| match *bound {
12371236
GenericBound::Trait(
12381237
ref ty,
@@ -1252,80 +1251,84 @@ impl<'a, 'hir> LoweringContext<'a, 'hir> {
12521251
}
12531252
},
12541253
));
1255-
let lifetime_bound =
1256-
lifetime_bound.unwrap_or_else(|| this.elided_dyn_bound(t.span));
1257-
(bounds, lifetime_bound)
1258-
});
1259-
hir::TyKind::TraitObject(bounds, lifetime_bound, kind)
1260-
}
1261-
TyKind::ImplTrait(def_node_id, ref bounds) => {
1262-
let span = t.span;
1263-
match itctx {
1264-
ImplTraitContext::ReturnPositionOpaqueTy { origin } => self
1265-
.lower_opaque_impl_trait(span, origin, def_node_id, |this| {
1266-
this.lower_param_bounds(bounds, itctx)
1267-
}),
1268-
ImplTraitContext::TypeAliasesOpaqueTy => {
1269-
let nested_itctx = ImplTraitContext::TypeAliasesOpaqueTy;
1270-
self.lower_opaque_impl_trait(
1271-
span,
1272-
hir::OpaqueTyOrigin::TyAlias,
1273-
def_node_id,
1274-
|this| this.lower_param_bounds(bounds, nested_itctx),
1275-
)
1276-
}
1277-
ImplTraitContext::Universal(in_band_ty_params, parent_def_id) => {
1278-
// Add a definition for the in-band `Param`.
1279-
let def_id = self.resolver.local_def_id(def_node_id);
1254+
let lifetime_bound =
1255+
lifetime_bound.unwrap_or_else(|| this.elided_dyn_bound(t.span));
1256+
(bounds, lifetime_bound)
1257+
});
1258+
hir::TyKind::TraitObject(bounds, lifetime_bound, kind)
1259+
}
1260+
TyKind::ImplTrait(def_node_id, ref bounds) => {
1261+
let span = t.span;
1262+
match itctx {
1263+
ImplTraitContext::ReturnPositionOpaqueTy { origin } => self
1264+
.lower_opaque_impl_trait(span, origin, def_node_id, |this| {
1265+
this.lower_param_bounds(bounds, itctx)
1266+
}),
1267+
ImplTraitContext::TypeAliasesOpaqueTy => {
1268+
let nested_itctx = ImplTraitContext::TypeAliasesOpaqueTy;
1269+
self.lower_opaque_impl_trait(
1270+
span,
1271+
hir::OpaqueTyOrigin::TyAlias,
1272+
def_node_id,
1273+
|this| this.lower_param_bounds(bounds, nested_itctx),
1274+
)
1275+
}
1276+
ImplTraitContext::Universal(in_band_ty_params, parent_def_id) => {
1277+
// Add a definition for the in-band `Param`.
1278+
let def_id = self.resolver.local_def_id(def_node_id);
12801279

1281-
let hir_bounds = self.lower_param_bounds(
1282-
bounds,
1283-
ImplTraitContext::Universal(in_band_ty_params, parent_def_id),
1284-
);
1285-
// Set the name to `impl Bound1 + Bound2`.
1286-
let ident = Ident::from_str_and_span(&pprust::ty_to_string(t), span);
1287-
in_band_ty_params.push(hir::GenericParam {
1288-
hir_id: self.lower_node_id(def_node_id),
1289-
name: ParamName::Plain(self.lower_ident(ident)),
1290-
pure_wrt_drop: false,
1291-
bounds: hir_bounds,
1292-
span: self.lower_span(span),
1293-
kind: hir::GenericParamKind::Type { default: None, synthetic: true },
1294-
});
1280+
let hir_bounds = self.lower_param_bounds(
1281+
bounds,
1282+
ImplTraitContext::Universal(in_band_ty_params, parent_def_id),
1283+
);
1284+
// Set the name to `impl Bound1 + Bound2`.
1285+
let ident = Ident::from_str_and_span(&pprust::ty_to_string(t), span);
1286+
in_band_ty_params.push(hir::GenericParam {
1287+
hir_id: self.lower_node_id(def_node_id),
1288+
name: ParamName::Plain(self.lower_ident(ident)),
1289+
pure_wrt_drop: false,
1290+
bounds: hir_bounds,
1291+
span: self.lower_span(span),
1292+
kind: hir::GenericParamKind::Type {
1293+
default: None,
1294+
synthetic: true,
1295+
},
1296+
});
12951297

1296-
hir::TyKind::Path(hir::QPath::Resolved(
1298+
hir::TyKind::Path(hir::QPath::Resolved(
12971299
None,
12981300
self.arena.alloc(hir::Path {
12991301
span: self.lower_span(span),
13001302
res: Res::Def(DefKind::TyParam, def_id.to_def_id()),
13011303
segments: arena_vec![self; hir::PathSegment::from_ident(self.lower_ident(ident))],
13021304
}),
13031305
))
1304-
}
1305-
ImplTraitContext::Disallowed(position) => {
1306-
let mut err = struct_span_err!(
1307-
self.sess,
1308-
t.span,
1309-
E0562,
1310-
"`impl Trait` only allowed in function and inherent method return types, not in {}",
1311-
position
1312-
);
1313-
err.emit();
1314-
hir::TyKind::Err
1306+
}
1307+
ImplTraitContext::Disallowed(position) => {
1308+
let mut err = struct_span_err!(
1309+
self.sess,
1310+
t.span,
1311+
E0562,
1312+
"`impl Trait` only allowed in function and inherent method return types, not in {}",
1313+
position
1314+
);
1315+
err.emit();
1316+
hir::TyKind::Err
1317+
}
13151318
}
13161319
}
1317-
}
1318-
TyKind::MacCall(_) => panic!("`TyKind::MacCall` should have been expanded by now"),
1319-
TyKind::CVarArgs => {
1320-
self.sess.delay_span_bug(
1321-
t.span,
1322-
"`TyKind::CVarArgs` should have been handled elsewhere",
1323-
);
1324-
hir::TyKind::Err
1325-
}
1326-
};
1320+
TyKind::MacCall(_) => panic!("`TyKind::MacCall` should have been expanded by now"),
1321+
TyKind::CVarArgs => {
1322+
self.sess.delay_span_bug(
1323+
t.span,
1324+
"`TyKind::CVarArgs` should have been handled elsewhere",
1325+
);
1326+
hir::TyKind::Err
1327+
}
1328+
};
13271329

1328-
hir::Ty { kind, span: self.lower_span(t.span), hir_id: self.lower_node_id(t.id) }
1330+
hir::Ty { kind, span: self.lower_span(t.span), hir_id: self.lower_node_id(t.id) }
1331+
})
13291332
}
13301333

13311334
#[tracing::instrument(level = "debug", skip(self, lower_bounds))]

compiler/rustc_ast_passes/src/ast_validation.rs

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -13,6 +13,7 @@ use rustc_ast::walk_list;
1313
use rustc_ast::*;
1414
use rustc_ast_pretty::pprust::{self, State};
1515
use rustc_data_structures::fx::FxHashMap;
16+
use rustc_data_structures::stack::ensure_sufficient_stack;
1617
use rustc_errors::{error_code, pluralize, struct_span_err, Applicability};
1718
use rustc_parse::validate_attr;
1819
use rustc_session::lint::builtin::{
@@ -215,7 +216,7 @@ impl<'a> AstValidator<'a> {
215216

216217
// Mirrors `visit::walk_ty`, but tracks relevant state.
217218
fn walk_ty(&mut self, t: &'a Ty) {
218-
match t.kind {
219+
ensure_sufficient_stack(|| match t.kind {
219220
TyKind::ImplTrait(..) => {
220221
self.with_impl_trait(Some(t.span), |this| visit::walk_ty(this, t))
221222
}
@@ -254,7 +255,7 @@ impl<'a> AstValidator<'a> {
254255
}
255256
}
256257
_ => visit::walk_ty(self, t),
257-
}
258+
})
258259
}
259260

260261
fn visit_struct_field_def(&mut self, field: &'a FieldDef) {

0 commit comments

Comments
 (0)