Skip to content

Commit 5a014eb

Browse files
feat: add expansion_grow_limit attr as another expansion limit
Signed-off-by: Vincenzo Palazzo <[email protected]>
1 parent 8091736 commit 5a014eb

File tree

8 files changed

+78
-0
lines changed

8 files changed

+78
-0
lines changed

compiler/rustc_expand/src/base.rs

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1008,6 +1008,7 @@ pub struct ExtCtxt<'a> {
10081008
pub ecfg: expand::ExpansionConfig<'a>,
10091009
pub num_standard_library_imports: usize,
10101010
pub reduced_recursion_limit: Option<Limit>,
1011+
pub reduced_expansion_growth_limit: Option<Limit>,
10111012
pub root_path: PathBuf,
10121013
pub resolver: &'a mut dyn ResolverExpand,
10131014
pub current_expansion: ExpansionData,
@@ -1037,6 +1038,7 @@ impl<'a> ExtCtxt<'a> {
10371038
ecfg,
10381039
num_standard_library_imports: 0,
10391040
reduced_recursion_limit: None,
1041+
reduced_expansion_growth_limit: None,
10401042
resolver,
10411043
lint_store,
10421044
root_path: PathBuf::new(),

compiler/rustc_expand/src/expand.rs

Lines changed: 47 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -621,6 +621,30 @@ impl<'a, 'b> MacroExpander<'a, 'b> {
621621
self.cx.trace_macros_diag();
622622
}
623623

624+
fn error_expansion_growth_limit(&mut self) {
625+
let expn_data = self.cx.current_expansion.id.expn_data();
626+
let suggested_limit = match self.cx.ecfg.expansion_growth_limit {
627+
Limit(0) => Limit(2),
628+
limit => limit * 2,
629+
};
630+
631+
self.cx
632+
.struct_span_err(
633+
expn_data.call_site,
634+
&format!(
635+
"expansion grow limit reached while expanding `{}`",
636+
expn_data.kind.descr()
637+
),
638+
)
639+
.help(&format!(
640+
"consider increasing the expansion grow limit by adding a \
641+
`#![expansion_growth_limit = \"{}\"]` attribute to your crate (`{}`)",
642+
suggested_limit, self.cx.ecfg.crate_name,
643+
))
644+
.emit();
645+
self.cx.trace_macros_diag();
646+
}
647+
624648
/// A macro's expansion does not fit in this fragment kind.
625649
/// For example, a non-type macro in a type position.
626650
fn error_wrong_fragment_kind(&mut self, kind: AstFragmentKind, mac: &ast::MacCall, span: Span) {
@@ -629,6 +653,22 @@ impl<'a, 'b> MacroExpander<'a, 'b> {
629653
self.cx.trace_macros_diag();
630654
}
631655

656+
fn reduce_expansion_growth_limit(&mut self, tokens_solved_size: usize) -> Result<(), ()> {
657+
let expansion_limit =
658+
self.cx.reduced_expansion_growth_limit.unwrap_or(self.cx.ecfg.expansion_growth_limit);
659+
if !expansion_limit.value_within_limit(tokens_solved_size) {
660+
if self.cx.reduced_expansion_growth_limit.is_none() {
661+
self.error_expansion_growth_limit();
662+
}
663+
664+
// Reduce the recursion limit by half each time it triggers.
665+
self.cx.reduced_recursion_limit = Some(expansion_limit / 2);
666+
667+
return Err(());
668+
}
669+
Ok(())
670+
}
671+
632672
fn expand_invoc(
633673
&mut self,
634674
invoc: Invocation,
@@ -657,6 +697,11 @@ impl<'a, 'b> MacroExpander<'a, 'b> {
657697
self.parse_ast_fragment(tok_result, fragment_kind, &mac.path, span)
658698
}
659699
SyntaxExtensionKind::LegacyBang(expander) => {
700+
if self.reduce_expansion_growth_limit(mac.args.inner_tokens().len()).is_err() {
701+
return ExpandResult::Ready(fragment_kind.dummy(span));
702+
}
703+
let prev = self.cx.current_expansion.prior_type_ascription;
704+
self.cx.current_expansion.prior_type_ascription = mac.prior_type_ascription;
660705
let tok_result = expander.expand(self.cx, span, mac.args.tokens.clone());
661706
let result = if let Some(result) = fragment_kind.make_from(tok_result) {
662707
result
@@ -1966,6 +2011,7 @@ pub struct ExpansionConfig<'feat> {
19662011
pub crate_name: String,
19672012
pub features: Option<&'feat Features>,
19682013
pub recursion_limit: Limit,
2014+
pub expansion_growth_limit: Limit,
19692015
pub trace_mac: bool,
19702016
/// If false, strip `#[test]` nodes
19712017
pub should_test: bool,
@@ -1981,6 +2027,7 @@ impl<'feat> ExpansionConfig<'feat> {
19812027
crate_name,
19822028
features: None,
19832029
recursion_limit: Limit::new(1024),
2030+
expansion_growth_limit: Limit::new(1500),
19842031
trace_mac: false,
19852032
should_test: false,
19862033
span_debug: false,

compiler/rustc_feature/src/builtin_attrs.rs

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -354,6 +354,7 @@ pub const BUILTIN_ATTRIBUTES: &[BuiltinAttribute] = &[
354354

355355
// Limits:
356356
ungated!(recursion_limit, CrateLevel, template!(NameValueStr: "N"), FutureWarnFollowing),
357+
ungated!(expansion_growth_limit, CrateLevel, template!(NameValueStr: "N"), FutureWarnFollowing),
357358
ungated!(type_length_limit, CrateLevel, template!(NameValueStr: "N"), FutureWarnFollowing),
358359
gated!(
359360
move_size_limit, CrateLevel, template!(NameValueStr: "N"), ErrorFollowing,

compiler/rustc_interface/src/passes.rs

Lines changed: 16 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -226,9 +226,11 @@ fn configure_and_expand(
226226
// Create the config for macro expansion
227227
let features = sess.features_untracked();
228228
let recursion_limit = get_recursion_limit(pre_configured_attrs, sess);
229+
let expansion_growth_limit = get_expansion_growth_limit(&krate.attrs, sess);
229230
let cfg = rustc_expand::expand::ExpansionConfig {
230231
features: Some(features),
231232
recursion_limit,
233+
expansion_growth_limit,
232234
trace_mac: sess.opts.unstable_opts.trace_macros,
233235
should_test: sess.is_test_crate(),
234236
span_debug: sess.opts.unstable_opts.span_debug,
@@ -903,3 +905,17 @@ fn get_recursion_limit(krate_attrs: &[ast::Attribute], sess: &Session) -> Limit
903905
}
904906
rustc_middle::middle::limits::get_recursion_limit(krate_attrs, sess)
905907
}
908+
909+
fn get_expansion_growth_limit(krate_attrs: &[ast::Attribute], sess: &Session) -> Limit {
910+
if let Some(attr) = krate_attrs
911+
.iter()
912+
.find(|attr| attr.has_name(sym::expansion_growth_limit) && attr.value_str().is_none())
913+
{
914+
validate_attr::emit_fatal_malformed_builtin_attribute(
915+
&sess.parse_sess,
916+
attr,
917+
sym::expansion_growth_limit,
918+
);
919+
}
920+
rustc_middle::middle::limits::get_expansion_growth_limit(krate_attrs, sess)
921+
}

compiler/rustc_middle/src/middle/limits.rs

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -21,6 +21,7 @@ use std::num::IntErrorKind;
2121
pub fn provide(providers: &mut Providers) {
2222
providers.limits = |tcx, ()| Limits {
2323
recursion_limit: get_recursion_limit(tcx.hir().krate_attrs(), tcx.sess),
24+
expansion_growth_limit: get_expansion_growth_limit(tcx.hir().krate_attrs(), tcx.sess),
2425
move_size_limit: get_limit(
2526
tcx.hir().krate_attrs(),
2627
tcx.sess,
@@ -40,6 +41,10 @@ pub fn get_recursion_limit(krate_attrs: &[Attribute], sess: &Session) -> Limit {
4041
get_limit(krate_attrs, sess, sym::recursion_limit, 128)
4142
}
4243

44+
pub fn get_expansion_growth_limit(krate_attrs: &[Attribute], sess: &Session) -> Limit {
45+
get_limit(krate_attrs, sess, sym::expansion_growth_limit, 1500)
46+
}
47+
4348
fn get_limit(krate_attrs: &[Attribute], sess: &Session, name: Symbol, default: usize) -> Limit {
4449
for attr in krate_attrs {
4550
if !attr.has_name(name) {

compiler/rustc_middle/src/ty/context.rs

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1175,6 +1175,10 @@ impl<'tcx> TyCtxt<'tcx> {
11751175
self.limits(()).recursion_limit
11761176
}
11771177

1178+
pub fn expansion_growth_limit(self) -> Limit {
1179+
self.limits(()).expansion_growth_limit
1180+
}
1181+
11781182
pub fn move_size_limit(self) -> Limit {
11791183
self.limits(()).move_size_limit
11801184
}

compiler/rustc_session/src/session.rs

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -128,6 +128,8 @@ pub struct Limits {
128128
pub move_size_limit: Limit,
129129
/// The maximum length of types during monomorphization.
130130
pub type_length_limit: Limit,
131+
/// FIXME(vincenzopalazzo) add docs
132+
pub expansion_growth_limit: Limit,
131133
}
132134

133135
pub struct CompilerIO {

compiler/rustc_span/src/symbol.rs

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -682,6 +682,7 @@ symbols! {
682682
existential_type,
683683
exp2f32,
684684
exp2f64,
685+
expansion_growth_limit,
685686
expect,
686687
expected,
687688
expf32,

0 commit comments

Comments
 (0)