From 08b3a8e4294484adcb8b7ed36e76f49e76c3a5f8 Mon Sep 17 00:00:00 2001 From: "Felix S. Klock II" Date: Fri, 27 Jul 2018 15:52:17 +0200 Subject: [PATCH] Regression tests. --- .../issue-45696-long-live-borrows-in-boxes.rs | 103 ++++++++++++++++ ...-45696-scribble-on-boxed-borrow.ast.stderr | 14 +++ ...96-scribble-on-boxed-borrow.migrate.stderr | 69 +++++++++++ ...-45696-scribble-on-boxed-borrow.nll.stderr | 48 ++++++++ .../issue-45696-scribble-on-boxed-borrow.rs | 110 ++++++++++++++++++ 5 files changed, 344 insertions(+) create mode 100644 src/test/ui/issue-45696-long-live-borrows-in-boxes.rs create mode 100644 src/test/ui/issue-45696-scribble-on-boxed-borrow.ast.stderr create mode 100644 src/test/ui/issue-45696-scribble-on-boxed-borrow.migrate.stderr create mode 100644 src/test/ui/issue-45696-scribble-on-boxed-borrow.nll.stderr create mode 100644 src/test/ui/issue-45696-scribble-on-boxed-borrow.rs diff --git a/src/test/ui/issue-45696-long-live-borrows-in-boxes.rs b/src/test/ui/issue-45696-long-live-borrows-in-boxes.rs new file mode 100644 index 00000000000..e5326bb315e --- /dev/null +++ b/src/test/ui/issue-45696-long-live-borrows-in-boxes.rs @@ -0,0 +1,103 @@ +// Copyright 2018 The Rust Project Developers. See the COPYRIGHT +// file at the top-level directory of this distribution and at +// http://rust-lang.org/COPYRIGHT. +// +// Licensed under the Apache License, Version 2.0 or the MIT license +// , at your +// option. This file may not be copied, modified, or distributed +// except according to those terms. + +// rust-lang/rust#45696: This test is checking that we can return +// mutable borrows owned by boxes even when the boxes are dropped. +// +// We will explicitly test AST-borrowck, NLL, and migration modes; +// thus we will also skip the automated compare-mode=nll. + +// revisions: ast nll migrate +// ignore-compare-mode-nll + +#![cfg_attr(nll, feature(nll))] +//[migrate]compile-flags: -Z borrowck=migrate -Z two-phase-borrows + +// run-pass + +type Boxed<'a, 'b> = Box<(&'a mut u32, &'b mut u32)>; + +fn return_borrow_from_dropped_box<'a>(x: Boxed<'a, '_>) -> &'a mut u32 { + &mut *x.0 +} + +fn return_borrow_from_dropped_tupled_box<'a>(x: (Boxed<'a, '_>, &mut u32)) -> &'a mut u32 { + &mut *(x.0).0 +} + +fn basic_tests() { + let mut x = 2; + let mut y = 3; + let mut z = 4; + *return_borrow_from_dropped_box(Box::new((&mut x, &mut y))) += 10; + assert_eq!((x, y, z), (12, 3, 4)); + *return_borrow_from_dropped_tupled_box((Box::new((&mut x, &mut y)), &mut z)) += 10; + assert_eq!((x, y, z), (22, 3, 4)); +} + +// These scribbling tests have been transcribed from +// issue-45696-scribble-on-boxed-borrow.rs +// +// In the context of that file, these tests are meant to show cases +// that should be *accepted* by the compiler, so here we are actually +// checking that the code we get when they are compiled matches our +// expectations. + +struct Scribble<'a>(&'a mut u32); + +impl<'a> Drop for Scribble<'a> { fn drop(&mut self) { *self.0 = 42; } } + +// this is okay, in both AST-borrowck and NLL: The `Scribble` here *has* +// to strictly outlive `'a` +fn borrowed_scribble<'a>(s: &'a mut Scribble) -> &'a mut u32 { + &mut *s.0 +} + +// this, by analogy to previous case, is also okay. +fn boxed_borrowed_scribble<'a>(s: Box<&'a mut Scribble>) -> &'a mut u32 { + &mut *(*s).0 +} + +// this, by analogy to previous case, is also okay. +fn boxed_boxed_borrowed_scribble<'a>(s: Box>) -> &'a mut u32 { + &mut *(**s).0 +} + +fn scribbling_tests() { + let mut x = 1; + { + let mut long_lived = Scribble(&mut x); + *borrowed_scribble(&mut long_lived) += 10; + assert_eq!(*long_lived.0, 11); + // (Scribble dtor runs here, after `&mut`-borrow above ends) + } + assert_eq!(x, 42); + x = 1; + { + let mut long_lived = Scribble(&mut x); + *boxed_borrowed_scribble(Box::new(&mut long_lived)) += 10; + assert_eq!(*long_lived.0, 11); + // (Scribble dtor runs here, after `&mut`-borrow above ends) + } + assert_eq!(x, 42); + x = 1; + { + let mut long_lived = Scribble(&mut x); + *boxed_boxed_borrowed_scribble(Box::new(Box::new(&mut long_lived))) += 10; + assert_eq!(*long_lived.0, 11); + // (Scribble dtor runs here, after `&mut`-borrow above ends) + } + assert_eq!(x, 42); +} + +fn main() { + basic_tests(); + scribbling_tests(); +} diff --git a/src/test/ui/issue-45696-scribble-on-boxed-borrow.ast.stderr b/src/test/ui/issue-45696-scribble-on-boxed-borrow.ast.stderr new file mode 100644 index 00000000000..6172a5e35a8 --- /dev/null +++ b/src/test/ui/issue-45696-scribble-on-boxed-borrow.ast.stderr @@ -0,0 +1,14 @@ +error: compilation successful + --> $DIR/issue-45696-scribble-on-boxed-borrow.rs:89:1 + | +LL | / fn main() { //[ast]~ ERROR compilation successful +LL | | //[migrate]~^ ERROR compilation successful +LL | | let mut x = 1; +LL | | { +... | +LL | | *boxed_boxed_scribbled(Box::new(Box::new(Scribble(&mut x)))) += 10; +LL | | } + | |_^ + +error: aborting due to previous error + diff --git a/src/test/ui/issue-45696-scribble-on-boxed-borrow.migrate.stderr b/src/test/ui/issue-45696-scribble-on-boxed-borrow.migrate.stderr new file mode 100644 index 00000000000..da0dfac2d18 --- /dev/null +++ b/src/test/ui/issue-45696-scribble-on-boxed-borrow.migrate.stderr @@ -0,0 +1,69 @@ +warning[E0597]: `*s.0` does not live long enough + --> $DIR/issue-45696-scribble-on-boxed-borrow.rs:63:5 + | +LL | &mut *s.0 //[nll]~ ERROR `*s.0` does not live long enough [E0597] + | ^^^^^^^^^ borrowed value does not live long enough +... +LL | } + | - `*s.0` dropped here while still borrowed + | +note: borrowed value must be valid for the lifetime 'a as defined on the function body at 62:14... + --> $DIR/issue-45696-scribble-on-boxed-borrow.rs:62:14 + | +LL | fn scribbled<'a>(s: Scribble<'a>) -> &'a mut u32 { + | ^^ + = warning: This error has been downgraded to a warning for backwards compatibility with previous releases. + It represents potential unsoundness in your code. + This warning will become a hard error in the future. + +warning[E0597]: `*s.0` does not live long enough + --> $DIR/issue-45696-scribble-on-boxed-borrow.rs:73:5 + | +LL | &mut *(*s).0 //[nll]~ ERROR `*s.0` does not live long enough [E0597] + | ^^^^^^^^^^^^ borrowed value does not live long enough +... +LL | } + | - `*s.0` dropped here while still borrowed + | +note: borrowed value must be valid for the lifetime 'a as defined on the function body at 72:20... + --> $DIR/issue-45696-scribble-on-boxed-borrow.rs:72:20 + | +LL | fn boxed_scribbled<'a>(s: Box>) -> &'a mut u32 { + | ^^ + = warning: This error has been downgraded to a warning for backwards compatibility with previous releases. + It represents potential unsoundness in your code. + This warning will become a hard error in the future. + +warning[E0597]: `*s.0` does not live long enough + --> $DIR/issue-45696-scribble-on-boxed-borrow.rs:83:5 + | +LL | &mut *(**s).0 //[nll]~ ERROR `*s.0` does not live long enough [E0597] + | ^^^^^^^^^^^^^ borrowed value does not live long enough +... +LL | } + | - `*s.0` dropped here while still borrowed + | +note: borrowed value must be valid for the lifetime 'a as defined on the function body at 82:26... + --> $DIR/issue-45696-scribble-on-boxed-borrow.rs:82:26 + | +LL | fn boxed_boxed_scribbled<'a>(s: Box>>) -> &'a mut u32 { + | ^^ + = warning: This error has been downgraded to a warning for backwards compatibility with previous releases. + It represents potential unsoundness in your code. + This warning will become a hard error in the future. + +error: compilation successful + --> $DIR/issue-45696-scribble-on-boxed-borrow.rs:89:1 + | +LL | / fn main() { //[ast]~ ERROR compilation successful +LL | | //[migrate]~^ ERROR compilation successful +LL | | let mut x = 1; +LL | | { +... | +LL | | *boxed_boxed_scribbled(Box::new(Box::new(Scribble(&mut x)))) += 10; +LL | | } + | |_^ + +error: aborting due to previous error + +For more information about this error, try `rustc --explain E0597`. diff --git a/src/test/ui/issue-45696-scribble-on-boxed-borrow.nll.stderr b/src/test/ui/issue-45696-scribble-on-boxed-borrow.nll.stderr new file mode 100644 index 00000000000..09cbc2f9451 --- /dev/null +++ b/src/test/ui/issue-45696-scribble-on-boxed-borrow.nll.stderr @@ -0,0 +1,48 @@ +error[E0597]: `*s.0` does not live long enough + --> $DIR/issue-45696-scribble-on-boxed-borrow.rs:63:5 + | +LL | &mut *s.0 //[nll]~ ERROR `*s.0` does not live long enough [E0597] + | ^^^^^^^^^ borrowed value does not live long enough +... +LL | } + | - `*s.0` dropped here while still borrowed + | +note: borrowed value must be valid for the lifetime 'a as defined on the function body at 62:14... + --> $DIR/issue-45696-scribble-on-boxed-borrow.rs:62:14 + | +LL | fn scribbled<'a>(s: Scribble<'a>) -> &'a mut u32 { + | ^^ + +error[E0597]: `*s.0` does not live long enough + --> $DIR/issue-45696-scribble-on-boxed-borrow.rs:73:5 + | +LL | &mut *(*s).0 //[nll]~ ERROR `*s.0` does not live long enough [E0597] + | ^^^^^^^^^^^^ borrowed value does not live long enough +... +LL | } + | - `*s.0` dropped here while still borrowed + | +note: borrowed value must be valid for the lifetime 'a as defined on the function body at 72:20... + --> $DIR/issue-45696-scribble-on-boxed-borrow.rs:72:20 + | +LL | fn boxed_scribbled<'a>(s: Box>) -> &'a mut u32 { + | ^^ + +error[E0597]: `*s.0` does not live long enough + --> $DIR/issue-45696-scribble-on-boxed-borrow.rs:83:5 + | +LL | &mut *(**s).0 //[nll]~ ERROR `*s.0` does not live long enough [E0597] + | ^^^^^^^^^^^^^ borrowed value does not live long enough +... +LL | } + | - `*s.0` dropped here while still borrowed + | +note: borrowed value must be valid for the lifetime 'a as defined on the function body at 82:26... + --> $DIR/issue-45696-scribble-on-boxed-borrow.rs:82:26 + | +LL | fn boxed_boxed_scribbled<'a>(s: Box>>) -> &'a mut u32 { + | ^^ + +error: aborting due to 3 previous errors + +For more information about this error, try `rustc --explain E0597`. diff --git a/src/test/ui/issue-45696-scribble-on-boxed-borrow.rs b/src/test/ui/issue-45696-scribble-on-boxed-borrow.rs new file mode 100644 index 00000000000..5a4874249e2 --- /dev/null +++ b/src/test/ui/issue-45696-scribble-on-boxed-borrow.rs @@ -0,0 +1,110 @@ +// Copyright 2018 The Rust Project Developers. See the COPYRIGHT +// file at the top-level directory of this distribution and at +// http://rust-lang.org/COPYRIGHT. +// +// Licensed under the Apache License, Version 2.0 or the MIT license +// , at your +// option. This file may not be copied, modified, or distributed +// except according to those terms. + +// rust-lang/rust#45696: This test is checking that we *cannot* return +// mutable borrows that would be scribbled over by destructors before +// the return occurs. +// +// We will explicitly test AST-borrowck, NLL, and migration modes; +// thus we will also skip the automated compare-mode=nll. + +// revisions: ast nll migrate +// ignore-compare-mode-nll + +// This test is going to pass in the ast and migrate revisions, +// because the AST-borrowck accepted this code in the past (see notes +// below). So we use `#[rustc_error]` to keep the outcome as an error +// in all scenarios, and rely on the stderr files to show what the +// actual behavior is. (See rust-lang/rust#49855.) +#![feature(rustc_attrs)] + +#![cfg_attr(nll, feature(nll))] +//[migrate]compile-flags: -Z borrowck=migrate -Z two-phase-borrows + +struct Scribble<'a>(&'a mut u32); + +impl<'a> Drop for Scribble<'a> { fn drop(&mut self) { *self.0 = 42; } } + +// this is okay, in both AST-borrowck and NLL: The `Scribble` here *has* +// to strictly outlive `'a` +fn borrowed_scribble<'a>(s: &'a mut Scribble) -> &'a mut u32 { + &mut *s.0 +} + +// this, by analogy to previous case, is also okay. +fn boxed_borrowed_scribble<'a>(s: Box<&'a mut Scribble>) -> &'a mut u32 { + &mut *(*s).0 +} + +// this, by analogy to previous case, is also okay. +fn boxed_boxed_borrowed_scribble<'a>(s: Box>) -> &'a mut u32 { + &mut *(**s).0 +} + +// this is not okay: in between the time that we take the mutable +// borrow and the caller receives it as a return value, the drop of +// `s` will scribble on it, violating our aliasing guarantees. +// +// * (Maybe in the future the two-phase borrows system will be +// extended to support this case. But for now, it is an error in +// NLL, even with two-phase borrows.) +// +// In any case, the AST-borrowck was not smart enough to know that +// this should be an error. (Which is perhaps the essence of why +// rust-lang/rust#45696 arose in the first place.) +fn scribbled<'a>(s: Scribble<'a>) -> &'a mut u32 { + &mut *s.0 //[nll]~ ERROR `*s.0` does not live long enough [E0597] + //[migrate]~^ WARNING `*s.0` does not live long enough [E0597] + //[migrate]~| WARNING This error has been downgraded to a warning for backwards compatibility +} + +// This, by analogy to previous case, is *also* not okay. +// +// (But again, AST-borrowck was not smart enogh to know that this +// should be an error.) +fn boxed_scribbled<'a>(s: Box>) -> &'a mut u32 { + &mut *(*s).0 //[nll]~ ERROR `*s.0` does not live long enough [E0597] + //[migrate]~^ WARNING `*s.0` does not live long enough [E0597] + //[migrate]~| WARNING This error has been downgraded to a warning for backwards compatibility +} + +// This, by analogy to previous case, is *also* not okay. +// +// (But again, AST-borrowck was not smart enogh to know that this +// should be an error.) +fn boxed_boxed_scribbled<'a>(s: Box>>) -> &'a mut u32 { + &mut *(**s).0 //[nll]~ ERROR `*s.0` does not live long enough [E0597] + //[migrate]~^ WARNING `*s.0` does not live long enough [E0597] + //[migrate]~| WARNING This error has been downgraded to a warning for backwards compatibility +} + +#[rustc_error] +fn main() { //[ast]~ ERROR compilation successful + //[migrate]~^ ERROR compilation successful + let mut x = 1; + { + let mut long_lived = Scribble(&mut x); + *borrowed_scribble(&mut long_lived) += 10; + // (Scribble dtor runs here, after `&mut`-borrow above ends) + } + { + let mut long_lived = Scribble(&mut x); + *boxed_borrowed_scribble(Box::new(&mut long_lived)) += 10; + // (Scribble dtor runs here, after `&mut`-borrow above ends) + } + { + let mut long_lived = Scribble(&mut x); + *boxed_boxed_borrowed_scribble(Box::new(Box::new(&mut long_lived))) += 10; + // (Scribble dtor runs here, after `&mut`-borrow above ends) + } + *scribbled(Scribble(&mut x)) += 10; + *boxed_scribbled(Box::new(Scribble(&mut x))) += 10; + *boxed_boxed_scribbled(Box::new(Box::new(Scribble(&mut x)))) += 10; +}