summaryrefslogtreecommitdiff
path: root/tests/src/no_nested_borrows.rs
diff options
context:
space:
mode:
Diffstat (limited to 'tests/src/no_nested_borrows.rs')
-rw-r--r--tests/src/no_nested_borrows.rs491
1 files changed, 491 insertions, 0 deletions
diff --git a/tests/src/no_nested_borrows.rs b/tests/src/no_nested_borrows.rs
new file mode 100644
index 00000000..9a7604e6
--- /dev/null
+++ b/tests/src/no_nested_borrows.rs
@@ -0,0 +1,491 @@
+//! This module doesn't contain **functions which use nested borrows in their
+//! signatures**, and doesn't contain functions with loops.
+
+pub struct Pair<T1, T2> {
+ pub x: T1,
+ pub y: T2,
+}
+
+pub enum List<T> {
+ Cons(T, Box<List<T>>),
+ Nil,
+}
+
+/// Sometimes, enumerations with one variant are not treated
+/// the same way as the other variants (for example, downcasts
+/// are not always introduced).
+/// A downcast is the cast of an enum to a specific variant, like
+/// in the left value of:
+/// `((_0 as Right).0: T2) = move _1;`
+pub enum One<T1> {
+ One(T1),
+}
+
+/// Truely degenerate case
+/// Instantiations of this are encoded as constant values by rust.
+pub enum EmptyEnum {
+ Empty,
+}
+
+/// Enumeration (several variants with no parameters)
+/// Those are not encoded as constant values.
+pub enum Enum {
+ Variant1,
+ Variant2,
+}
+
+/// Degenerate struct
+/// Instanciations of this are encoded as constant values by rust.
+pub struct EmptyStruct {}
+
+pub enum Sum<T1, T2> {
+ Left(T1),
+ Right(T2),
+}
+
+pub fn cast_u32_to_i32(x: u32) -> i32 {
+ x as i32
+}
+
+pub fn cast_bool_to_i32(x: bool) -> i32 {
+ x as i32
+}
+
+#[allow(clippy::unnecessary_cast)]
+pub fn cast_bool_to_bool(x: bool) -> bool {
+ x as bool
+}
+
+#[allow(unused_variables)]
+pub fn test2() {
+ let x: u32 = 23;
+ let y: u32 = 44;
+ let z = x + y;
+ let p: Pair<u32, u32> = Pair { x, y: z };
+ let s: Sum<u32, bool> = Sum::Right(true);
+ let o: One<u64> = One::One(3);
+ let e0 = EmptyEnum::Empty;
+ let e1 = e0;
+ let enum0 = Enum::Variant1;
+}
+
+pub fn get_max(x: u32, y: u32) -> u32 {
+ if x >= y {
+ x
+ } else {
+ y
+ }
+}
+
+pub fn test3() {
+ let x = get_max(4, 3);
+ let y = get_max(10, 11);
+ let z = x + y;
+ assert!(z == 15);
+}
+
+pub fn test_neg1() {
+ let x: i32 = 3;
+ let y = -x;
+ assert!(y == -3);
+}
+
+/// Testing nested references.
+pub fn refs_test1() {
+ let mut x = 0;
+ let mut px = &mut x;
+ let ppx = &mut px;
+ **ppx = 1;
+ // The interesting thing happening here is that the borrow of x is inside
+ // the borrow of px: ending the borrow of x requires ending the borrow of
+ // px first.
+ assert!(x == 1);
+}
+
+pub fn refs_test2() {
+ let mut x = 0;
+ let mut y = 1;
+ let mut px = &mut x;
+ let py = &mut y;
+ let ppx = &mut px;
+ *ppx = py;
+ **ppx = 2;
+ assert!(*px == 2);
+ assert!(x == 0);
+ assert!(*py == 2);
+ assert!(y == 2);
+}
+
+/// Box creation
+#[allow(unused_variables)]
+pub fn test_list1() {
+ let l: List<i32> = List::Cons(0, Box::new(List::Nil));
+}
+
+/// Box deref
+pub fn test_box1() {
+ use std::ops::Deref;
+ use std::ops::DerefMut;
+ let mut b: Box<i32> = Box::new(0);
+ let x = b.deref_mut();
+ *x = 1;
+ let x = b.deref();
+ assert!(*x == 1);
+}
+
+pub fn copy_int(x: i32) -> i32 {
+ x
+}
+
+/// Just checking the parameters given to unreachable
+/// Rk.: the input parameter prevents using the function as a unit test.
+pub fn test_unreachable(b: bool) {
+ if b {
+ unreachable!();
+ }
+}
+
+/// Just checking the parameters given to panic
+/// Rk.: the input parameter prevents using the function as a unit test.
+pub fn test_panic(b: bool) {
+ if b {
+ panic!("Panicked!");
+ }
+}
+
+// Just testing that shared loans are correctly handled
+pub fn test_copy_int() {
+ let x = 0;
+ let px = &x;
+ let y = copy_int(x);
+ assert!(*px == y);
+}
+
+pub fn is_cons<T>(l: &List<T>) -> bool {
+ match l {
+ List::Cons(_, _) => true,
+ List::Nil => false,
+ }
+}
+
+pub fn test_is_cons() {
+ let l: List<i32> = List::Cons(0, Box::new(List::Nil));
+
+ assert!(is_cons(&l));
+}
+
+pub fn split_list<T>(l: List<T>) -> (T, List<T>) {
+ match l {
+ List::Cons(hd, tl) => (hd, *tl),
+ _ => panic!(),
+ }
+}
+
+#[allow(unused_variables)]
+pub fn test_split_list() {
+ let l: List<i32> = List::Cons(0, Box::new(List::Nil));
+
+ let (hd, tl) = split_list(l);
+ assert!(hd == 0);
+}
+
+pub fn choose<'a, T>(b: bool, x: &'a mut T, y: &'a mut T) -> &'a mut T {
+ if b {
+ x
+ } else {
+ y
+ }
+}
+
+pub fn choose_test() {
+ let mut x = 0;
+ let mut y = 0;
+ let z = choose(true, &mut x, &mut y);
+ *z += 1;
+ assert!(*z == 1);
+ // drop(z)
+ assert!(x == 1);
+ assert!(y == 0);
+}
+
+/// Test with a char literal - testing serialization
+pub fn test_char() -> char {
+ 'a'
+}
+
+/// Mutually recursive types
+pub enum Tree<T> {
+ Leaf(T),
+ Node(T, NodeElem<T>, Box<Tree<T>>),
+}
+
+pub enum NodeElem<T> {
+ Cons(Box<Tree<T>>, Box<NodeElem<T>>),
+ Nil,
+}
+
+/*
+// TODO: those definitions requires semantic termination (breaks the Coq backend
+// because we don't use fuel in this case).
+
+/// Mutually recursive functions
+pub fn even(x: u32) -> bool {
+ if x == 0 {
+ true
+ } else {
+ odd(x - 1)
+ }
+}
+
+pub fn odd(x: u32) -> bool {
+ if x == 0 {
+ false
+ } else {
+ even(x - 1)
+ }
+}
+
+pub fn test_even_odd() {
+ assert!(even(0));
+ assert!(even(4));
+ assert!(odd(1));
+ assert!(odd(5));
+}
+*/
+
+#[allow(clippy::needless_lifetimes)]
+pub fn list_length<'a, T>(l: &'a List<T>) -> u32 {
+ match l {
+ List::Nil => 0,
+ List::Cons(_, l1) => 1 + list_length(l1),
+ }
+}
+
+#[allow(clippy::needless_lifetimes)]
+pub fn list_nth_shared<'a, T>(l: &'a List<T>, i: u32) -> &'a T {
+ match l {
+ List::Nil => {
+ panic!()
+ }
+ List::Cons(x, tl) => {
+ if i == 0 {
+ x
+ } else {
+ list_nth_shared(tl, i - 1)
+ }
+ }
+ }
+}
+
+#[allow(clippy::needless_lifetimes)]
+pub fn list_nth_mut<'a, T>(l: &'a mut List<T>, i: u32) -> &'a mut T {
+ match l {
+ List::Nil => {
+ panic!()
+ }
+ List::Cons(x, tl) => {
+ if i == 0 {
+ x
+ } else {
+ list_nth_mut(tl, i - 1)
+ }
+ }
+ }
+}
+
+/// In-place list reversal - auxiliary function
+pub fn list_rev_aux<T>(li: List<T>, mut lo: List<T>) -> List<T> {
+ match li {
+ List::Nil => lo,
+ List::Cons(hd, mut tl) => {
+ let next = *tl;
+ *tl = lo;
+ lo = List::Cons(hd, tl);
+ list_rev_aux(next, lo)
+ }
+ }
+}
+
+/// In-place list reversal
+#[allow(clippy::needless_lifetimes)]
+pub fn list_rev<'a, T>(l: &'a mut List<T>) {
+ let li = std::mem::replace(l, List::Nil);
+ *l = list_rev_aux(li, List::Nil);
+}
+
+pub fn test_list_functions() {
+ let mut ls = List::Cons(
+ 0,
+ Box::new(List::Cons(1, Box::new(List::Cons(2, Box::new(List::Nil))))),
+ );
+ assert!(list_length(&ls) == 3);
+ assert!(*list_nth_shared(&ls, 0) == 0);
+ assert!(*list_nth_shared(&ls, 1) == 1);
+ assert!(*list_nth_shared(&ls, 2) == 2);
+ let x = list_nth_mut(&mut ls, 1);
+ *x = 3;
+ assert!(*list_nth_shared(&ls, 0) == 0);
+ assert!(*list_nth_shared(&ls, 1) == 3); // Updated
+ assert!(*list_nth_shared(&ls, 2) == 2);
+}
+
+pub fn id_mut_pair1<'a, T1, T2>(x: &'a mut T1, y: &'a mut T2) -> (&'a mut T1, &'a mut T2) {
+ (x, y)
+}
+
+pub fn id_mut_pair2<'a, T1, T2>(p: (&'a mut T1, &'a mut T2)) -> (&'a mut T1, &'a mut T2) {
+ p
+}
+
+pub fn id_mut_pair3<'a, 'b, T1, T2>(x: &'a mut T1, y: &'b mut T2) -> (&'a mut T1, &'b mut T2) {
+ (x, y)
+}
+
+pub fn id_mut_pair4<'a, 'b, T1, T2>(p: (&'a mut T1, &'b mut T2)) -> (&'a mut T1, &'b mut T2) {
+ p
+}
+
+/// Testing constants (some constants are hard to retrieve from MIR, because
+/// they are compiled to very low values).
+/// We resort to the following structure to make rustc generate constants...
+pub struct StructWithTuple<T1, T2> {
+ p: (T1, T2),
+}
+
+pub fn new_tuple1() -> StructWithTuple<u32, u32> {
+ StructWithTuple { p: (1, 2) }
+}
+
+pub fn new_tuple2() -> StructWithTuple<i16, i16> {
+ StructWithTuple { p: (1, 2) }
+}
+
+pub fn new_tuple3() -> StructWithTuple<u64, i64> {
+ StructWithTuple { p: (1, 2) }
+}
+
+/// Similar to [StructWithTuple]
+pub struct StructWithPair<T1, T2> {
+ p: Pair<T1, T2>,
+}
+
+pub fn new_pair1() -> StructWithPair<u32, u32> {
+ // This actually doesn't make rustc generate a constant...
+ // I guess it only happens for tuples.
+ StructWithPair {
+ p: Pair { x: 1, y: 2 },
+ }
+}
+
+pub fn test_constants() {
+ assert!(new_tuple1().p.0 == 1);
+ assert!(new_tuple2().p.0 == 1);
+ assert!(new_tuple3().p.0 == 1);
+ assert!(new_pair1().p.x == 1);
+}
+
+/// This assignment is trickier than it seems
+#[allow(unused_assignments)]
+pub fn test_weird_borrows1() {
+ let mut x = 0;
+ let mut px = &mut x;
+ // Context:
+ // x -> [l0]
+ // px -> &mut l0 (0:i32)
+
+ px = &mut (*px);
+}
+
+pub fn test_mem_replace(px: &mut u32) {
+ let y = std::mem::replace(px, 1);
+ assert!(y == 0);
+ *px = 2;
+}
+
+/// Check that matching on borrowed values works well.
+pub fn test_shared_borrow_bool1(b: bool) -> u32 {
+ // Create a shared borrow of b
+ let _pb = &b;
+ // Match on b
+ if b {
+ 0
+ } else {
+ 1
+ }
+}
+
+/// Check that matching on borrowed values works well.
+/// Testing the concrete execution here.
+pub fn test_shared_borrow_bool2() -> u32 {
+ let b = true;
+ // Create a shared borrow of b
+ let _pb = &b;
+ // Match on b
+ if b {
+ 0
+ } else {
+ 1
+ }
+}
+
+/// Check that matching on borrowed values works well.
+/// In case of enumerations, we need to strip the outer loans before evaluating
+/// the discriminant.
+pub fn test_shared_borrow_enum1(l: List<u32>) -> u32 {
+ // Create a shared borrow of l
+ let _pl = &l;
+ // Match on l - must ignore the shared loan
+ match l {
+ List::Nil => 0,
+ List::Cons(_, _) => 1,
+ }
+}
+
+/// Check that matching on borrowed values works well.
+/// Testing the concrete execution here.
+pub fn test_shared_borrow_enum2() -> u32 {
+ let l: List<u32> = List::Nil;
+ // Create a shared borrow of l
+ let _pl = &l;
+ // Match on l - must ignore the shared loan
+ match l {
+ List::Nil => 0,
+ List::Cons(_, _) => 1,
+ }
+}
+
+pub fn incr(x: &mut u32) {
+ *x += 1;
+}
+
+pub fn call_incr(mut x: u32) -> u32 {
+ incr(&mut x);
+ x
+}
+
+pub fn read_then_incr(x: &mut u32) -> u32 {
+ let r = *x;
+ *x += 1;
+ r
+}
+
+pub struct Tuple<T1, T2>(T1, T2);
+
+pub fn use_tuple_struct(x: &mut Tuple<u32, u32>) {
+ x.0 = 1;
+}
+
+pub fn create_tuple_struct(x: u32, y: u64) -> Tuple<u32, u64> {
+ Tuple(x, y)
+}
+
+/// Structure with one field
+pub struct IdType<T>(T);
+
+pub fn use_id_type<T>(x: IdType<T>) -> T {
+ x.0
+}
+
+pub fn create_id_type<T>(x: T) -> IdType<T> {
+ IdType(x)
+}