Skip to content

Commit 1d5e4c3

Browse files
authored
Merge pull request #23 from alecmocatta/static-var-fix
Fix static variables used by reference in closures
2 parents fdd6057 + 78bedc4 commit 1d5e4c3

File tree

6 files changed

+66
-36
lines changed

6 files changed

+66
-36
lines changed

Cargo.toml

+3-3
Original file line numberDiff line numberDiff line change
@@ -2,7 +2,7 @@
22

33
[package]
44
name = "serde_closure"
5-
version = "0.2.8"
5+
version = "0.2.9"
66
license = "MIT OR Apache-2.0"
77
authors = ["Alec Mocatta <[email protected]>"]
88
categories = ["development-tools","encoding","rust-patterns","network-programming"]
@@ -14,7 +14,7 @@ This library provides macros that wrap closures to make them serializable and de
1414
"""
1515
repository = "https://github.com/alecmocatta/serde_closure"
1616
homepage = "https://github.com/alecmocatta/serde_closure"
17-
documentation = "https://docs.rs/serde_closure/0.2.8"
17+
documentation = "https://docs.rs/serde_closure/0.2.9"
1818
readme = "README.md"
1919
edition = "2018"
2020

@@ -23,7 +23,7 @@ azure-devops = { project = "alecmocatta/serde_closure", pipeline = "tests" }
2323
maintenance = { status = "actively-developed" }
2424

2525
[dependencies]
26-
serde_closure_derive = { version = "=0.2.8", path = "serde_closure_derive" }
26+
serde_closure_derive = { version = "=0.2.9", path = "serde_closure_derive" }
2727
serde = { version = "1.0", features = ["derive"] }
2828
proc-macro-hack = "0.5"
2929

README.md

+4-4
Original file line numberDiff line numberDiff line change
@@ -4,7 +4,7 @@
44
[![MIT / Apache 2.0 licensed](https://img.shields.io/crates/l/serde_closure.svg?maxAge=2592000)](#License)
55
[![Build Status](https://dev.azure.com/alecmocatta/serde_closure/_apis/build/status/tests?branchName=master)](https://dev.azure.com/alecmocatta/serde_closure/_build/latest?branchName=master)
66

7-
[Docs](https://docs.rs/serde_closure/0.2.8)
7+
[Docs](https://docs.rs/serde_closure/0.2.9)
88

99
Serializable and debuggable closures.
1010

@@ -30,9 +30,9 @@ requires nightly Rust for the `unboxed_closures` and `fn_traits` features (rust
3030
issue [#29625](https://github.com/rust-lang/rust/issues/29625)).
3131

3232
* There are three macros,
33-
[`FnOnce`](https://docs.rs/serde_closure/0.2.8/serde_closure/macro.FnOnce.html),
34-
[`FnMut`](https://docs.rs/serde_closure/0.2.8/serde_closure/macro.FnMut.html)
35-
and [`Fn`](https://docs.rs/serde_closure/0.2.8/serde_closure/macro.Fn.html),
33+
[`FnOnce`](https://docs.rs/serde_closure/0.2.9/serde_closure/macro.FnOnce.html),
34+
[`FnMut`](https://docs.rs/serde_closure/0.2.9/serde_closure/macro.FnMut.html)
35+
and [`Fn`](https://docs.rs/serde_closure/0.2.9/serde_closure/macro.Fn.html),
3636
corresponding to the three types of Rust closure.
3737
* Wrap your closure with one of the macros and it will now implement `Copy`,
3838
`Clone`, `PartialEq`, `Eq`, `Hash`, `PartialOrd`, `Ord`, `Serialize`,

serde_closure_derive/Cargo.toml

+2-2
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
[package]
22
name = "serde_closure_derive"
3-
version = "0.2.8"
3+
version = "0.2.9"
44
license = "MIT OR Apache-2.0"
55
authors = ["Alec Mocatta <[email protected]>"]
66
categories = ["development-tools","encoding","rust-patterns","network-programming"]
@@ -14,7 +14,7 @@ See https://crates.io/crates/serde_closure for documentation.
1414
"""
1515
repository = "https://github.com/alecmocatta/serde_closure"
1616
homepage = "https://github.com/alecmocatta/serde_closure"
17-
documentation = "https://docs.rs/serde_closure/0.2.8"
17+
documentation = "https://docs.rs/serde_closure/0.2.9"
1818
edition = "2018"
1919

2020
[badges]

serde_closure_derive/src/lib.rs

+47-26
Original file line numberDiff line numberDiff line change
@@ -9,18 +9,18 @@
99
//! See [`serde_closure`](https://docs.rs/serde_closure/) for
1010
//! documentation.
1111
12-
#![doc(html_root_url = "https://docs.rs/serde_closure_derive/0.2.8")]
12+
#![doc(html_root_url = "https://docs.rs/serde_closure_derive/0.2.9")]
1313
#![feature(proc_macro_diagnostic)]
1414
#![allow(non_snake_case)] // due to proc-macro-hack can't apply this directly
1515

1616
extern crate proc_macro;
1717

1818
use proc_macro2::{Span, TokenStream};
1919
use proc_macro_hack::proc_macro_hack;
20-
use quote::{quote, quote_spanned, ToTokens};
21-
use std::{collections::HashSet, iter, iter::successors, str};
20+
use quote::{quote, ToTokens};
21+
use std::{collections::HashSet, iter, iter::successors, mem::take, str};
2222
use syn::{
23-
parse::{Parse, ParseStream}, parse2, spanned::Spanned, token::Bracket, Arm, Error, Expr, ExprArray, ExprAssign, ExprAssignOp, ExprAsync, ExprAwait, ExprBinary, ExprBlock, ExprBox, ExprBreak, ExprCall, ExprCast, ExprClosure, ExprField, ExprForLoop, ExprGroup, ExprIf, ExprIndex, ExprLet, ExprLoop, ExprMacro, ExprMatch, ExprMethodCall, ExprParen, ExprPath, ExprRange, ExprReference, ExprRepeat, ExprReturn, ExprStruct, ExprTry, ExprTryBlock, ExprTuple, ExprType, ExprUnary, ExprUnsafe, ExprWhile, ExprYield, FieldValue, Ident, Local, Member, Pat, PatBox, PatIdent, PatReference, PatSlice, PatTuple, PatTupleStruct, PatType, Path, PathArguments, PathSegment, Stmt, Type, TypeInfer, TypeReference, UnOp
23+
parse::{Parse, ParseStream}, parse2, spanned::Spanned, token::Bracket, Arm, Block, Error, Expr, ExprArray, ExprAssign, ExprAssignOp, ExprAsync, ExprAwait, ExprBinary, ExprBlock, ExprBox, ExprBreak, ExprCall, ExprCast, ExprClosure, ExprField, ExprForLoop, ExprGroup, ExprIf, ExprIndex, ExprLet, ExprLoop, ExprMacro, ExprMatch, ExprMethodCall, ExprParen, ExprPath, ExprRange, ExprReference, ExprRepeat, ExprReturn, ExprStruct, ExprTry, ExprTryBlock, ExprTuple, ExprType, ExprUnary, ExprUnsafe, ExprWhile, ExprYield, FieldValue, Ident, Local, Member, Pat, PatBox, PatIdent, PatReference, PatSlice, PatTuple, PatTupleStruct, PatType, Path, PathArguments, PathSegment, Stmt, Type, TypeInfer, TypeReference, UnOp
2424
};
2525

2626
#[proc_macro_hack]
@@ -88,18 +88,33 @@ fn impl_fn_once(closure: Closure, kind: Kind) -> Result<TokenStream, Error> {
8888
let impls_name = Ident::new("__serde_closure_impls", span);
8989

9090
let _ = closure.env;
91-
let closure = closure.closure;
91+
let mut closure = closure.closure;
9292
let source = closure.to_token_stream().to_string();
9393
let capture = closure.capture.is_some();
94+
// Convert closure to use block so any not_env_variables can be asserted.
95+
closure.body = Box::new(match *closure.body {
96+
Expr::Block(block) => Expr::Block(block),
97+
expr => Expr::Block(ExprBlock {
98+
attrs: vec![],
99+
label: None,
100+
block: Block {
101+
brace_token: Default::default(),
102+
stmts: vec![Stmt::Expr(expr)],
103+
},
104+
}),
105+
});
94106
let mut closure = Expr::Closure(closure);
95107
let mut env_variables = HashSet::new();
108+
let mut not_env_variables = HashSet::new();
96109
State::new(
97110
&mut env_variables,
111+
&mut not_env_variables,
98112
kind != Kind::FnOnce,
99113
kind != Kind::FnOnce && !capture,
100114
&env_name,
101115
)
102116
.expr(&mut closure, false);
117+
assert!(not_env_variables.is_empty());
103118
let mut env_variables: Vec<Ident> = env_variables.into_iter().collect();
104119
env_variables.sort();
105120
let env_variables = &env_variables;
@@ -476,17 +491,20 @@ fn pat_to_type(pat: &Pat) -> Type {
476491
struct State<'a> {
477492
variables: HashSet<Ident>,
478493
env_variables: &'a mut HashSet<Ident>,
494+
not_env_variables: &'a mut HashSet<Ident>,
479495
env_struct: bool,
480496
deref: bool,
481497
env_name: &'a Ident,
482498
}
483499
impl<'a> State<'a> {
484500
fn new(
485-
env_variables: &'a mut HashSet<Ident>, env_struct: bool, deref: bool, env_name: &'a Ident,
501+
env_variables: &'a mut HashSet<Ident>, not_env_variables: &'a mut HashSet<Ident>,
502+
env_struct: bool, deref: bool, env_name: &'a Ident,
486503
) -> Self {
487504
Self {
488505
variables: HashSet::new(),
489506
env_variables,
507+
not_env_variables,
490508
env_struct,
491509
deref,
492510
env_name,
@@ -496,6 +514,7 @@ impl<'a> State<'a> {
496514
State {
497515
variables: self.variables.clone(),
498516
env_variables: self.env_variables,
517+
not_env_variables: self.not_env_variables,
499518
env_struct: self.env_struct,
500519
deref: self.deref,
501520
env_name: self.env_name,
@@ -542,21 +561,31 @@ impl<'a> State<'a> {
542561
}
543562
}
544563

545-
fn block(&mut self, stmts: &mut [Stmt]) {
546-
for stmt in stmts {
547-
match stmt {
548-
Stmt::Local(Local { pat, init, .. }) => {
549-
if let Some((_, expr)) = init {
564+
fn block(&mut self, stmts: &mut Vec<Stmt>) {
565+
*stmts = take(stmts)
566+
.into_iter()
567+
.flat_map(|mut stmt| {
568+
match &mut stmt {
569+
Stmt::Local(Local { pat, init, .. }) => {
570+
if let Some((_, expr)) = init {
571+
self.expr(expr, false);
572+
}
573+
self.pat(pat);
574+
}
575+
Stmt::Expr(expr) | Stmt::Semi(expr, _) => {
550576
self.expr(expr, false);
551577
}
552-
self.pat(pat);
578+
Stmt::Item(_) => (),
553579
}
554-
Stmt::Expr(expr) | Stmt::Semi(expr, _) => {
555-
self.expr(expr, false);
580+
let not_env_variables = take(self.not_env_variables).into_iter();
581+
let mut vec = Vec::with_capacity(2);
582+
if not_env_variables.len() != 0 {
583+
vec.push(parse2(quote! { { #(use #not_env_variables;)* } }).unwrap());
556584
}
557-
Stmt::Item(_) => (),
558-
}
559-
}
585+
vec.push(stmt);
586+
vec
587+
})
588+
.collect();
560589
}
561590

562591
fn expr(&mut self, expr: &mut Expr, is_func: bool) {
@@ -734,15 +763,7 @@ impl<'a> State<'a> {
734763
expr: Box::new(a),
735764
});
736765
} else {
737-
let ident = (*ident).clone();
738-
*expr = parse2(quote_spanned! { expr.span() =>
739-
({
740-
use #ident;
741-
fn eq<T>(a: T, b: T) -> T { a }
742-
eq(#expr, #expr)
743-
})
744-
})
745-
.unwrap();
766+
let _ = self.not_env_variables.insert(ident.clone());
746767
}
747768
}
748769
}

src/lib.rs

+1-1
Original file line numberDiff line numberDiff line change
@@ -164,7 +164,7 @@
164164
//! automatically serializable and deserializable with
165165
//! [`serde`](https://github.com/serde-rs/serde).
166166
167-
#![doc(html_root_url = "https://docs.rs/serde_closure/0.2.8")]
167+
#![doc(html_root_url = "https://docs.rs/serde_closure/0.2.9")]
168168
#![feature(unboxed_closures, fn_traits)]
169169
#![warn(
170170
missing_copy_implementations,

tests/test.rs

+9
Original file line numberDiff line numberDiff line change
@@ -459,6 +459,15 @@ fn multiple_async() {
459459
};
460460
}
461461

462+
#[test]
463+
fn static_var() {
464+
static STATIC: String = String::new();
465+
466+
FnMut!(move || {
467+
let a = &STATIC;
468+
});
469+
}
470+
462471
mod no_prelude {
463472
#![no_implicit_prelude]
464473

0 commit comments

Comments
 (0)