summaryrefslogtreecommitdiff
path: root/tests/compile_fail
diff options
context:
space:
mode:
authorAlex Orlenko <zxteam@protonmail.com>2019-10-16 14:59:40 +0100
committerAlex Orlenko <zxteam@protonmail.com>2019-11-04 22:23:15 +0000
commit551e4f1f8773bcf5c2dc8f4d872bdbbf0244fea3 (patch)
tree696a0f58ac6d15936612d67807e56c23b8d41d6f /tests/compile_fail
parent6f42a6cca9798fc3effcd13e1b5423ab24e5ae04 (diff)
downloadmlua-551e4f1f8773bcf5c2dc8f4d872bdbbf0244fea3.zip
Add compile_fail tests
Diffstat (limited to 'tests/compile_fail')
-rw-r--r--tests/compile_fail/function_borrow.rs12
-rw-r--r--tests/compile_fail/function_borrow.stderr20
-rw-r--r--tests/compile_fail/lua_norefunwindsafe.rs8
-rw-r--r--tests/compile_fail/lua_norefunwindsafe.stderr43
-rw-r--r--tests/compile_fail/ref_nounwindsafe.rs9
-rw-r--r--tests/compile_fail/ref_nounwindsafe.stderr49
-rw-r--r--tests/compile_fail/scope_callback_capture.rs22
-rw-r--r--tests/compile_fail/scope_callback_capture.stderr45
-rw-r--r--tests/compile_fail/scope_callback_inner.rs19
-rw-r--r--tests/compile_fail/scope_callback_inner.stderr45
-rw-r--r--tests/compile_fail/scope_callback_outer.rs19
-rw-r--r--tests/compile_fail/scope_callback_outer.stderr11
-rw-r--r--tests/compile_fail/scope_invariance.rs23
-rw-r--r--tests/compile_fail/scope_invariance.stderr25
-rw-r--r--tests/compile_fail/scope_mutable_aliasing.rs15
-rw-r--r--tests/compile_fail/scope_mutable_aliasing.stderr9
-rw-r--r--tests/compile_fail/scope_userdata_borrow.rs20
-rw-r--r--tests/compile_fail/scope_userdata_borrow.stderr13
-rw-r--r--tests/compile_fail/userdata_borrow.rs19
-rw-r--r--tests/compile_fail/userdata_borrow.stderr13
20 files changed, 439 insertions, 0 deletions
diff --git a/tests/compile_fail/function_borrow.rs b/tests/compile_fail/function_borrow.rs
new file mode 100644
index 0000000..f64f3b8
--- /dev/null
+++ b/tests/compile_fail/function_borrow.rs
@@ -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)
+ });
+}
diff --git a/tests/compile_fail/function_borrow.stderr b/tests/compile_fail/function_borrow.stderr
new file mode 100644
index 0000000..c1c4d1f
--- /dev/null
+++ b/tests/compile_fail/function_borrow.stderr
@@ -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> {
+ | ^^^^^^^^^^^^^^^^^^^^^^^^^^^
diff --git a/tests/compile_fail/lua_norefunwindsafe.rs b/tests/compile_fail/lua_norefunwindsafe.rs
new file mode 100644
index 0000000..805f61f
--- /dev/null
+++ b/tests/compile_fail/lua_norefunwindsafe.rs
@@ -0,0 +1,8 @@
+use std::panic::catch_unwind;
+
+use mlua::Lua;
+
+fn main() {
+ let lua = Lua::new();
+ catch_unwind(|| lua.create_table().unwrap());
+}
diff --git a/tests/compile_fail/lua_norefunwindsafe.stderr b/tests/compile_fail/lua_norefunwindsafe.stderr
new file mode 100644
index 0000000..5bdd274
--- /dev/null
+++ b/tests/compile_fail/lua_norefunwindsafe.stderr
@@ -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`
diff --git a/tests/compile_fail/ref_nounwindsafe.rs b/tests/compile_fail/ref_nounwindsafe.rs
new file mode 100644
index 0000000..8518c40
--- /dev/null
+++ b/tests/compile_fail/ref_nounwindsafe.rs
@@ -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());
+}
diff --git a/tests/compile_fail/ref_nounwindsafe.stderr b/tests/compile_fail/ref_nounwindsafe.stderr
new file mode 100644
index 0000000..4047f3d
--- /dev/null
+++ b/tests/compile_fail/ref_nounwindsafe.stderr
@@ -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`
diff --git a/tests/compile_fail/scope_callback_capture.rs b/tests/compile_fail/scope_callback_capture.rs
new file mode 100644
index 0000000..93667f0
--- /dev/null
+++ b/tests/compile_fail/scope_callback_capture.rs
@@ -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(())
+ });
+}
diff --git a/tests/compile_fail/scope_callback_capture.stderr b/tests/compile_fail/scope_callback_capture.stderr
new file mode 100644
index 0000000..b23ea95
--- /dev/null
+++ b/tests/compile_fail/scope_callback_capture.stderr
@@ -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 | | });
+ | |______^
diff --git a/tests/compile_fail/scope_callback_inner.rs b/tests/compile_fail/scope_callback_inner.rs
new file mode 100644
index 0000000..56b56ba
--- /dev/null
+++ b/tests/compile_fail/scope_callback_inner.rs
@@ -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(())
+ });
+}
diff --git a/tests/compile_fail/scope_callback_inner.stderr b/tests/compile_fail/scope_callback_inner.stderr
new file mode 100644
index 0000000..077fba4
--- /dev/null
+++ b/tests/compile_fail/scope_callback_inner.stderr
@@ -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 | | });
+ | |______^
diff --git a/tests/compile_fail/scope_callback_outer.rs b/tests/compile_fail/scope_callback_outer.rs
new file mode 100644
index 0000000..57437c9
--- /dev/null
+++ b/tests/compile_fail/scope_callback_outer.rs
@@ -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(())
+ });
+}
diff --git a/tests/compile_fail/scope_callback_outer.stderr b/tests/compile_fail/scope_callback_outer.stderr
new file mode 100644
index 0000000..c68bb4f
--- /dev/null
+++ b/tests/compile_fail/scope_callback_outer.stderr
@@ -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...
diff --git a/tests/compile_fail/scope_invariance.rs b/tests/compile_fail/scope_invariance.rs
new file mode 100644
index 0000000..569ada1
--- /dev/null
+++ b/tests/compile_fail/scope_invariance.rs
@@ -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::<_, ()>(())
+ });
+}
diff --git a/tests/compile_fail/scope_invariance.stderr b/tests/compile_fail/scope_invariance.stderr
new file mode 100644
index 0000000..434eb78
--- /dev/null
+++ b/tests/compile_fail/scope_invariance.stderr
@@ -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 |_, ()| {
+ | ^^^^^^^^^^^^
diff --git a/tests/compile_fail/scope_mutable_aliasing.rs b/tests/compile_fail/scope_mutable_aliasing.rs
new file mode 100644
index 0000000..4d8d2f0
--- /dev/null
+++ b/tests/compile_fail/scope_mutable_aliasing.rs
@@ -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(())
+ });
+}
diff --git a/tests/compile_fail/scope_mutable_aliasing.stderr b/tests/compile_fail/scope_mutable_aliasing.stderr
new file mode 100644
index 0000000..d78f983
--- /dev/null
+++ b/tests/compile_fail/scope_mutable_aliasing.stderr
@@ -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
diff --git a/tests/compile_fail/scope_userdata_borrow.rs b/tests/compile_fail/scope_userdata_borrow.rs
new file mode 100644
index 0000000..b88d1d6
--- /dev/null
+++ b/tests/compile_fail/scope_userdata_borrow.rs
@@ -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(())
+ });
+}
diff --git a/tests/compile_fail/scope_userdata_borrow.stderr b/tests/compile_fail/scope_userdata_borrow.stderr
new file mode 100644
index 0000000..c143c9a
--- /dev/null
+++ b/tests/compile_fail/scope_userdata_borrow.stderr
@@ -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
diff --git a/tests/compile_fail/userdata_borrow.rs b/tests/compile_fail/userdata_borrow.rs
new file mode 100644
index 0000000..26eb3c7
--- /dev/null
+++ b/tests/compile_fail/userdata_borrow.rs
@@ -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(())
+}
diff --git a/tests/compile_fail/userdata_borrow.stderr b/tests/compile_fail/userdata_borrow.stderr
new file mode 100644
index 0000000..7ac9670
--- /dev/null
+++ b/tests/compile_fail/userdata_borrow.stderr
@@ -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