Skip to content
This repository has been archived by the owner on May 6, 2020. It is now read-only.

Commit

Permalink
Auto merge of #92 - serde-rs:stack, r=erickt
Browse files Browse the repository at this point in the history
Add syntex::with_extra_stack helper

This is the same workaround from serde-rs/serde#503. I am adding it here because Servo just hit this with quasi_codegen (rust-lang/rust-bindgen#35) and I want to share the code. I will update the serde_codegen implementation to use this too.

Unfortunately we can't apply this to `syntex::Registry::expand` in general because rustc overflows its stack trying to decide whether `syntex::Registry` implements Send :panda_face:.
  • Loading branch information
homu committed Aug 20, 2016
2 parents 9d86db2 + 8337663 commit 7488fa6
Show file tree
Hide file tree
Showing 2 changed files with 66 additions and 0 deletions.
3 changes: 3 additions & 0 deletions syntex/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -27,6 +27,9 @@ use syntex_syntax::ptr::P;
mod error;
pub use error::Error;

mod stack;
pub use stack::with_extra_stack;

pub type Pass = fn(ast::Crate) -> ast::Crate;

pub struct Registry {
Expand Down
63 changes: 63 additions & 0 deletions syntex/src/stack.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,63 @@
use std::env;
use std::ffi::OsStr;
use std::ops::Drop;
use std::thread;

const STACK_ENV_VAR: &'static str = "RUST_MIN_STACK";
const EXTRA_STACK: &'static str = "16777216"; // 16 MB

/// Runs a function in a thread with extra stack space (16 MB or
/// `$RUST_MIN_STACK` if set).
///
/// The Rust parser uses a lot of stack space so codegen sometimes requires more
/// than is available by default.
///
/// ```rust,ignore
/// syntex::with_extra_stack(move || {
/// let mut reg = syntex::Registry::new();
/// reg.add_decorator(/* ... */);
/// reg.expand("", src, dst)
/// })
/// ```
///
/// This function runs with a 16 MB stack by default but a different value can
/// be set by the RUST_MIN_STACK environment variable.
pub fn with_extra_stack<F, T>(f: F) -> T
where F: Send + 'static + FnOnce() -> T,
T: Send + 'static
{
let _tmp_env = set_if_unset(STACK_ENV_VAR, EXTRA_STACK);

thread::spawn(f).join().unwrap()
}

fn set_if_unset<K, V>(k: K, v: V) -> TmpEnv<K>
where K: AsRef<OsStr>,
V: AsRef<OsStr>,
{
match env::var(&k) {
Ok(_) => TmpEnv::WasAlreadySet,
Err(_) => {
env::set_var(&k, v);
TmpEnv::WasNotSet(k)
}
}
}

#[must_use]
enum TmpEnv<K>
where K: AsRef<OsStr>,
{
WasAlreadySet,
WasNotSet(K),
}

impl<K> Drop for TmpEnv<K>
where K: AsRef<OsStr>,
{
fn drop(&mut self) {
if let TmpEnv::WasNotSet(ref k) = *self {
env::remove_var(k);
}
}
}

0 comments on commit 7488fa6

Please sign in to comment.