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
Cargo.lock
*.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.
/// The code is conditionally compiled so that all QADAPT-related bits
/// 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]
fn protected_body(fn_body: Group) -> TokenTree {
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!("__ret__"),
punct!('=', Spacing::Alone),
@ -110,7 +89,15 @@ fn protected_body(fn_body: Group) -> TokenTree {
))
)),
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__")
))
))
@ -129,7 +116,18 @@ fn escape_return(ts: TokenStream) -> TokenStream {
vec![group!(Delimiter::Brace, escape_return(g.stream()))]
}
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(),
],
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
/// panics should be triggered if allocations/drops happen while we are running.
pub fn enter_protected() {
if thread::panicking() {
return;
}
#[cfg(debug_assertions)]
{
if thread::panicking() {
return;
}
PROTECTION_LEVEL
.try_with(|v| {
*v.write() += 1;
})
.unwrap_or_else(|_e| ());
PROTECTION_LEVEL
.try_with(|v| {
*v.write() += 1;
})
.unwrap_or_else(|_e| ());
}
}
/// Let QADAPT know that we are exiting a protected region. Will panic
/// if we attempt to [`exit_protected`] more times than we [`enter_protected`].
pub fn exit_protected() {
if thread::panicking() {
return;
}
#[cfg(debug_assertions)]
{
if thread::panicking() {
return;
}
PROTECTION_LEVEL
.try_with(|v| {
let val = { *v.read() };
match val {
v if v == 0 => panic!("Attempt to exit protected too many times"),
_ => {
*v.write() -= 1;
PROTECTION_LEVEL
.try_with(|v| {
let val = { *v.read() };
match val {
v if v == 0 => panic!("Attempt to exit protected too many times"),
_ => {
*v.write() -= 1;
}
}
}
})
.unwrap_or_else(|_e| ());
})
.unwrap_or_else(|_e| ());
}
}
static INTERNAL_ALLOCATION: RwLock<usize> = RwLock::new(usize::max_value());
/// Get the current "protection level" in QADAPT: calls to enter_protected() - exit_protected()
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() {

View File

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

View File

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