Skip to content

Commit 469c641

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

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
@@ -1011,6 +1011,7 @@ pub struct ExtCtxt<'a> {
10111011
pub ecfg: expand::ExpansionConfig<'a>,
10121012
pub num_standard_library_imports: usize,
10131013
pub reduced_recursion_limit: Option<Limit>,
1014+
pub reduced_expansion_growth_limit: Option<Limit>,
10141015
pub root_path: PathBuf,
10151016
pub resolver: &'a mut dyn ResolverExpand,
10161017
pub current_expansion: ExpansionData,
@@ -1040,6 +1041,7 @@ impl<'a> ExtCtxt<'a> {
10401041
ecfg,
10411042
num_standard_library_imports: 0,
10421043
reduced_recursion_limit: None,
1044+
reduced_expansion_growth_limit: None,
10431045
resolver,
10441046
lint_store,
10451047
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,
@@ -658,6 +698,11 @@ impl<'a, 'b> MacroExpander<'a, 'b> {
658698
self.parse_ast_fragment(tok_result, fragment_kind, &mac.path, span)
659699
}
660700
SyntaxExtensionKind::LegacyBang(expander) => {
701+
if self.reduce_expansion_growth_limit(mac.args.inner_tokens().len()).is_err() {
702+
return ExpandResult::Ready(fragment_kind.dummy(span));
703+
}
704+
let prev = self.cx.current_expansion.prior_type_ascription;
705+
self.cx.current_expansion.prior_type_ascription = mac.prior_type_ascription;
661706
let tok_result = expander.expand(self.cx, span, mac.args.tokens.clone());
662707
let result = if let Some(result) = fragment_kind.make_from(tok_result) {
663708
result
@@ -1979,6 +2024,7 @@ pub struct ExpansionConfig<'feat> {
19792024
pub crate_name: String,
19802025
pub features: &'feat Features,
19812026
pub recursion_limit: Limit,
2027+
pub expansion_growth_limit: Limit,
19822028
pub trace_mac: bool,
19832029
/// If false, strip `#[test]` nodes
19842030
pub should_test: bool,
@@ -1994,6 +2040,7 @@ impl ExpansionConfig<'_> {
19942040
crate_name,
19952041
features,
19962042
recursion_limit: Limit::new(1024),
2043+
expansion_growth_limit: Limit::new(1500),
19972044
trace_mac: false,
19982045
should_test: false,
19992046
span_debug: false,

compiler/rustc_feature/src/builtin_attrs.rs

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

356356
// Limits:
357357
ungated!(recursion_limit, CrateLevel, template!(NameValueStr: "N"), FutureWarnFollowing),
358+
ungated!(expansion_growth_limit, CrateLevel, template!(NameValueStr: "N"), FutureWarnFollowing),
358359
ungated!(type_length_limit, CrateLevel, template!(NameValueStr: "N"), FutureWarnFollowing),
359360
gated!(
360361
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
@@ -212,10 +212,12 @@ fn configure_and_expand(
212212

213213
// Create the config for macro expansion
214214
let recursion_limit = get_recursion_limit(pre_configured_attrs, sess);
215+
let expansion_growth_limit = get_expansion_growth_limit(&krate.attrs, sess);
215216
let cfg = rustc_expand::expand::ExpansionConfig {
216217
crate_name: crate_name.to_string(),
217218
features,
218219
recursion_limit,
220+
expansion_growth_limit,
219221
trace_mac: sess.opts.unstable_opts.trace_macros,
220222
should_test: sess.is_test_crate(),
221223
span_debug: sess.opts.unstable_opts.span_debug,
@@ -1007,3 +1009,17 @@ fn get_recursion_limit(krate_attrs: &[ast::Attribute], sess: &Session) -> Limit
10071009
}
10081010
rustc_middle::middle::limits::get_recursion_limit(krate_attrs, sess)
10091011
}
1012+
1013+
fn get_expansion_growth_limit(krate_attrs: &[ast::Attribute], sess: &Session) -> Limit {
1014+
if let Some(attr) = krate_attrs
1015+
.iter()
1016+
.find(|attr| attr.has_name(sym::expansion_growth_limit) && attr.value_str().is_none())
1017+
{
1018+
validate_attr::emit_fatal_malformed_builtin_attribute(
1019+
&sess.parse_sess,
1020+
attr,
1021+
sym::expansion_growth_limit,
1022+
);
1023+
}
1024+
rustc_middle::middle::limits::get_expansion_growth_limit(krate_attrs, sess)
1025+
}

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
@@ -1165,6 +1165,10 @@ impl<'tcx> TyCtxt<'tcx> {
11651165
self.limits(()).recursion_limit
11661166
}
11671167

1168+
pub fn expansion_growth_limit(self) -> Limit {
1169+
self.limits(()).expansion_growth_limit
1170+
}
1171+
11681172
pub fn move_size_limit(self) -> Limit {
11691173
self.limits(()).move_size_limit
11701174
}

compiler/rustc_session/src/session.rs

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -130,6 +130,8 @@ pub struct Limits {
130130
pub move_size_limit: Limit,
131131
/// The maximum length of types during monomorphization.
132132
pub type_length_limit: Limit,
133+
/// FIXME(vincenzopalazzo) add docs
134+
pub expansion_growth_limit: Limit,
133135
}
134136

135137
pub struct CompilerIO {

compiler/rustc_span/src/symbol.rs

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -700,6 +700,7 @@ symbols! {
700700
existential_type,
701701
exp2f32,
702702
exp2f64,
703+
expansion_growth_limit,
703704
expect,
704705
expected,
705706
expf32,

0 commit comments

Comments
 (0)