Fix conditional compilation guards

pull/3/head
Bradlee Speice 2018-11-18 21:29:32 -05:00
parent 79f57ba2f9
commit 5d7be8e18e
6 changed files with 101 additions and 62 deletions

1
.gitignore vendored
View File

@ -2,3 +2,4 @@
**/*.rs.bk **/*.rs.bk
Cargo.lock Cargo.lock
*.swp *.swp
.idea/

19
examples/release_mode.rs Normal file
View File

@ -0,0 +1,19 @@
extern crate qadapt;
use qadapt::allocate_panic;
use qadapt::QADAPT;
#[global_allocator]
static Q: QADAPT = QADAPT;
#[allocate_panic]
fn does_allocate() -> Box<u8> {
Box::new(0)
}
fn main() {
// If you were to run `cargo run --example release_mode`, this program blows up.
// If, however, you ran `cargo run --release --example release_mode`,
// nothing interesting will happen.
does_allocate();
}

View File

@ -58,35 +58,6 @@ macro_rules! token_stream {
}; };
} }
#[rustfmt::skip]
fn release_guard(fn_name: &str) -> TokenStream {
// #[cfg(any(debug, test))]
// { ::qadapt::`fn_name`() }
token_stream!(
punct!('#', Spacing::Alone),
group!(Delimiter::Bracket, token_stream!(
ident!("cfg"),
group!(Delimiter::Parenthesis, token_stream!(
ident!("any"),
group!(Delimiter::Parenthesis, token_stream!(
ident!("debug"),
punct!(',', Spacing::Alone),
ident!("test")
)),
)),
)),
group!(Delimiter::Brace, token_stream!(
punct!(':', Spacing::Joint),
punct!(':', Spacing::Alone),
ident!("qadapt"),
punct!(':', Spacing::Joint),
punct!(':', Spacing::Alone),
ident!(fn_name),
group!(Delimiter::Parenthesis)
))
)
}
/// Generate the body of a function that is protected from making allocations. /// Generate the body of a function that is protected from making allocations.
/// The code is conditionally compiled so that all QADAPT-related bits /// The code is conditionally compiled so that all QADAPT-related bits
/// will be removed for release/bench builds, making the proc_macro safe /// will be removed for release/bench builds, making the proc_macro safe
@ -94,7 +65,15 @@ fn release_guard(fn_name: &str) -> TokenStream {
#[rustfmt::skip] #[rustfmt::skip]
fn protected_body(fn_body: Group) -> TokenTree { fn protected_body(fn_body: Group) -> TokenTree {
group!(Delimiter::Brace, token_stream!( group!(Delimiter::Brace, token_stream!(
group!(Delimiter::Brace, release_guard("enter_protected")), group!(Delimiter::Brace, token_stream!(
punct!(':', Spacing::Joint),
punct!(':', Spacing::Alone),
ident!("qadapt"),
punct!(':', Spacing::Joint),
punct!(':', Spacing::Alone),
ident!("enter_protected"),
group!(Delimiter::Parenthesis)
)),
ident!("let"), ident!("let"),
ident!("__ret__"), ident!("__ret__"),
punct!('=', Spacing::Alone), punct!('=', Spacing::Alone),
@ -110,7 +89,15 @@ fn protected_body(fn_body: Group) -> TokenTree {
)) ))
)), )),
group!(Delimiter::Brace, token_stream!( group!(Delimiter::Brace, token_stream!(
group!(Delimiter::Brace, release_guard("exit_protected")), group!(Delimiter::Brace, token_stream!(
punct!(':', Spacing::Joint),
punct!(':', Spacing::Alone),
ident!("qadapt"),
punct!(':', Spacing::Joint),
punct!(':', Spacing::Alone),
ident!("exit_protected"),
group!(Delimiter::Parenthesis)
)),
ident!("__ret__") ident!("__ret__")
)) ))
)) ))
@ -129,7 +116,18 @@ fn escape_return(ts: TokenStream) -> TokenStream {
vec![group!(Delimiter::Brace, escape_return(g.stream()))] vec![group!(Delimiter::Brace, escape_return(g.stream()))]
} }
TokenTree::Ident(ref i) if i.to_string() == "return" && !in_closure => vec![ TokenTree::Ident(ref i) if i.to_string() == "return" && !in_closure => vec![
group!(Delimiter::Brace, release_guard("exit_protected")), group!(
Delimiter::Brace,
token_stream!(
punct!(':', Spacing::Joint),
punct!(':', Spacing::Alone),
ident!("qadapt"),
punct!(':', Spacing::Joint),
punct!(':', Spacing::Alone),
ident!("exit_protected"),
group!(Delimiter::Parenthesis)
)
),
tt.clone(), tt.clone(),
], ],
TokenTree::Punct(ref p) if p.as_char() == '|' => { TokenTree::Punct(ref p) if p.as_char() == '|' => {

View File

@ -39,42 +39,55 @@ pub struct QADAPT;
/// Let QADAPT know that we are now entering a protected region and that /// Let QADAPT know that we are now entering a protected region and that
/// panics should be triggered if allocations/drops happen while we are running. /// panics should be triggered if allocations/drops happen while we are running.
pub fn enter_protected() { pub fn enter_protected() {
if thread::panicking() { #[cfg(debug_assertions)]
return; {
} if thread::panicking() {
return;
}
PROTECTION_LEVEL PROTECTION_LEVEL
.try_with(|v| { .try_with(|v| {
*v.write() += 1; *v.write() += 1;
}) })
.unwrap_or_else(|_e| ()); .unwrap_or_else(|_e| ());
}
} }
/// Let QADAPT know that we are exiting a protected region. Will panic /// Let QADAPT know that we are exiting a protected region. Will panic
/// if we attempt to [`exit_protected`] more times than we [`enter_protected`]. /// if we attempt to [`exit_protected`] more times than we [`enter_protected`].
pub fn exit_protected() { pub fn exit_protected() {
if thread::panicking() { #[cfg(debug_assertions)]
return; {
} if thread::panicking() {
return;
}
PROTECTION_LEVEL PROTECTION_LEVEL
.try_with(|v| { .try_with(|v| {
let val = { *v.read() }; let val = { *v.read() };
match val { match val {
v if v == 0 => panic!("Attempt to exit protected too many times"), v if v == 0 => panic!("Attempt to exit protected too many times"),
_ => { _ => {
*v.write() -= 1; *v.write() -= 1;
}
} }
} })
}) .unwrap_or_else(|_e| ());
.unwrap_or_else(|_e| ()); }
} }
static INTERNAL_ALLOCATION: RwLock<usize> = RwLock::new(usize::max_value()); static INTERNAL_ALLOCATION: RwLock<usize> = RwLock::new(usize::max_value());
/// Get the current "protection level" in QADAPT: calls to enter_protected() - exit_protected() /// Get the current "protection level" in QADAPT: calls to enter_protected() - exit_protected()
pub fn protection_level() -> usize { pub fn protection_level() -> usize {
PROTECTION_LEVEL.try_with(|v| *v.read()).unwrap_or(0) #[cfg(debug_assertions)]
{
PROTECTION_LEVEL.try_with(|v| *v.read()).unwrap_or(0)
}
#[cfg(not(debug_assertions))]
{
0
}
} }
fn claim_internal_alloc() { fn claim_internal_alloc() {

View File

@ -17,7 +17,7 @@ fn test_copy() {
} }
#[test] #[test]
#[should_panic] #[cfg_attr(debug_assertions, should_panic)]
fn test_allocate() { fn test_allocate() {
enter_protected(); enter_protected();
let _x = Box::new(12); let _x = Box::new(12);
@ -90,7 +90,7 @@ fn vec_with_one() {
} }
#[test] #[test]
#[should_panic] #[cfg_attr(debug_assertions, should_panic)]
fn exit_too_often() { fn exit_too_often() {
enter_protected(); enter_protected();
exit_protected(); exit_protected();
@ -98,7 +98,7 @@ fn exit_too_often() {
} }
#[test] #[test]
#[should_panic] #[cfg_attr(debug_assertions, should_panic)]
fn intentional_drop() { fn intentional_drop() {
let v: Vec<()> = Vec::new(); let v: Vec<()> = Vec::new();
let v = Box::new(v); let v = Box::new(v);

View File

@ -9,11 +9,6 @@ static Q: QADAPT = QADAPT;
#[allocate_panic] #[allocate_panic]
fn no_allocate() { fn no_allocate() {
#[cfg(not(release))]
{
let _v = 0;
}
assert_eq!(::qadapt::protection_level(), 1);
let _v: Vec<()> = Vec::with_capacity(0); let _v: Vec<()> = Vec::with_capacity(0);
} }
@ -149,3 +144,16 @@ fn example_closure() {
fn macro_closure() { fn macro_closure() {
example_closure() example_closure()
} }
#[test]
#[allocate_panic]
fn macro_release_safe() {
#[cfg(debug_assertions)]
{
assert_eq!(1, ::qadapt::protection_level());
}
#[cfg(not(debug_assertions))]
{
assert_eq!(0, ::qadapt::protection_level());
}
}