Skip to content

Commit

Permalink
Reuse the P in InvocationCollector::fold_{,opt_}expr.
Browse files Browse the repository at this point in the history
This requires adding a new method, `P::filter_map`.

This commit reduces instruction counts for various benchmarks by up to
0.7%.
  • Loading branch information
nnethercote committed Nov 20, 2018
1 parent 9649c1f commit 6674db4
Show file tree
Hide file tree
Showing 2 changed files with 73 additions and 39 deletions.
84 changes: 48 additions & 36 deletions src/libsyntax/ext/expand.rs
Original file line number Diff line number Diff line change
Expand Up @@ -1201,50 +1201,62 @@ impl<'a, 'b> InvocationCollector<'a, 'b> {

impl<'a, 'b> Folder for InvocationCollector<'a, 'b> {
fn fold_expr(&mut self, expr: P<ast::Expr>) -> P<ast::Expr> {
let mut expr = self.cfg.configure_expr(expr).into_inner();
expr.node = self.cfg.configure_expr_kind(expr.node);

// ignore derives so they remain unused
let (attr, expr, after_derive) = self.classify_nonitem(expr);

if attr.is_some() {
// collect the invoc regardless of whether or not attributes are permitted here
// expansion will eat the attribute so it won't error later
attr.as_ref().map(|a| self.cfg.maybe_emit_expr_attr_err(a));

// AstFragmentKind::Expr requires the macro to emit an expression
return self.collect_attr(attr, vec![], Annotatable::Expr(P(expr)),
AstFragmentKind::Expr, after_derive).make_expr();
}
let expr = self.cfg.configure_expr(expr);
expr.map(|mut expr| {
expr.node = self.cfg.configure_expr_kind(expr.node);

// ignore derives so they remain unused
let (attr, expr, after_derive) = self.classify_nonitem(expr);

if attr.is_some() {
// Collect the invoc regardless of whether or not attributes are permitted here
// expansion will eat the attribute so it won't error later.
attr.as_ref().map(|a| self.cfg.maybe_emit_expr_attr_err(a));

// AstFragmentKind::Expr requires the macro to emit an expression.
return self.collect_attr(attr, vec![], Annotatable::Expr(P(expr)),
AstFragmentKind::Expr, after_derive)
.make_expr()
.into_inner()
}

if let ast::ExprKind::Mac(mac) = expr.node {
self.check_attributes(&expr.attrs);
self.collect_bang(mac, expr.span, AstFragmentKind::Expr).make_expr()
} else {
P(noop_fold_expr(expr, self))
}
if let ast::ExprKind::Mac(mac) = expr.node {
self.check_attributes(&expr.attrs);
self.collect_bang(mac, expr.span, AstFragmentKind::Expr)
.make_expr()
.into_inner()
} else {
noop_fold_expr(expr, self)
}
})
}

fn fold_opt_expr(&mut self, expr: P<ast::Expr>) -> Option<P<ast::Expr>> {
let mut expr = configure!(self, expr).into_inner();
expr.node = self.cfg.configure_expr_kind(expr.node);
let expr = configure!(self, expr);
expr.filter_map(|mut expr| {
expr.node = self.cfg.configure_expr_kind(expr.node);

// ignore derives so they remain unused
let (attr, expr, after_derive) = self.classify_nonitem(expr);
// Ignore derives so they remain unused.
let (attr, expr, after_derive) = self.classify_nonitem(expr);

if attr.is_some() {
attr.as_ref().map(|a| self.cfg.maybe_emit_expr_attr_err(a));
if attr.is_some() {
attr.as_ref().map(|a| self.cfg.maybe_emit_expr_attr_err(a));

return self.collect_attr(attr, vec![], Annotatable::Expr(P(expr)),
AstFragmentKind::OptExpr, after_derive).make_opt_expr();
}
return self.collect_attr(attr, vec![], Annotatable::Expr(P(expr)),
AstFragmentKind::OptExpr, after_derive)
.make_opt_expr()
.map(|expr| expr.into_inner())
}

if let ast::ExprKind::Mac(mac) = expr.node {
self.check_attributes(&expr.attrs);
self.collect_bang(mac, expr.span, AstFragmentKind::OptExpr).make_opt_expr()
} else {
Some(P(noop_fold_expr(expr, self)))
}
if let ast::ExprKind::Mac(mac) = expr.node {
self.check_attributes(&expr.attrs);
self.collect_bang(mac, expr.span, AstFragmentKind::OptExpr)
.make_opt_expr()
.map(|expr| expr.into_inner())
} else {
Some(noop_fold_expr(expr, self))
}
})
}

fn fold_pat(&mut self, pat: P<ast::Pat>) -> P<ast::Pat> {
Expand Down
28 changes: 25 additions & 3 deletions src/libsyntax/ptr.rs
Original file line number Diff line number Diff line change
Expand Up @@ -72,7 +72,7 @@ impl<T: 'static> P<T> {
*self.ptr
}

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

// Recreate self from the raw pointer.
P {
ptr: Box::from_raw(p)
P { ptr: Box::from_raw(p) }
}
}

/// Optionally produce a new `P<T>` from `self` without reallocating.
pub fn filter_map<F>(mut self, f: F) -> Option<P<T>> where
F: FnOnce(T) -> Option<T>,
{
let p: *mut T = &mut *self.ptr;

// Leak self in case of panic.
// FIXME(eddyb) Use some sort of "free guard" that
// only deallocates, without dropping the pointee,
// in case the call the `f` below ends in a panic.
mem::forget(self);

unsafe {
if let Some(v) = f(ptr::read(p)) {
ptr::write(p, v);

// Recreate self from the raw pointer.
Some(P { ptr: Box::from_raw(p) })
} else {
None
}
}
}
Expand Down

0 comments on commit 6674db4

Please sign in to comment.