Add compile_fail tests

This commit is contained in:
Alex Orlenko 2019-10-16 14:59:40 +01:00
parent 6f42a6cca9
commit 551e4f1f87
22 changed files with 446 additions and 1 deletions

View File

@ -7,7 +7,7 @@ description = "High level bindings to Lua 5.1 / LuaJIT / Lua 5.3"
repository = "https://github.com/khvzak/mlua"
documentation = "https://docs.rs/mlua"
readme = "README.md"
keywords = ["lua"]
keywords = ["lua", "luajit"]
license = "MIT"
# [badges]
@ -34,6 +34,7 @@ pkg-config = { version = "0.3.11" }
[dev-dependencies]
rustyline = "5.0"
criterion = "0.2.0"
trybuild = "1.0"
[[bench]]
name = "benchmark"

5
tests/compile_fail.rs Normal file
View File

@ -0,0 +1,5 @@
#[test]
fn test_compile_fail() {
let t = trybuild::TestCases::new();
t.compile_fail("tests/compile_fail/*.rs");
}

View File

@ -0,0 +1,12 @@
use mlua::{Lua, Result};
struct Test(i32);
fn main() {
let test = Test(0);
let lua = Lua::new();
let _ = lua.create_function(|_, ()| -> Result<i32> {
Ok(test.0)
});
}

View File

@ -0,0 +1,20 @@
error[E0373]: closure may outlive the current function, but it borrows `test`, which is owned by the current function
--> $DIR/function_borrow.rs:9:33
|
9 | let _ = lua.create_function(|_, ()| -> Result<i32> {
| ^^^^^^^^^^^^^^^^^^^^^^ may outlive borrowed value `test`
10 | Ok(test.0)
| ---- `test` is borrowed here
|
note: function requires argument type to outlive `'static`
--> $DIR/function_borrow.rs:9:13
|
9 | let _ = lua.create_function(|_, ()| -> Result<i32> {
| _____________^
10 | | Ok(test.0)
11 | | });
| |______^
help: to force the closure to take ownership of `test` (and any other referenced variables), use the `move` keyword
|
9 | let _ = lua.create_function(move |_, ()| -> Result<i32> {
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^

View File

@ -0,0 +1,8 @@
use std::panic::catch_unwind;
use mlua::Lua;
fn main() {
let lua = Lua::new();
catch_unwind(|| lua.create_table().unwrap());
}

View File

@ -0,0 +1,43 @@
error[E0277]: the type `std::cell::UnsafeCell<()>` may contain interior mutability and a reference may not be safely transferrable across a catch_unwind boundary
--> $DIR/lua_norefunwindsafe.rs:7:5
|
7 | catch_unwind(|| lua.create_table().unwrap());
| ^^^^^^^^^^^^ `std::cell::UnsafeCell<()>` may contain interior mutability and a reference may not be safely transferrable across a catch_unwind boundary
|
= help: within `mlua::lua::Lua`, the trait `std::panic::RefUnwindSafe` is not implemented for `std::cell::UnsafeCell<()>`
= note: required because it appears within the type `std::marker::PhantomData<std::cell::UnsafeCell<()>>`
= note: required because it appears within the type `mlua::lua::Lua`
= note: required because of the requirements on the impl of `std::panic::UnwindSafe` for `&mlua::lua::Lua`
= note: required because it appears within the type `[closure@$DIR/tests/compile_fail/lua_norefunwindsafe.rs:7:18: 7:48 lua:&mlua::lua::Lua]`
= note: required by `std::panic::catch_unwind`
error[E0277]: the type `std::cell::UnsafeCell<mlua::lua::ExtraData>` may contain interior mutability and a reference may not be safely transferrable across a catch_unwind boundary
--> $DIR/lua_norefunwindsafe.rs:7:5
|
7 | catch_unwind(|| lua.create_table().unwrap());
| ^^^^^^^^^^^^ `std::cell::UnsafeCell<mlua::lua::ExtraData>` may contain interior mutability and a reference may not be safely transferrable across a catch_unwind boundary
|
= help: within `mlua::lua::Lua`, the trait `std::panic::RefUnwindSafe` is not implemented for `std::cell::UnsafeCell<mlua::lua::ExtraData>`
= note: required because it appears within the type `std::cell::RefCell<mlua::lua::ExtraData>`
= note: required because it appears within the type `std::marker::PhantomData<std::cell::RefCell<mlua::lua::ExtraData>>`
= note: required because it appears within the type `std::sync::Arc<std::cell::RefCell<mlua::lua::ExtraData>>`
= note: required because it appears within the type `mlua::lua::Lua`
= note: required because of the requirements on the impl of `std::panic::UnwindSafe` for `&mlua::lua::Lua`
= note: required because it appears within the type `[closure@$DIR/tests/compile_fail/lua_norefunwindsafe.rs:7:18: 7:48 lua:&mlua::lua::Lua]`
= note: required by `std::panic::catch_unwind`
error[E0277]: the type `std::cell::UnsafeCell<isize>` may contain interior mutability and a reference may not be safely transferrable across a catch_unwind boundary
--> $DIR/lua_norefunwindsafe.rs:7:5
|
7 | catch_unwind(|| lua.create_table().unwrap());
| ^^^^^^^^^^^^ `std::cell::UnsafeCell<isize>` may contain interior mutability and a reference may not be safely transferrable across a catch_unwind boundary
|
= help: within `mlua::lua::Lua`, the trait `std::panic::RefUnwindSafe` is not implemented for `std::cell::UnsafeCell<isize>`
= note: required because it appears within the type `std::cell::Cell<isize>`
= note: required because it appears within the type `std::cell::RefCell<mlua::lua::ExtraData>`
= note: required because it appears within the type `std::marker::PhantomData<std::cell::RefCell<mlua::lua::ExtraData>>`
= note: required because it appears within the type `std::sync::Arc<std::cell::RefCell<mlua::lua::ExtraData>>`
= note: required because it appears within the type `mlua::lua::Lua`
= note: required because of the requirements on the impl of `std::panic::UnwindSafe` for `&mlua::lua::Lua`
= note: required because it appears within the type `[closure@$DIR/tests/compile_fail/lua_norefunwindsafe.rs:7:18: 7:48 lua:&mlua::lua::Lua]`
= note: required by `std::panic::catch_unwind`

View File

@ -0,0 +1,9 @@
use std::panic::catch_unwind;
use mlua::Lua;
fn main() {
let lua = Lua::new();
let table = lua.create_table().unwrap();
catch_unwind(move || table.set("a", "b").unwrap());
}

View File

@ -0,0 +1,49 @@
error[E0277]: the type `std::cell::UnsafeCell<()>` may contain interior mutability and a reference may not be safely transferrable across a catch_unwind boundary
--> $DIR/ref_nounwindsafe.rs:8:5
|
8 | catch_unwind(move || table.set("a", "b").unwrap());
| ^^^^^^^^^^^^ `std::cell::UnsafeCell<()>` may contain interior mutability and a reference may not be safely transferrable across a catch_unwind boundary
|
= help: within `mlua::lua::Lua`, the trait `std::panic::RefUnwindSafe` is not implemented for `std::cell::UnsafeCell<()>`
= note: required because it appears within the type `std::marker::PhantomData<std::cell::UnsafeCell<()>>`
= note: required because it appears within the type `mlua::lua::Lua`
= note: required because of the requirements on the impl of `std::panic::UnwindSafe` for `&mlua::lua::Lua`
= note: required because it appears within the type `mlua::types::LuaRef<'_>`
= note: required because it appears within the type `mlua::table::Table<'_>`
= note: required because it appears within the type `[closure@$DIR/tests/compile_fail/ref_nounwindsafe.rs:8:18: 8:54 table:mlua::table::Table<'_>]`
= note: required by `std::panic::catch_unwind`
error[E0277]: the type `std::cell::UnsafeCell<mlua::lua::ExtraData>` may contain interior mutability and a reference may not be safely transferrable across a catch_unwind boundary
--> $DIR/ref_nounwindsafe.rs:8:5
|
8 | catch_unwind(move || table.set("a", "b").unwrap());
| ^^^^^^^^^^^^ `std::cell::UnsafeCell<mlua::lua::ExtraData>` may contain interior mutability and a reference may not be safely transferrable across a catch_unwind boundary
|
= help: within `mlua::lua::Lua`, the trait `std::panic::RefUnwindSafe` is not implemented for `std::cell::UnsafeCell<mlua::lua::ExtraData>`
= note: required because it appears within the type `std::cell::RefCell<mlua::lua::ExtraData>`
= note: required because it appears within the type `std::marker::PhantomData<std::cell::RefCell<mlua::lua::ExtraData>>`
= note: required because it appears within the type `std::sync::Arc<std::cell::RefCell<mlua::lua::ExtraData>>`
= note: required because it appears within the type `mlua::lua::Lua`
= note: required because of the requirements on the impl of `std::panic::UnwindSafe` for `&mlua::lua::Lua`
= note: required because it appears within the type `mlua::types::LuaRef<'_>`
= note: required because it appears within the type `mlua::table::Table<'_>`
= note: required because it appears within the type `[closure@$DIR/tests/compile_fail/ref_nounwindsafe.rs:8:18: 8:54 table:mlua::table::Table<'_>]`
= note: required by `std::panic::catch_unwind`
error[E0277]: the type `std::cell::UnsafeCell<isize>` may contain interior mutability and a reference may not be safely transferrable across a catch_unwind boundary
--> $DIR/ref_nounwindsafe.rs:8:5
|
8 | catch_unwind(move || table.set("a", "b").unwrap());
| ^^^^^^^^^^^^ `std::cell::UnsafeCell<isize>` may contain interior mutability and a reference may not be safely transferrable across a catch_unwind boundary
|
= help: within `mlua::lua::Lua`, the trait `std::panic::RefUnwindSafe` is not implemented for `std::cell::UnsafeCell<isize>`
= note: required because it appears within the type `std::cell::Cell<isize>`
= note: required because it appears within the type `std::cell::RefCell<mlua::lua::ExtraData>`
= note: required because it appears within the type `std::marker::PhantomData<std::cell::RefCell<mlua::lua::ExtraData>>`
= note: required because it appears within the type `std::sync::Arc<std::cell::RefCell<mlua::lua::ExtraData>>`
= note: required because it appears within the type `mlua::lua::Lua`
= note: required because of the requirements on the impl of `std::panic::UnwindSafe` for `&mlua::lua::Lua`
= note: required because it appears within the type `mlua::types::LuaRef<'_>`
= note: required because it appears within the type `mlua::table::Table<'_>`
= note: required because it appears within the type `[closure@$DIR/tests/compile_fail/ref_nounwindsafe.rs:8:18: 8:54 table:mlua::table::Table<'_>]`
= note: required by `std::panic::catch_unwind`

View File

@ -0,0 +1,22 @@
use mlua::{Lua, Table, Result};
struct Test {
field: i32,
}
fn main() {
let lua = Lua::new();
lua.scope(|scope| -> Result<()> {
let mut inner: Option<Table> = None;
let f = scope
.create_function_mut(move |lua, t: Table| {
if let Some(old) = inner.take() {
// Access old callback `Lua`.
}
inner = Some(t);
Ok(())
})?;
f.call::<_, ()>(lua.create_table()?)?;
Ok(())
});
}

View File

@ -0,0 +1,45 @@
error[E0495]: cannot infer an appropriate lifetime for autoref due to conflicting requirements
--> $DIR/scope_callback_capture.rs:12:14
|
12 | .create_function_mut(move |lua, t: Table| {
| ^^^^^^^^^^^^^^^^^^^
|
note: first, the lifetime cannot outlive the anonymous lifetime #2 defined on the body at 9:15...
--> $DIR/scope_callback_capture.rs:9:15
|
9 | lua.scope(|scope| -> Result<()> {
| _______________^
10 | | let mut inner: Option<Table> = None;
11 | | let f = scope
12 | | .create_function_mut(move |lua, t: Table| {
... |
20 | | Ok(())
21 | | });
| |_____^
note: ...so that reference does not outlive borrowed content
--> $DIR/scope_callback_capture.rs:11:17
|
11 | let f = scope
| ^^^^^
note: but, the lifetime must be valid for the method call at 9:5...
--> $DIR/scope_callback_capture.rs:9:5
|
9 | / lua.scope(|scope| -> Result<()> {
10 | | let mut inner: Option<Table> = None;
11 | | let f = scope
12 | | .create_function_mut(move |lua, t: Table| {
... |
20 | | Ok(())
21 | | });
| |______^
note: ...so that a type/lifetime parameter is in scope here
--> $DIR/scope_callback_capture.rs:9:5
|
9 | / lua.scope(|scope| -> Result<()> {
10 | | let mut inner: Option<Table> = None;
11 | | let f = scope
12 | | .create_function_mut(move |lua, t: Table| {
... |
20 | | Ok(())
21 | | });
| |______^

View File

@ -0,0 +1,19 @@
use mlua::{Lua, Table, Result};
struct Test {
field: i32,
}
fn main() {
let lua = Lua::new();
lua.scope(|scope| -> Result<()> {
let mut inner: Option<Table> = None;
let f = scope
.create_function_mut(|_, t: Table| {
inner = Some(t);
Ok(())
})?;
f.call::<_, ()>(lua.create_table()?)?;
Ok(())
});
}

View File

@ -0,0 +1,45 @@
error[E0495]: cannot infer an appropriate lifetime for autoref due to conflicting requirements
--> $DIR/scope_callback_inner.rs:12:14
|
12 | .create_function_mut(|_, t: Table| {
| ^^^^^^^^^^^^^^^^^^^
|
note: first, the lifetime cannot outlive the anonymous lifetime #2 defined on the body at 9:15...
--> $DIR/scope_callback_inner.rs:9:15
|
9 | lua.scope(|scope| -> Result<()> {
| _______________^
10 | | let mut inner: Option<Table> = None;
11 | | let f = scope
12 | | .create_function_mut(|_, t: Table| {
... |
17 | | Ok(())
18 | | });
| |_____^
note: ...so that reference does not outlive borrowed content
--> $DIR/scope_callback_inner.rs:11:17
|
11 | let f = scope
| ^^^^^
note: but, the lifetime must be valid for the method call at 9:5...
--> $DIR/scope_callback_inner.rs:9:5
|
9 | / lua.scope(|scope| -> Result<()> {
10 | | let mut inner: Option<Table> = None;
11 | | let f = scope
12 | | .create_function_mut(|_, t: Table| {
... |
17 | | Ok(())
18 | | });
| |______^
note: ...so that a type/lifetime parameter is in scope here
--> $DIR/scope_callback_inner.rs:9:5
|
9 | / lua.scope(|scope| -> Result<()> {
10 | | let mut inner: Option<Table> = None;
11 | | let f = scope
12 | | .create_function_mut(|_, t: Table| {
... |
17 | | Ok(())
18 | | });
| |______^

View File

@ -0,0 +1,19 @@
use mlua::{Lua, Table, Result};
struct Test {
field: i32,
}
fn main() {
let lua = Lua::new();
let mut outer: Option<Table> = None;
lua.scope(|scope| -> Result<()> {
let f = scope
.create_function_mut(|_, t: Table| {
outer = Some(t);
Ok(())
})?;
f.call::<_, ()>(lua.create_table()?)?;
Ok(())
});
}

View File

@ -0,0 +1,11 @@
error: borrowed data cannot be stored outside of its closure
--> $DIR/scope_callback_outer.rs:11:17
|
9 | let mut outer: Option<Table> = None;
| --------- ...so that variable is valid at time of its declaration
10 | lua.scope(|scope| -> Result<()> {
| --------------------- borrowed data cannot outlive this closure
11 | let f = scope
| ^^^^^ cannot be stored outside of its closure
12 | .create_function_mut(|_, t: Table| {
| ------------------- cannot infer an appropriate lifetime...

View File

@ -0,0 +1,23 @@
use mlua::{Lua, Result};
struct Test {
field: i32,
}
fn main() {
let lua = Lua::new();
lua.scope(|scope| -> Result<()> {
let f = {
let mut test = Test { field: 0 };
scope
.create_function_mut(|_, ()| {
test.field = 42;
//~^ error: `test` does not live long enough
Ok(())
})?
};
f.call::<_, ()>(())
});
}

View File

@ -0,0 +1,25 @@
error[E0373]: closure may outlive the current function, but it borrows `test`, which is owned by the current function
--> $DIR/scope_invariance.rs:14:38
|
9 | lua.scope(|scope| -> Result<()> {
| ----- has type `&mlua::scope::Scope<'_, '1>`
...
14 | .create_function_mut(|_, ()| {
| ^^^^^^^ may outlive borrowed value `test`
15 | test.field = 42;
| ---- `test` is borrowed here
|
note: function requires argument type to outlive `'1`
--> $DIR/scope_invariance.rs:13:13
|
13 | / scope
14 | | .create_function_mut(|_, ()| {
15 | | test.field = 42;
16 | | //~^ error: `test` does not live long enough
17 | | Ok(())
18 | | })?
| |__________________^
help: to force the closure to take ownership of `test` (and any other referenced variables), use the `move` keyword
|
14 | .create_function_mut(move |_, ()| {
| ^^^^^^^^^^^^

View File

@ -0,0 +1,15 @@
use mlua::{Lua, UserData, Result};
struct MyUserData<'a>(&'a mut i32);
impl<'a> UserData for MyUserData<'a> {}
fn main() {
let mut i = 1;
let lua = Lua::new();
lua.scope(|scope| -> Result<()> {
let _a = scope.create_nonstatic_userdata(MyUserData(&mut i))?;
let _b = scope.create_nonstatic_userdata(MyUserData(&mut i))?;
Ok(())
});
}

View File

@ -0,0 +1,9 @@
error[E0499]: cannot borrow `i` as mutable more than once at a time
--> $DIR/scope_mutable_aliasing.rs:12:61
|
11 | let _a = scope.create_nonstatic_userdata(MyUserData(&mut i))?;
| ------ first mutable borrow occurs here
12 | let _b = scope.create_nonstatic_userdata(MyUserData(&mut i))?;
| ------------------------- ^^^^^^ second mutable borrow occurs here
| |
| first borrow later used by call

View File

@ -0,0 +1,20 @@
use mlua::{Lua, UserData, Result};
struct MyUserData<'a>(&'a i32);
impl<'a> UserData for MyUserData<'a> {}
fn main() {
// Should not allow userdata borrow to outlive lifetime of AnyUserData handle
let igood = 1;
let lua = Lua::new();
lua.scope(|scope| -> Result<()> {
let _ugood = scope.create_nonstatic_userdata(MyUserData(&igood))?;
let _ubad = {
let ibad = 42;
scope.create_nonstatic_userdata(MyUserData(&ibad))?;
};
Ok(())
});
}

View File

@ -0,0 +1,13 @@
error[E0597]: `ibad` does not live long enough
--> $DIR/scope_userdata_borrow.rs:16:56
|
12 | lua.scope(|scope| -> Result<()> {
| ----- has type `&mlua::scope::Scope<'_, '1>`
...
16 | scope.create_nonstatic_userdata(MyUserData(&ibad))?;
| -------------------------------------------^^^^^--
| | |
| | borrowed value does not live long enough
| argument requires that `ibad` is borrowed for `'1`
17 | };
| - `ibad` dropped here while still borrowed

View File

@ -0,0 +1,19 @@
use mlua::{AnyUserData, Lua, Table, UserData, Result};
fn main() -> Result<()> {
let lua = Lua::new();
let globals = lua.globals();
// Should not allow userdata borrow to outlive lifetime of AnyUserData handle
struct MyUserData;
impl UserData for MyUserData {};
let _userdata_ref;
{
let touter = globals.get::<_, Table>("touter")?;
touter.set("userdata", lua.create_userdata(MyUserData)?)?;
let userdata = touter.get::<_, AnyUserData>("userdata")?;
_userdata_ref = userdata.borrow::<MyUserData>();
//~^ error: `userdata` does not live long enough
}
Ok(())
}

View File

@ -0,0 +1,13 @@
error[E0597]: `userdata` does not live long enough
--> $DIR/userdata_borrow.rs:15:25
|
15 | _userdata_ref = userdata.borrow::<MyUserData>();
| ^^^^^^^^ borrowed value does not live long enough
16 | //~^ error: `userdata` does not live long enough
17 | }
| - `userdata` dropped here while still borrowed
18 | Ok(())
19 | }
| - borrow might be used here, when `_userdata_ref` is dropped and runs the destructor for type `std::result::Result<std::cell::Ref<'_, main::MyUserData>, mlua::error::Error>`
|
= note: values in a scope are dropped in the opposite order they are defined