Skip to content

Commit 5ba4bbd

Browse files
committed
Introduce -Zmacro-stats.
It collects data about macro expansions and prints them in a table after expansion finishes. It's very useful for detecting macro bloat, especially for proc macros. Details: - It measures code snippets by pretty-printing them and then measuring lines and bytes. This required a bunch of additional pretty-printing plumbing, in `rustc_ast_pretty` and `rustc_expand`. - The measurement is done in `MacroExpander::expand_invoc`. - The measurements are stored in `ExtCtxt::macro_stats`.
1 parent 68f349c commit 5ba4bbd

File tree

13 files changed

+626
-50
lines changed

13 files changed

+626
-50
lines changed

compiler/rustc_ast_pretty/src/pprust/mod.rs

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -53,6 +53,18 @@ pub fn item_to_string(i: &ast::Item) -> String {
5353
State::new().item_to_string(i)
5454
}
5555

56+
pub fn assoc_item_to_string(i: &ast::AssocItem) -> String {
57+
State::new().assoc_item_to_string(i)
58+
}
59+
60+
pub fn foreign_item_to_string(i: &ast::ForeignItem) -> String {
61+
State::new().foreign_item_to_string(i)
62+
}
63+
64+
pub fn stmt_to_string(s: &ast::Stmt) -> String {
65+
State::new().stmt_to_string(s)
66+
}
67+
5668
pub fn path_to_string(p: &ast::Path) -> String {
5769
State::new().path_to_string(p)
5870
}

compiler/rustc_ast_pretty/src/pprust/state.rs

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1063,6 +1063,14 @@ pub trait PrintState<'a>: std::ops::Deref<Target = pp::Printer> + std::ops::Dere
10631063
Self::to_string(|s| s.print_item(i))
10641064
}
10651065

1066+
fn assoc_item_to_string(&self, i: &ast::AssocItem) -> String {
1067+
Self::to_string(|s| s.print_assoc_item(i))
1068+
}
1069+
1070+
fn foreign_item_to_string(&self, i: &ast::ForeignItem) -> String {
1071+
Self::to_string(|s| s.print_foreign_item(i))
1072+
}
1073+
10661074
fn path_to_string(&self, p: &ast::Path) -> String {
10671075
Self::to_string(|s| s.print_path(p, false, 0))
10681076
}

compiler/rustc_ast_pretty/src/pprust/state/item.rs

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -28,7 +28,7 @@ impl<'a> State<'a> {
2828
}
2929
}
3030

31-
fn print_foreign_item(&mut self, item: &ast::ForeignItem) {
31+
pub(crate) fn print_foreign_item(&mut self, item: &ast::ForeignItem) {
3232
let ast::Item { id, span, ref attrs, ref kind, ref vis, tokens: _ } = *item;
3333
self.ann.pre(self, AnnNode::SubItem(id));
3434
self.hardbreak_if_not_bol();
@@ -548,7 +548,7 @@ impl<'a> State<'a> {
548548
}
549549
}
550550

551-
fn print_assoc_item(&mut self, item: &ast::AssocItem) {
551+
pub(crate) fn print_assoc_item(&mut self, item: &ast::AssocItem) {
552552
let ast::Item { id, span, ref attrs, ref kind, ref vis, tokens: _ } = *item;
553553
self.ann.pre(self, AnnNode::SubItem(id));
554554
self.hardbreak_if_not_bol();

compiler/rustc_expand/src/base.rs

Lines changed: 48 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -12,7 +12,7 @@ use rustc_ast::tokenstream::TokenStream;
1212
use rustc_ast::visit::{AssocCtxt, Visitor};
1313
use rustc_ast::{self as ast, AttrVec, Attribute, HasAttrs, Item, NodeId, PatKind};
1414
use rustc_attr_data_structures::{AttributeKind, Deprecation, Stability, find_attr};
15-
use rustc_data_structures::fx::FxIndexMap;
15+
use rustc_data_structures::fx::{FxHashMap, FxIndexMap};
1616
use rustc_data_structures::sync;
1717
use rustc_errors::{DiagCtxtHandle, ErrorGuaranteed, PResult};
1818
use rustc_feature::Features;
@@ -727,6 +727,7 @@ pub enum SyntaxExtensionKind {
727727
/// A trivial attribute "macro" that does nothing,
728728
/// only keeps the attribute and marks it as inert,
729729
/// thus making it ineligible for further expansion.
730+
/// E.g. `#[default]`, `#[rustfmt::skip]`.
730731
NonMacroAttr,
731732

732733
/// A token-based derive macro.
@@ -1166,6 +1167,49 @@ pub struct ExpansionData {
11661167
pub is_trailing_mac: bool,
11671168
}
11681169

1170+
#[derive(Default)]
1171+
pub struct MacroStat {
1172+
/// Number of invocations of the macro.
1173+
pub count: usize,
1174+
1175+
/// Net increase in number of lines of code (when pretty-printed), i.e.
1176+
/// `lines(output) - lines(invocation)`. Can be negative because a macro
1177+
/// output may be smaller than the invocation.
1178+
pub lines: isize,
1179+
1180+
/// Net increase in number of lines of code (when pretty-printed), i.e.
1181+
/// `bytes(output) - bytes(invocation)`. Can be negative because a macro
1182+
/// output may be smaller than the invocation.
1183+
pub bytes: isize,
1184+
}
1185+
1186+
#[derive(Clone, Copy, PartialEq, Eq, PartialOrd, Ord, Hash)]
1187+
pub enum MacroStatKind {
1188+
Attr,
1189+
Derive,
1190+
// This covers declarative macros and fn-like proc macros.
1191+
FnLike,
1192+
}
1193+
1194+
impl MacroStatKind {
1195+
pub fn label(&self) -> String {
1196+
match self {
1197+
MacroStatKind::Attr => "attr".to_string(),
1198+
MacroStatKind::Derive => "derive".to_string(),
1199+
MacroStatKind::FnLike => "fn-like".to_string(),
1200+
}
1201+
}
1202+
1203+
// Decorate the name to look like the macro invocation.
1204+
pub fn decorated_name(&self, name: &str) -> String {
1205+
match self {
1206+
MacroStatKind::Attr => format!("#[{name}]"),
1207+
MacroStatKind::Derive => name.to_string(),
1208+
MacroStatKind::FnLike => format!("{name}!"),
1209+
}
1210+
}
1211+
}
1212+
11691213
/// One of these is made during expansion and incrementally updated as we go;
11701214
/// when a macro expansion occurs, the resulting nodes have the `backtrace()
11711215
/// -> expn_data` of their expansion context stored into their span.
@@ -1189,6 +1233,8 @@ pub struct ExtCtxt<'a> {
11891233
/// in the AST, but insert it here so that we know
11901234
/// not to expand it again.
11911235
pub(super) expanded_inert_attrs: MarkedAttrs,
1236+
/// `-Zmacro-stats` data.
1237+
pub macro_stats: FxHashMap<(String, MacroStatKind), MacroStat>,
11921238
}
11931239

11941240
impl<'a> ExtCtxt<'a> {
@@ -1218,6 +1264,7 @@ impl<'a> ExtCtxt<'a> {
12181264
expansions: FxIndexMap::default(),
12191265
expanded_inert_attrs: MarkedAttrs::new(),
12201266
buffered_early_lint: vec![],
1267+
macro_stats: Default::default(),
12211268
}
12221269
}
12231270

0 commit comments

Comments
 (0)