Skip to content

Commit 70567f6

Browse files
committed
Rollup merge of #56268 - nnethercote:fold_opt_expr-recycle, r=petrochenkov
Reuse the `P` in `InvocationCollector::fold_{,opt_}expr`. This requires adding a new method, `P::filter_map`. This commit reduces instruction counts for various benchmarks by up to 0.7%.
2 parents a524143 + 6674db4 commit 70567f6

File tree

2 files changed

+73
-39
lines changed

2 files changed

+73
-39
lines changed

src/libsyntax/ext/expand.rs

+48-36
Original file line numberDiff line numberDiff line change
@@ -1201,50 +1201,62 @@ impl<'a, 'b> InvocationCollector<'a, 'b> {
12011201

12021202
impl<'a, 'b> Folder for InvocationCollector<'a, 'b> {
12031203
fn fold_expr(&mut self, expr: P<ast::Expr>) -> P<ast::Expr> {
1204-
let mut expr = self.cfg.configure_expr(expr).into_inner();
1205-
expr.node = self.cfg.configure_expr_kind(expr.node);
1206-
1207-
// ignore derives so they remain unused
1208-
let (attr, expr, after_derive) = self.classify_nonitem(expr);
1209-
1210-
if attr.is_some() {
1211-
// collect the invoc regardless of whether or not attributes are permitted here
1212-
// expansion will eat the attribute so it won't error later
1213-
attr.as_ref().map(|a| self.cfg.maybe_emit_expr_attr_err(a));
1214-
1215-
// AstFragmentKind::Expr requires the macro to emit an expression
1216-
return self.collect_attr(attr, vec![], Annotatable::Expr(P(expr)),
1217-
AstFragmentKind::Expr, after_derive).make_expr();
1218-
}
1204+
let expr = self.cfg.configure_expr(expr);
1205+
expr.map(|mut expr| {
1206+
expr.node = self.cfg.configure_expr_kind(expr.node);
1207+
1208+
// ignore derives so they remain unused
1209+
let (attr, expr, after_derive) = self.classify_nonitem(expr);
1210+
1211+
if attr.is_some() {
1212+
// Collect the invoc regardless of whether or not attributes are permitted here
1213+
// expansion will eat the attribute so it won't error later.
1214+
attr.as_ref().map(|a| self.cfg.maybe_emit_expr_attr_err(a));
1215+
1216+
// AstFragmentKind::Expr requires the macro to emit an expression.
1217+
return self.collect_attr(attr, vec![], Annotatable::Expr(P(expr)),
1218+
AstFragmentKind::Expr, after_derive)
1219+
.make_expr()
1220+
.into_inner()
1221+
}
12191222

1220-
if let ast::ExprKind::Mac(mac) = expr.node {
1221-
self.check_attributes(&expr.attrs);
1222-
self.collect_bang(mac, expr.span, AstFragmentKind::Expr).make_expr()
1223-
} else {
1224-
P(noop_fold_expr(expr, self))
1225-
}
1223+
if let ast::ExprKind::Mac(mac) = expr.node {
1224+
self.check_attributes(&expr.attrs);
1225+
self.collect_bang(mac, expr.span, AstFragmentKind::Expr)
1226+
.make_expr()
1227+
.into_inner()
1228+
} else {
1229+
noop_fold_expr(expr, self)
1230+
}
1231+
})
12261232
}
12271233

12281234
fn fold_opt_expr(&mut self, expr: P<ast::Expr>) -> Option<P<ast::Expr>> {
1229-
let mut expr = configure!(self, expr).into_inner();
1230-
expr.node = self.cfg.configure_expr_kind(expr.node);
1235+
let expr = configure!(self, expr);
1236+
expr.filter_map(|mut expr| {
1237+
expr.node = self.cfg.configure_expr_kind(expr.node);
12311238

1232-
// ignore derives so they remain unused
1233-
let (attr, expr, after_derive) = self.classify_nonitem(expr);
1239+
// Ignore derives so they remain unused.
1240+
let (attr, expr, after_derive) = self.classify_nonitem(expr);
12341241

1235-
if attr.is_some() {
1236-
attr.as_ref().map(|a| self.cfg.maybe_emit_expr_attr_err(a));
1242+
if attr.is_some() {
1243+
attr.as_ref().map(|a| self.cfg.maybe_emit_expr_attr_err(a));
12371244

1238-
return self.collect_attr(attr, vec![], Annotatable::Expr(P(expr)),
1239-
AstFragmentKind::OptExpr, after_derive).make_opt_expr();
1240-
}
1245+
return self.collect_attr(attr, vec![], Annotatable::Expr(P(expr)),
1246+
AstFragmentKind::OptExpr, after_derive)
1247+
.make_opt_expr()
1248+
.map(|expr| expr.into_inner())
1249+
}
12411250

1242-
if let ast::ExprKind::Mac(mac) = expr.node {
1243-
self.check_attributes(&expr.attrs);
1244-
self.collect_bang(mac, expr.span, AstFragmentKind::OptExpr).make_opt_expr()
1245-
} else {
1246-
Some(P(noop_fold_expr(expr, self)))
1247-
}
1251+
if let ast::ExprKind::Mac(mac) = expr.node {
1252+
self.check_attributes(&expr.attrs);
1253+
self.collect_bang(mac, expr.span, AstFragmentKind::OptExpr)
1254+
.make_opt_expr()
1255+
.map(|expr| expr.into_inner())
1256+
} else {
1257+
Some(noop_fold_expr(expr, self))
1258+
}
1259+
})
12481260
}
12491261

12501262
fn fold_pat(&mut self, pat: P<ast::Pat>) -> P<ast::Pat> {

src/libsyntax/ptr.rs

+25-3
Original file line numberDiff line numberDiff line change
@@ -72,7 +72,7 @@ impl<T: 'static> P<T> {
7272
*self.ptr
7373
}
7474

75-
/// Transform the inner value, consuming `self` and producing a new `P<T>`.
75+
/// Produce a new `P<T>` from `self` without reallocating.
7676
pub fn map<F>(mut self, f: F) -> P<T> where
7777
F: FnOnce(T) -> T,
7878
{
@@ -88,8 +88,30 @@ impl<T: 'static> P<T> {
8888
ptr::write(p, f(ptr::read(p)));
8989

9090
// Recreate self from the raw pointer.
91-
P {
92-
ptr: Box::from_raw(p)
91+
P { ptr: Box::from_raw(p) }
92+
}
93+
}
94+
95+
/// Optionally produce a new `P<T>` from `self` without reallocating.
96+
pub fn filter_map<F>(mut self, f: F) -> Option<P<T>> where
97+
F: FnOnce(T) -> Option<T>,
98+
{
99+
let p: *mut T = &mut *self.ptr;
100+
101+
// Leak self in case of panic.
102+
// FIXME(eddyb) Use some sort of "free guard" that
103+
// only deallocates, without dropping the pointee,
104+
// in case the call the `f` below ends in a panic.
105+
mem::forget(self);
106+
107+
unsafe {
108+
if let Some(v) = f(ptr::read(p)) {
109+
ptr::write(p, v);
110+
111+
// Recreate self from the raw pointer.
112+
Some(P { ptr: Box::from_raw(p) })
113+
} else {
114+
None
93115
}
94116
}
95117
}

0 commit comments

Comments
 (0)