diff options
Diffstat (limited to 'src/test/ui/rfcs')
60 files changed, 2100 insertions, 0 deletions
diff --git a/src/test/ui/rfcs/rfc-1014-2.rs b/src/test/ui/rfcs/rfc-1014-2.rs new file mode 100644 index 000000000..7dd65701f --- /dev/null +++ b/src/test/ui/rfcs/rfc-1014-2.rs @@ -0,0 +1,31 @@ +// run-pass +#![allow(dead_code)] + +#![feature(rustc_private)] + +extern crate libc; + +type DWORD = u32; +type HANDLE = *mut u8; +type BOOL = i32; + +#[cfg(windows)] +extern "system" { + fn SetStdHandle(nStdHandle: DWORD, nHandle: HANDLE) -> BOOL; +} + +#[cfg(windows)] +fn close_stdout() { + const STD_OUTPUT_HANDLE: DWORD = -11i32 as DWORD; + unsafe { SetStdHandle(STD_OUTPUT_HANDLE, 0 as HANDLE); } +} + +#[cfg(windows)] +fn main() { + close_stdout(); + println!("hello"); + println!("world"); +} + +#[cfg(not(windows))] +fn main() {} diff --git a/src/test/ui/rfcs/rfc-1014.rs b/src/test/ui/rfcs/rfc-1014.rs new file mode 100644 index 000000000..c454dfa4e --- /dev/null +++ b/src/test/ui/rfcs/rfc-1014.rs @@ -0,0 +1,34 @@ +// run-pass +#![allow(dead_code)] +// ignore-wasm32-bare no libc +// ignore-sgx no libc + +#![feature(rustc_private)] + +extern crate libc; + +type DWORD = u32; +type HANDLE = *mut u8; + +#[cfg(windows)] +extern "system" { + fn GetStdHandle(which: DWORD) -> HANDLE; + fn CloseHandle(handle: HANDLE) -> i32; +} + +#[cfg(windows)] +fn close_stdout() { + const STD_OUTPUT_HANDLE: DWORD = -11i32 as DWORD; + unsafe { CloseHandle(GetStdHandle(STD_OUTPUT_HANDLE)); } +} + +#[cfg(not(windows))] +fn close_stdout() { + unsafe { libc::close(1); } +} + +fn main() { + close_stdout(); + println!("hello"); + println!("world"); +} diff --git a/src/test/ui/rfcs/rfc-1789-as-cell/from-mut.rs b/src/test/ui/rfcs/rfc-1789-as-cell/from-mut.rs new file mode 100644 index 000000000..329fadb15 --- /dev/null +++ b/src/test/ui/rfcs/rfc-1789-as-cell/from-mut.rs @@ -0,0 +1,20 @@ +// run-pass + +#![feature(as_array_of_cells)] + +use std::cell::Cell; + +fn main() { + let slice: &mut [i32] = &mut [1, 2, 3]; + let cell_slice: &Cell<[i32]> = Cell::from_mut(slice); + let slice_cell: &[Cell<i32>] = cell_slice.as_slice_of_cells(); + + assert_eq!(slice_cell.len(), 3); + + let mut array: [i32; 3] = [1, 2, 3]; + let cell_array: &Cell<[i32; 3]> = Cell::from_mut(&mut array); + let array_cell: &[Cell<i32>; 3] = cell_array.as_array_of_cells(); + + array_cell[0].set(99); + assert_eq!(array, [99, 2, 3]); +} diff --git a/src/test/ui/rfcs/rfc-1937-termination-trait/termination-trait-for-box-dyn-error.rs b/src/test/ui/rfcs/rfc-1937-termination-trait/termination-trait-for-box-dyn-error.rs new file mode 100644 index 000000000..e98582cbc --- /dev/null +++ b/src/test/ui/rfcs/rfc-1937-termination-trait/termination-trait-for-box-dyn-error.rs @@ -0,0 +1,6 @@ +// run-pass +use std::error::Error; + +fn main() -> Result<(), Box<dyn Error>> { + Ok(()) +} diff --git a/src/test/ui/rfcs/rfc-1937-termination-trait/termination-trait-for-empty.rs b/src/test/ui/rfcs/rfc-1937-termination-trait/termination-trait-for-empty.rs new file mode 100644 index 000000000..bac695d4e --- /dev/null +++ b/src/test/ui/rfcs/rfc-1937-termination-trait/termination-trait-for-empty.rs @@ -0,0 +1,2 @@ +// run-pass +fn main() {} diff --git a/src/test/ui/rfcs/rfc-1937-termination-trait/termination-trait-for-exitcode.rs b/src/test/ui/rfcs/rfc-1937-termination-trait/termination-trait-for-exitcode.rs new file mode 100644 index 000000000..6d4c15620 --- /dev/null +++ b/src/test/ui/rfcs/rfc-1937-termination-trait/termination-trait-for-exitcode.rs @@ -0,0 +1,7 @@ +// run-pass + +use std::process::ExitCode; + +fn main() -> ExitCode { + ExitCode::SUCCESS +} diff --git a/src/test/ui/rfcs/rfc-1937-termination-trait/termination-trait-for-impl-termination.rs b/src/test/ui/rfcs/rfc-1937-termination-trait/termination-trait-for-impl-termination.rs new file mode 100644 index 000000000..c06a135dc --- /dev/null +++ b/src/test/ui/rfcs/rfc-1937-termination-trait/termination-trait-for-impl-termination.rs @@ -0,0 +1,3 @@ +// run-pass + +fn main() -> impl std::process::Termination { } diff --git a/src/test/ui/rfcs/rfc-1937-termination-trait/termination-trait-for-result-box-error_ok.rs b/src/test/ui/rfcs/rfc-1937-termination-trait/termination-trait-for-result-box-error_ok.rs new file mode 100644 index 000000000..b0e932e1f --- /dev/null +++ b/src/test/ui/rfcs/rfc-1937-termination-trait/termination-trait-for-result-box-error_ok.rs @@ -0,0 +1,6 @@ +// run-pass +use std::io::Error; + +fn main() -> Result<(), Box<Error>> { + Ok(()) +} diff --git a/src/test/ui/rfcs/rfc-1937-termination-trait/termination-trait-for-result.rs b/src/test/ui/rfcs/rfc-1937-termination-trait/termination-trait-for-result.rs new file mode 100644 index 000000000..30f36c244 --- /dev/null +++ b/src/test/ui/rfcs/rfc-1937-termination-trait/termination-trait-for-result.rs @@ -0,0 +1,6 @@ +// run-pass +use std::io::Error; + +fn main() -> Result<(), Error> { + Ok(()) +} diff --git a/src/test/ui/rfcs/rfc-1937-termination-trait/termination-trait-for-str.rs b/src/test/ui/rfcs/rfc-1937-termination-trait/termination-trait-for-str.rs new file mode 100644 index 000000000..f0591c38c --- /dev/null +++ b/src/test/ui/rfcs/rfc-1937-termination-trait/termination-trait-for-str.rs @@ -0,0 +1,4 @@ +// run-pass +fn main() -> Result<(), &'static str> { + Ok(()) +} diff --git a/src/test/ui/rfcs/rfc-2005-default-binding-mode/box.rs b/src/test/ui/rfcs/rfc-2005-default-binding-mode/box.rs new file mode 100644 index 000000000..0d1cded36 --- /dev/null +++ b/src/test/ui/rfcs/rfc-2005-default-binding-mode/box.rs @@ -0,0 +1,18 @@ +// run-pass +#![allow(unreachable_patterns)] +#![feature(box_patterns)] + +struct Foo{} + +pub fn main() { + let b = Box::new(Foo{}); + let box f = &b; + let _: &Foo = f; + + match &&&b { + box f => { + let _: &Foo = f; + }, + _ => panic!(), + } +} diff --git a/src/test/ui/rfcs/rfc-2005-default-binding-mode/constref.rs b/src/test/ui/rfcs/rfc-2005-default-binding-mode/constref.rs new file mode 100644 index 000000000..d5bca6a24 --- /dev/null +++ b/src/test/ui/rfcs/rfc-2005-default-binding-mode/constref.rs @@ -0,0 +1,40 @@ +// run-pass +const CONST_REF: &[u8; 3] = b"foo"; + +trait Foo { + const CONST_REF_DEFAULT: &'static [u8; 3] = b"bar"; + const CONST_REF: &'static [u8; 3]; +} + +impl Foo for i32 { + const CONST_REF: &'static [u8; 3] = b"jjj"; +} + +impl Foo for i64 { + const CONST_REF_DEFAULT: &'static [u8; 3] = b"ggg"; + const CONST_REF: &'static [u8; 3] = b"fff"; +} + +// Check that (associated and free) const references are not mistaken for a +// non-reference pattern (in which case they would be auto-dereferenced, making +// the types mismatched). + +fn const_ref() -> bool { + let f = b"foo"; + match f { + CONST_REF => true, + _ => false, + } +} + +fn associated_const_ref() -> bool { + match (b"bar", b"jjj", b"ggg", b"fff") { + (i32::CONST_REF_DEFAULT, i32::CONST_REF, i64::CONST_REF_DEFAULT, i64::CONST_REF) => true, + _ => false, + } +} + +pub fn main() { + assert!(const_ref()); + assert!(associated_const_ref()); +} diff --git a/src/test/ui/rfcs/rfc-2005-default-binding-mode/enum.rs b/src/test/ui/rfcs/rfc-2005-default-binding-mode/enum.rs new file mode 100644 index 000000000..52fbb90ed --- /dev/null +++ b/src/test/ui/rfcs/rfc-2005-default-binding-mode/enum.rs @@ -0,0 +1,45 @@ +// run-pass +enum Wrapper { + Wrap(i32), +} + +use Wrapper::Wrap; + +pub fn main() { + let Wrap(x) = &Wrap(3); + println!("{}", *x); + + let Wrap(x) = &mut Wrap(3); + println!("{}", *x); + + if let Some(x) = &Some(3) { + println!("{}", *x); + } else { + panic!(); + } + + if let Some(x) = &mut Some(3) { + println!("{}", *x); + } else { + panic!(); + } + + if let Some(x) = &mut Some(3) { + *x += 1; + } else { + panic!(); + } + + while let Some(x) = &Some(3) { + println!("{}", *x); + break; + } + while let Some(x) = &mut Some(3) { + println!("{}", *x); + break; + } + while let Some(x) = &mut Some(3) { + *x += 1; + break; + } +} diff --git a/src/test/ui/rfcs/rfc-2005-default-binding-mode/for.rs b/src/test/ui/rfcs/rfc-2005-default-binding-mode/for.rs new file mode 100644 index 000000000..a5a24a806 --- /dev/null +++ b/src/test/ui/rfcs/rfc-2005-default-binding-mode/for.rs @@ -0,0 +1,20 @@ +// run-pass +pub fn main() { + let mut tups = vec![(0u8, 1u8)]; + + for (n, m) in &tups { + let _: &u8 = n; + let _: &u8 = m; + } + + for (n, m) in &mut tups { + *n += 1; + *m += 2; + } + + assert_eq!(tups, vec![(1u8, 3u8)]); + + for (n, m) in tups { + println!("{} {}", m, n); + } +} diff --git a/src/test/ui/rfcs/rfc-2005-default-binding-mode/general.rs b/src/test/ui/rfcs/rfc-2005-default-binding-mode/general.rs new file mode 100644 index 000000000..0207f607b --- /dev/null +++ b/src/test/ui/rfcs/rfc-2005-default-binding-mode/general.rs @@ -0,0 +1,249 @@ +// run-pass +#![allow(unused_variables)] +fn some_or_wildcard(r: &Option<i32>, b: &i32) { + let _: &i32 = match r { + Some(a) => a, + _ => b, + }; +} + +fn none_or_wildcard(r: &Option<i32>, b: &i32) { + let _: &i32 = match r { + None => b, + _ => b, + }; +} + +fn some_or_ref_none(r: &Option<i32>, b: &i32) { + let _: &i32 = match r { + Some(a) => a, + &None => b, + }; +} + +fn ref_some_or_none(r: &Option<i32>, b: &i32) { + let _: &i32 = match r { + &Some(ref a) => a, + None => b, + }; +} + +fn some_or_self(r: &Option<i32>) { + let _: &Option<i32> = match r { + Some(n) => { + let _: &i32 = n; + r + }, + x => x, + }; +} + +fn multiple_deref(r: &&&&&Option<i32>) { + let _: i32 = match r { + Some(a) => *a, + None => 5, + }; +} + +fn match_with_or() { + // FIXME(tschottdorf): #44912. + // + // let x = &Some((3, 3)); + // let _: &i32 = match x { + // Some((x, 3)) | &Some((ref x, 5)) => x, + // _ => &5i32, + // }; +} + +fn nested_mixed() { + match (&Some(5), &Some(6)) { + (Some(a), &Some(mut b)) => { + // Here, the `a` will be `&i32`, because in the first half of the tuple + // we hit a non-reference pattern and shift into `ref` mode. + // + // In the second half of the tuple there's no non-reference pattern, + // so `b` will be `i32` (bound with `move` mode). Moreover, `b` is + // mutable. + let _: &i32 = a; + b = 7; + let _: i32 = b; + }, + _ => {}, + }; +} + +fn nested_mixed_multiple_deref_1() { + let x = (1, &Some(5)); + let y = &Some(x); + match y { + Some((a, Some(b))) => { + let _: &i32 = a; + let _: &i32 = b; + }, + _ => {}, + }; +} + +fn nested_mixed_multiple_deref_2() { + let x = &Some(5); + let y = &x; + match y { + Some(z) => { + let _: &i32 = z; + }, + _ => {}, + } +} + +fn new_mutable_reference() { + let mut x = &mut Some(5); + match &mut x { + Some(y) => { + *y = 5; + }, + None => { }, + } + + match &mut x { + Some(y) => { + println!("{}", *y); + }, + None => {}, + } +} + +fn let_implicit_ref_binding() { + struct Foo(i32); + + // Note that these rules apply to any pattern matching + // whether it be in a `match` or a `let`. + // For example, `x` here is a `ref` binding: + let Foo(x) = &Foo(3); + let _: &i32 = x; +} + +fn explicit_mut_binding() { + match &Some(5i32) { + Some(mut n) => { + n += 1; + let _ = n; + } + None => {}, + }; + + match &mut Some(5i32) { + Some(n) => { + *n += 1; + let _ = n; + } + None => {}, + }; + + match &mut &mut Some(5i32) { + Some(n) => { + let _: &mut i32 = n; + } + None => {}, + }; +} + +fn tuple_mut_and_mut_mut() { + match (Some(5i32), &Some(5i32)) { + (Some(n), Some(m)) => { + // `n` and `m` are bound as immutable references. Make new references from them to + // assert that. + let r = n; + let _ = r; + let q = m; + let _ = q; + + // Assert the types. Note that we use `n` and `m` here which would fail had they been + // moved due to the assignments above. + let _: i32 = n; + let _: &i32 = m; + } + (_, _) => {}, + }; + + match (&Some(5i32), &&Some(5i32)) { + (Some(n), Some(m)) => { + let _: &i32 = n; + let _: &i32 = m; + } + (_, _) => {}, + }; + + match &mut &mut (Some(5i32), Some(5i32)) { + (Some(n), Some(m)) => { + // Dereferenced through &mut &mut, so a mutable binding results. + let _: &mut i32 = n; + let _: &mut i32 = m; + } + (_, _) => {}, + }; + + match (&mut Some(5i32), &mut &mut Some(5i32)) { + (Some(n), Some(m)) => { + let _: &mut i32 = n; + let _: &mut i32 = m; + } + (_, _) => {}, + }; +} + +fn min_mir_embedded_type() { + // The reduced invocation that an ICE was diagnosed with (was consuming + // adjustments in wrong order). + match (0u8, &&Some(5i32)) { + (_, Some(m)) => { + let _: &i32 = m; + } + (_, _) => {}, + }; +} + +fn no_autoderef() { + // Binding. + let x = &3; + println!("{}", *x); + + // Wildcard. + let _ = &3; + + // Constant of generic type (string) + const Y: &'static str = "foo"; + assert_eq!(0, match "foo" { + Y => 0, + _ => 1, + }); + + // Reference pattern. + let &x = &3; +} + +pub fn main() { + let r: &Option<i32> = &Some(3); + let b = &4i32; + + none_or_wildcard(r, b); + some_or_wildcard(r, b); + some_or_ref_none(r, b); + ref_some_or_none(r, b); + + some_or_self(r); + multiple_deref(&&&&r); + match_with_or(); + + nested_mixed(); + nested_mixed_multiple_deref_1(); + nested_mixed_multiple_deref_2(); + + new_mutable_reference(); + explicit_mut_binding(); + tuple_mut_and_mut_mut(); + min_mir_embedded_type(); + + let_implicit_ref_binding(); + + no_autoderef(); +} diff --git a/src/test/ui/rfcs/rfc-2005-default-binding-mode/lit.rs b/src/test/ui/rfcs/rfc-2005-default-binding-mode/lit.rs new file mode 100644 index 000000000..937975359 --- /dev/null +++ b/src/test/ui/rfcs/rfc-2005-default-binding-mode/lit.rs @@ -0,0 +1,34 @@ +// run-pass +#![allow(dead_code)] +fn with_u8() { + let s = 5u8; + let r = match &s { + 4 => false, + 5 => true, + _ => false, + }; + assert!(r); +} + +// A string literal isn't mistaken for a non-ref pattern (in which case we'd +// deref `s` and mess things up). +fn with_str() { + let s: &'static str = "abc"; + match s { + "abc" => true, + _ => panic!(), + }; +} + +// Ditto with byte strings. +fn with_bytes() { + let s: &'static [u8] = b"abc"; + match s { + b"abc" => true, + _ => panic!(), + }; +} + +pub fn main() { + with_str(); +} diff --git a/src/test/ui/rfcs/rfc-2005-default-binding-mode/range.rs b/src/test/ui/rfcs/rfc-2005-default-binding-mode/range.rs new file mode 100644 index 000000000..f8abd1b96 --- /dev/null +++ b/src/test/ui/rfcs/rfc-2005-default-binding-mode/range.rs @@ -0,0 +1,9 @@ +// run-pass +pub fn main() { + let i = 5; + match &&&&i { + 1 ..= 3 => panic!(), + 4 ..= 8 => {}, + _ => panic!(), + } +} diff --git a/src/test/ui/rfcs/rfc-2005-default-binding-mode/ref-region.rs b/src/test/ui/rfcs/rfc-2005-default-binding-mode/ref-region.rs new file mode 100644 index 000000000..b74e45c93 --- /dev/null +++ b/src/test/ui/rfcs/rfc-2005-default-binding-mode/ref-region.rs @@ -0,0 +1,16 @@ +// run-pass +fn foo<'a, 'b>(x: &'a &'b Option<u32>) -> &'a u32 { + let x: &'a &'a Option<u32> = x; + match x { + Some(r) => { + let _: &u32 = r; + r + }, + &None => panic!(), + } +} + +pub fn main() { + let x = Some(5); + foo(&&x); +} diff --git a/src/test/ui/rfcs/rfc-2005-default-binding-mode/reset-mode.rs b/src/test/ui/rfcs/rfc-2005-default-binding-mode/reset-mode.rs new file mode 100644 index 000000000..3b9d07610 --- /dev/null +++ b/src/test/ui/rfcs/rfc-2005-default-binding-mode/reset-mode.rs @@ -0,0 +1,14 @@ +// run-pass +// Test that we "reset" the mode as we pass through a `&` pattern. +// +// cc #46688 + +fn surprise(x: i32) { + assert_eq!(x, 2); +} + +fn main() { + let x = &(1, &2); + let (_, &b) = x; + surprise(b); +} diff --git a/src/test/ui/rfcs/rfc-2005-default-binding-mode/slice.rs b/src/test/ui/rfcs/rfc-2005-default-binding-mode/slice.rs new file mode 100644 index 000000000..33229a205 --- /dev/null +++ b/src/test/ui/rfcs/rfc-2005-default-binding-mode/slice.rs @@ -0,0 +1,25 @@ +// run-pass + +fn slice_pat() { + let sl: &[u8] = b"foo"; + + match sl { + [first, remainder @ ..] => { + let _: &u8 = first; + assert_eq!(first, &b'f'); + assert_eq!(remainder, b"oo"); + } + [] => panic!(), + } +} + +fn slice_pat_omission() { + match &[0, 1, 2] { + [..] => {} + }; +} + +fn main() { + slice_pat(); + slice_pat_omission(); +} diff --git a/src/test/ui/rfcs/rfc-2005-default-binding-mode/struct.rs b/src/test/ui/rfcs/rfc-2005-default-binding-mode/struct.rs new file mode 100644 index 000000000..5a00e5b68 --- /dev/null +++ b/src/test/ui/rfcs/rfc-2005-default-binding-mode/struct.rs @@ -0,0 +1,22 @@ +// run-pass +#[derive(Debug, PartialEq)] +struct Foo { + x: u8, +} + +pub fn main() { + let mut foo = Foo { + x: 1, + }; + + match &mut foo { + Foo{x: n} => { + *n += 1; + }, + }; + + assert_eq!(foo, Foo{x: 2}); + + let Foo{x: n} = &foo; + assert_eq!(*n, 2); +} diff --git a/src/test/ui/rfcs/rfc-2005-default-binding-mode/tuple-struct.rs b/src/test/ui/rfcs/rfc-2005-default-binding-mode/tuple-struct.rs new file mode 100644 index 000000000..0cf9ba1b4 --- /dev/null +++ b/src/test/ui/rfcs/rfc-2005-default-binding-mode/tuple-struct.rs @@ -0,0 +1,19 @@ +// run-pass +#![allow(dead_code)] +enum Foo { + Bar(Option<i8>, (), (), Vec<i32>), + Baz, +} + +pub fn main() { + let foo = Foo::Bar(Some(1), (), (), vec![2, 3]); + + match &foo { + Foo::Baz => panic!(), + Foo::Bar(None, ..) => panic!(), + Foo::Bar(Some(n), .., v) => { + assert_eq!((*v).len(), 2); + assert_eq!(*n, 1); + } + } +} diff --git a/src/test/ui/rfcs/rfc-2005-default-binding-mode/tuple.rs b/src/test/ui/rfcs/rfc-2005-default-binding-mode/tuple.rs new file mode 100644 index 000000000..4c22aa2d7 --- /dev/null +++ b/src/test/ui/rfcs/rfc-2005-default-binding-mode/tuple.rs @@ -0,0 +1,12 @@ +// run-pass +pub fn main() { + let foo = (Some(1), (), (), vec![2, 3]); + + match &foo { + (Some(n), .., v) => { + assert_eq!((*v).len(), 2); + assert_eq!(*n, 1); + } + (None, (), (), ..) => panic!(), + } +} diff --git a/src/test/ui/rfcs/rfc-2151-raw-identifiers/attr.rs b/src/test/ui/rfcs/rfc-2151-raw-identifiers/attr.rs new file mode 100644 index 000000000..d359067f6 --- /dev/null +++ b/src/test/ui/rfcs/rfc-2151-raw-identifiers/attr.rs @@ -0,0 +1,15 @@ +// run-pass +use std::mem; + +#[r#repr(r#C, r#packed)] +struct Test { + a: bool, b: u64 +} + +#[r#derive(r#Debug)] +struct Test2(#[allow(unused_tuple_struct_fields)] u32); + +pub fn main() { + assert_eq!(mem::size_of::<Test>(), 9); + assert_eq!("Test2(123)", format!("{:?}", Test2(123))); +} diff --git a/src/test/ui/rfcs/rfc-2151-raw-identifiers/basic.rs b/src/test/ui/rfcs/rfc-2151-raw-identifiers/basic.rs new file mode 100644 index 000000000..f2fe59668 --- /dev/null +++ b/src/test/ui/rfcs/rfc-2151-raw-identifiers/basic.rs @@ -0,0 +1,20 @@ +// run-pass +fn r#fn(r#match: u32) -> u32 { + r#match +} + +pub fn main() { + let r#struct = 1; + assert_eq!(1, r#struct); + + let foo = 2; + assert_eq!(2, r#foo); + + let r#bar = 3; + assert_eq!(3, bar); + + assert_eq!(4, r#fn(4)); + + let r#true = false; + assert_eq!(r#true, false); +} diff --git a/src/test/ui/rfcs/rfc-2151-raw-identifiers/items.rs b/src/test/ui/rfcs/rfc-2151-raw-identifiers/items.rs new file mode 100644 index 000000000..466522517 --- /dev/null +++ b/src/test/ui/rfcs/rfc-2151-raw-identifiers/items.rs @@ -0,0 +1,32 @@ +// run-pass +#[derive(Debug, PartialEq, Eq)] +struct IntWrapper(u32); + +#[derive(Debug, Ord, PartialOrd, PartialEq, Eq, Hash, Copy, Clone, Default)] +struct HasKeywordField { + r#struct: u32, +} + +struct Generic<r#T>(T); + +trait Trait { + fn r#trait(&self) -> u32; +} +impl Trait for Generic<u32> { + fn r#trait(&self) -> u32 { + self.0 + } +} + +pub fn main() { + assert_eq!(IntWrapper(1), r#IntWrapper(1)); + + match IntWrapper(2) { + r#IntWrapper(r#struct) => assert_eq!(2, r#struct), + } + + assert_eq!("HasKeywordField { struct: 3 }", format!("{:?}", HasKeywordField { r#struct: 3 })); + + assert_eq!(4, Generic(4).0); + assert_eq!(5, Generic(5).r#trait()); +} diff --git a/src/test/ui/rfcs/rfc-2151-raw-identifiers/macros.rs b/src/test/ui/rfcs/rfc-2151-raw-identifiers/macros.rs new file mode 100644 index 000000000..0ab7e17f8 --- /dev/null +++ b/src/test/ui/rfcs/rfc-2151-raw-identifiers/macros.rs @@ -0,0 +1,38 @@ +// run-pass +#![feature(decl_macro)] + +macro_rules! r#struct { + ($r#struct:expr) => { $r#struct } +} + +macro_rules! old_macro { + ($a:expr) => {$a} +} + +macro r#decl_macro($r#fn:expr) { + $r#fn +} + +macro passthrough($id:ident) { + $id +} + +macro_rules! test_pat_match { + (a) => { 6 }; + (r#a) => { 7 }; +} + +pub fn main() { + r#println!("{struct}", r#struct = 1); + assert_eq!(2, r#struct!(2)); + assert_eq!(3, r#old_macro!(3)); + assert_eq!(4, decl_macro!(4)); + + let r#match = 5; + assert_eq!(5, passthrough!(r#match)); + + assert_eq!("r#struct", stringify!(r#struct)); + + assert_eq!(6, test_pat_match!(a)); + assert_eq!(7, test_pat_match!(r#a)); +} diff --git a/src/test/ui/rfcs/rfc-2175-or-if-while-let/basic.rs b/src/test/ui/rfcs/rfc-2175-or-if-while-let/basic.rs new file mode 100644 index 000000000..22f04c58f --- /dev/null +++ b/src/test/ui/rfcs/rfc-2175-or-if-while-let/basic.rs @@ -0,0 +1,33 @@ +// run-pass +#![allow(dead_code)] + +enum E { + V(u8), + U(u8), + W, +} +use E::*; + +fn main() { + let mut e = V(10); + + if let V(x) | U(x) = e { + assert_eq!(x, 10); + } + while let V(x) | U(x) = e { + assert_eq!(x, 10); + e = W; + } + + // Accept leading `|`: + + let mut e = V(10); + + if let | V(x) | U(x) = e { + assert_eq!(x, 10); + } + while let | V(x) | U(x) = e { + assert_eq!(x, 10); + e = W; + } +} diff --git a/src/test/ui/rfcs/rfc-2302-self-struct-ctor.rs b/src/test/ui/rfcs/rfc-2302-self-struct-ctor.rs new file mode 100644 index 000000000..1ec20c500 --- /dev/null +++ b/src/test/ui/rfcs/rfc-2302-self-struct-ctor.rs @@ -0,0 +1,127 @@ +// run-pass + +#![allow(dead_code)] + +use std::fmt::Display; + +struct ST1(i32, i32); + +impl ST1 { + fn new() -> Self { + ST1(0, 1) + } + + fn ctor() -> Self { + Self(1,2) // Self as a constructor + } + + fn pattern(self) { + match self { + Self(x, y) => println!("{} {}", x, y), // Self as a pattern + } + } +} + +struct ST2<T>(T); // With type parameter + +impl<T> ST2<T> where T: Display { + + fn ctor(v: T) -> Self { + Self(v) + } + + fn pattern(&self) { + match self { + Self(ref v) => println!("{}", v), + } + } +} + +struct ST3<'a>(&'a i32); // With lifetime parameter + +impl<'a> ST3<'a> { + + fn ctor(v: &'a i32) -> Self { + Self(v) + } + + fn pattern(self) { + let Self(ref v) = self; + println!("{}", v); + } +} + +struct ST4(usize); + +impl ST4 { + fn map(opt: Option<usize>) -> Option<Self> { + opt.map(Self) // use `Self` as a function passed somewhere + } +} + +struct ST5; // unit struct + +impl ST5 { + fn ctor() -> Self { + Self // `Self` as a unit struct value + } + + fn pattern(self) -> Self { + match self { + Self => Self, // `Self` as a unit struct value for matching + } + } +} + +struct ST6(i32); +type T = ST6; +impl T { + fn ctor() -> Self { + ST6(1) + } + + fn type_alias(self) { + let Self(_x) = match self { Self(x) => Self(x) }; + let _opt: Option<Self> = Some(0).map(Self); + } +} + +struct ST7<T1, T2>(T1, T2); + +impl ST7<i32, usize> { + + fn ctor() -> Self { + Self(1, 2) + } + + fn pattern(self) -> Self { + match self { + Self(x, y) => Self(x, y), + } + } +} + +fn main() { + let v1 = ST1::ctor(); + v1.pattern(); + + let v2 = ST2::ctor(10); + v2.pattern(); + + let local = 42; + let v3 = ST3::ctor(&local); + v3.pattern(); + + let v4 = Some(1usize); + let _ = ST4::map(v4); + + let v5 = ST5::ctor(); + v5.pattern(); + + let v6 = ST6::ctor(); + v6.type_alias(); + + let v7 = ST7::<i32, usize>::ctor(); + let r = v7.pattern(); + println!("{} {}", r.0, r.1) +} diff --git a/src/test/ui/rfcs/rfc-2396-target_feature-11/check-pass.rs b/src/test/ui/rfcs/rfc-2396-target_feature-11/check-pass.rs new file mode 100644 index 000000000..e0842bfa4 --- /dev/null +++ b/src/test/ui/rfcs/rfc-2396-target_feature-11/check-pass.rs @@ -0,0 +1,52 @@ +// Tests the new rules added by RFC 2396, including: +// - applying `#[target_feature]` to safe functions is allowed +// - calling functions with `#[target_feature]` is allowed in +// functions which have (at least) the same features +// - calling functions with `#[target_feature]` is allowed in +// unsafe contexts +// - functions with `#[target_feature]` can coerce to unsafe fn pointers + +// check-pass +// only-x86_64 +// revisions: mir thir +// [thir]compile-flags: -Z thir-unsafeck + +#![feature(target_feature_11)] + +#[target_feature(enable = "sse2")] +const fn sse2() {} + +#[cfg(target_feature = "sse2")] +const SSE2_ONLY: () = unsafe { + sse2(); +}; + +#[target_feature(enable = "sse2")] +fn also_sse2() { + sse2(); +} + +#[target_feature(enable = "sse2")] +#[target_feature(enable = "avx")] +fn sse2_and_avx() { + sse2(); +} + +struct Foo; + +impl Foo { + #[target_feature(enable = "sse2")] + fn sse2(&self) { + sse2(); + } +} + +fn main() { + if cfg!(target_feature = "sse2") { + unsafe { + sse2(); + Foo.sse2(); + } + } + let sse2_ptr: unsafe fn() = sse2; +} diff --git a/src/test/ui/rfcs/rfc-2396-target_feature-11/closures-inherit-target_feature.rs b/src/test/ui/rfcs/rfc-2396-target_feature-11/closures-inherit-target_feature.rs new file mode 100644 index 000000000..a59d7c2d7 --- /dev/null +++ b/src/test/ui/rfcs/rfc-2396-target_feature-11/closures-inherit-target_feature.rs @@ -0,0 +1,20 @@ +// Tests #73631: closures inherit `#[target_feature]` annotations + +// check-pass +// revisions: mir thir +// [thir]compile-flags: -Z thir-unsafeck +// only-x86_64 + +#![feature(target_feature_11)] + +#[target_feature(enable="avx")] +fn also_use_avx() { + println!("Hello from AVX") +} + +#[target_feature(enable="avx")] +fn use_avx() -> Box<dyn Fn()> { + Box::new(|| also_use_avx()) +} + +fn main() {} diff --git a/src/test/ui/rfcs/rfc-2396-target_feature-11/feature-gate-target_feature_11.rs b/src/test/ui/rfcs/rfc-2396-target_feature-11/feature-gate-target_feature_11.rs new file mode 100644 index 000000000..975d7a1f6 --- /dev/null +++ b/src/test/ui/rfcs/rfc-2396-target_feature-11/feature-gate-target_feature_11.rs @@ -0,0 +1,6 @@ +// only-x86_64 + +#[target_feature(enable = "sse2")] //~ ERROR can only be applied to `unsafe` functions +fn foo() {} + +fn main() {} diff --git a/src/test/ui/rfcs/rfc-2396-target_feature-11/feature-gate-target_feature_11.stderr b/src/test/ui/rfcs/rfc-2396-target_feature-11/feature-gate-target_feature_11.stderr new file mode 100644 index 000000000..18917fd25 --- /dev/null +++ b/src/test/ui/rfcs/rfc-2396-target_feature-11/feature-gate-target_feature_11.stderr @@ -0,0 +1,14 @@ +error[E0658]: `#[target_feature(..)]` can only be applied to `unsafe` functions + --> $DIR/feature-gate-target_feature_11.rs:3:1 + | +LL | #[target_feature(enable = "sse2")] + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ +LL | fn foo() {} + | -------- not an `unsafe` function + | + = note: see issue #69098 <https://github.com/rust-lang/rust/issues/69098> for more information + = help: add `#![feature(target_feature_11)]` to the crate attributes to enable + +error: aborting due to previous error + +For more information about this error, try `rustc --explain E0658`. diff --git a/src/test/ui/rfcs/rfc-2396-target_feature-11/fn-ptr.mir.stderr b/src/test/ui/rfcs/rfc-2396-target_feature-11/fn-ptr.mir.stderr new file mode 100644 index 000000000..cf5815df5 --- /dev/null +++ b/src/test/ui/rfcs/rfc-2396-target_feature-11/fn-ptr.mir.stderr @@ -0,0 +1,18 @@ +error[E0308]: mismatched types + --> $DIR/fn-ptr.rs:11:21 + | +LL | #[target_feature(enable = "sse2")] + | ---------------------------------- `#[target_feature]` added here +... +LL | let foo: fn() = foo; + | ---- ^^^ cannot coerce functions with `#[target_feature]` to safe function pointers + | | + | expected due to this + | + = note: expected fn pointer `fn()` + found fn item `fn() {foo}` + = note: functions with `#[target_feature]` can only be coerced to `unsafe` function pointers + +error: aborting due to previous error + +For more information about this error, try `rustc --explain E0308`. diff --git a/src/test/ui/rfcs/rfc-2396-target_feature-11/fn-ptr.rs b/src/test/ui/rfcs/rfc-2396-target_feature-11/fn-ptr.rs new file mode 100644 index 000000000..c95d4a08e --- /dev/null +++ b/src/test/ui/rfcs/rfc-2396-target_feature-11/fn-ptr.rs @@ -0,0 +1,12 @@ +// revisions: mir thir +// [thir]compile-flags: -Z thir-unsafeck +// only-x86_64 + +#![feature(target_feature_11)] + +#[target_feature(enable = "sse2")] +fn foo() {} + +fn main() { + let foo: fn() = foo; //~ ERROR mismatched types +} diff --git a/src/test/ui/rfcs/rfc-2396-target_feature-11/fn-ptr.thir.stderr b/src/test/ui/rfcs/rfc-2396-target_feature-11/fn-ptr.thir.stderr new file mode 100644 index 000000000..cf5815df5 --- /dev/null +++ b/src/test/ui/rfcs/rfc-2396-target_feature-11/fn-ptr.thir.stderr @@ -0,0 +1,18 @@ +error[E0308]: mismatched types + --> $DIR/fn-ptr.rs:11:21 + | +LL | #[target_feature(enable = "sse2")] + | ---------------------------------- `#[target_feature]` added here +... +LL | let foo: fn() = foo; + | ---- ^^^ cannot coerce functions with `#[target_feature]` to safe function pointers + | | + | expected due to this + | + = note: expected fn pointer `fn()` + found fn item `fn() {foo}` + = note: functions with `#[target_feature]` can only be coerced to `unsafe` function pointers + +error: aborting due to previous error + +For more information about this error, try `rustc --explain E0308`. diff --git a/src/test/ui/rfcs/rfc-2396-target_feature-11/fn-traits.rs b/src/test/ui/rfcs/rfc-2396-target_feature-11/fn-traits.rs new file mode 100644 index 000000000..43bda4962 --- /dev/null +++ b/src/test/ui/rfcs/rfc-2396-target_feature-11/fn-traits.rs @@ -0,0 +1,34 @@ +// only-x86_64 + +#![feature(target_feature_11)] + +#[target_feature(enable = "avx")] +fn foo() {} + +#[target_feature(enable = "avx")] +unsafe fn foo_unsafe() {} + +fn call(f: impl Fn()) { + f() +} + +fn call_mut(f: impl FnMut()) { + f() +} + +fn call_once(f: impl FnOnce()) { + f() +} + +fn main() { + call(foo); //~ ERROR expected a `Fn<()>` closure, found `fn() {foo}` + call_mut(foo); //~ ERROR expected a `FnMut<()>` closure, found `fn() {foo}` + call_once(foo); //~ ERROR expected a `FnOnce<()>` closure, found `fn() {foo}` + + call(foo_unsafe); + //~^ ERROR expected a `Fn<()>` closure, found `unsafe fn() {foo_unsafe}` + call_mut(foo_unsafe); + //~^ ERROR expected a `FnMut<()>` closure, found `unsafe fn() {foo_unsafe}` + call_once(foo_unsafe); + //~^ ERROR expected a `FnOnce<()>` closure, found `unsafe fn() {foo_unsafe}` +} diff --git a/src/test/ui/rfcs/rfc-2396-target_feature-11/fn-traits.stderr b/src/test/ui/rfcs/rfc-2396-target_feature-11/fn-traits.stderr new file mode 100644 index 000000000..94a90a568 --- /dev/null +++ b/src/test/ui/rfcs/rfc-2396-target_feature-11/fn-traits.stderr @@ -0,0 +1,105 @@ +error[E0277]: expected a `Fn<()>` closure, found `fn() {foo}` + --> $DIR/fn-traits.rs:24:10 + | +LL | call(foo); + | ---- ^^^ expected an `Fn<()>` closure, found `fn() {foo}` + | | + | required by a bound introduced by this call + | + = help: the trait `Fn<()>` is not implemented for `fn() {foo}` + = note: wrap the `fn() {foo}` in a closure with no arguments: `|| { /* code */ }` + = note: `#[target_feature]` functions do not implement the `Fn` traits +note: required by a bound in `call` + --> $DIR/fn-traits.rs:11:17 + | +LL | fn call(f: impl Fn()) { + | ^^^^ required by this bound in `call` + +error[E0277]: expected a `FnMut<()>` closure, found `fn() {foo}` + --> $DIR/fn-traits.rs:25:14 + | +LL | call_mut(foo); + | -------- ^^^ expected an `FnMut<()>` closure, found `fn() {foo}` + | | + | required by a bound introduced by this call + | + = help: the trait `FnMut<()>` is not implemented for `fn() {foo}` + = note: wrap the `fn() {foo}` in a closure with no arguments: `|| { /* code */ }` + = note: `#[target_feature]` functions do not implement the `Fn` traits +note: required by a bound in `call_mut` + --> $DIR/fn-traits.rs:15:21 + | +LL | fn call_mut(f: impl FnMut()) { + | ^^^^^^^ required by this bound in `call_mut` + +error[E0277]: expected a `FnOnce<()>` closure, found `fn() {foo}` + --> $DIR/fn-traits.rs:26:15 + | +LL | call_once(foo); + | --------- ^^^ expected an `FnOnce<()>` closure, found `fn() {foo}` + | | + | required by a bound introduced by this call + | + = help: the trait `FnOnce<()>` is not implemented for `fn() {foo}` + = note: wrap the `fn() {foo}` in a closure with no arguments: `|| { /* code */ }` + = note: `#[target_feature]` functions do not implement the `Fn` traits +note: required by a bound in `call_once` + --> $DIR/fn-traits.rs:19:22 + | +LL | fn call_once(f: impl FnOnce()) { + | ^^^^^^^^ required by this bound in `call_once` + +error[E0277]: expected a `Fn<()>` closure, found `unsafe fn() {foo_unsafe}` + --> $DIR/fn-traits.rs:28:10 + | +LL | call(foo_unsafe); + | ---- ^^^^^^^^^^ call the function in a closure: `|| unsafe { /* code */ }` + | | + | required by a bound introduced by this call + | + = help: the trait `Fn<()>` is not implemented for `unsafe fn() {foo_unsafe}` + = note: wrap the `unsafe fn() {foo_unsafe}` in a closure with no arguments: `|| { /* code */ }` + = note: `#[target_feature]` functions do not implement the `Fn` traits +note: required by a bound in `call` + --> $DIR/fn-traits.rs:11:17 + | +LL | fn call(f: impl Fn()) { + | ^^^^ required by this bound in `call` + +error[E0277]: expected a `FnMut<()>` closure, found `unsafe fn() {foo_unsafe}` + --> $DIR/fn-traits.rs:30:14 + | +LL | call_mut(foo_unsafe); + | -------- ^^^^^^^^^^ call the function in a closure: `|| unsafe { /* code */ }` + | | + | required by a bound introduced by this call + | + = help: the trait `FnMut<()>` is not implemented for `unsafe fn() {foo_unsafe}` + = note: wrap the `unsafe fn() {foo_unsafe}` in a closure with no arguments: `|| { /* code */ }` + = note: `#[target_feature]` functions do not implement the `Fn` traits +note: required by a bound in `call_mut` + --> $DIR/fn-traits.rs:15:21 + | +LL | fn call_mut(f: impl FnMut()) { + | ^^^^^^^ required by this bound in `call_mut` + +error[E0277]: expected a `FnOnce<()>` closure, found `unsafe fn() {foo_unsafe}` + --> $DIR/fn-traits.rs:32:15 + | +LL | call_once(foo_unsafe); + | --------- ^^^^^^^^^^ call the function in a closure: `|| unsafe { /* code */ }` + | | + | required by a bound introduced by this call + | + = help: the trait `FnOnce<()>` is not implemented for `unsafe fn() {foo_unsafe}` + = note: wrap the `unsafe fn() {foo_unsafe}` in a closure with no arguments: `|| { /* code */ }` + = note: `#[target_feature]` functions do not implement the `Fn` traits +note: required by a bound in `call_once` + --> $DIR/fn-traits.rs:19:22 + | +LL | fn call_once(f: impl FnOnce()) { + | ^^^^^^^^ required by this bound in `call_once` + +error: aborting due to 6 previous errors + +For more information about this error, try `rustc --explain E0277`. diff --git a/src/test/ui/rfcs/rfc-2396-target_feature-11/issue-99876.rs b/src/test/ui/rfcs/rfc-2396-target_feature-11/issue-99876.rs new file mode 100644 index 000000000..033dcdfc0 --- /dev/null +++ b/src/test/ui/rfcs/rfc-2396-target_feature-11/issue-99876.rs @@ -0,0 +1,9 @@ +// check-pass + +#![feature(target_feature_11)] + +struct S<T>(T) +where + [T; (|| {}, 1).1]: Copy; + +fn main() {} diff --git a/src/test/ui/rfcs/rfc-2396-target_feature-11/safe-calls.mir.stderr b/src/test/ui/rfcs/rfc-2396-target_feature-11/safe-calls.mir.stderr new file mode 100644 index 000000000..0ef7b8b09 --- /dev/null +++ b/src/test/ui/rfcs/rfc-2396-target_feature-11/safe-calls.mir.stderr @@ -0,0 +1,83 @@ +error[E0133]: call to function with `#[target_feature]` is unsafe and requires unsafe function or block + --> $DIR/safe-calls.rs:23:5 + | +LL | sse2(); + | ^^^^^^ call to function with `#[target_feature]` + | + = note: can only be called if the required target features are available + +error[E0133]: call to function with `#[target_feature]` is unsafe and requires unsafe function or block + --> $DIR/safe-calls.rs:26:5 + | +LL | avx_bmi2(); + | ^^^^^^^^^^ call to function with `#[target_feature]` + | + = note: can only be called if the required target features are available + +error[E0133]: call to function with `#[target_feature]` is unsafe and requires unsafe function or block + --> $DIR/safe-calls.rs:29:5 + | +LL | Quux.avx_bmi2(); + | ^^^^^^^^^^^^^^^ call to function with `#[target_feature]` + | + = note: can only be called if the required target features are available + +error[E0133]: call to function with `#[target_feature]` is unsafe and requires unsafe function or block + --> $DIR/safe-calls.rs:36:5 + | +LL | avx_bmi2(); + | ^^^^^^^^^^ call to function with `#[target_feature]` + | + = note: can only be called if the required target features are available + +error[E0133]: call to function with `#[target_feature]` is unsafe and requires unsafe function or block + --> $DIR/safe-calls.rs:39:5 + | +LL | Quux.avx_bmi2(); + | ^^^^^^^^^^^^^^^ call to function with `#[target_feature]` + | + = note: can only be called if the required target features are available + +error[E0133]: call to function with `#[target_feature]` is unsafe and requires unsafe function or block + --> $DIR/safe-calls.rs:46:5 + | +LL | sse2(); + | ^^^^^^ call to function with `#[target_feature]` + | + = note: can only be called if the required target features are available + +error[E0133]: call to function with `#[target_feature]` is unsafe and requires unsafe function or block + --> $DIR/safe-calls.rs:49:5 + | +LL | avx_bmi2(); + | ^^^^^^^^^^ call to function with `#[target_feature]` + | + = note: can only be called if the required target features are available + +error[E0133]: call to function with `#[target_feature]` is unsafe and requires unsafe function or block + --> $DIR/safe-calls.rs:52:5 + | +LL | Quux.avx_bmi2(); + | ^^^^^^^^^^^^^^^ call to function with `#[target_feature]` + | + = note: can only be called if the required target features are available + +error[E0133]: call to function with `#[target_feature]` is unsafe and requires unsafe function or block + --> $DIR/safe-calls.rs:60:5 + | +LL | sse2(); + | ^^^^^^ call to function with `#[target_feature]` + | + = note: can only be called if the required target features are available + +error[E0133]: call to function with `#[target_feature]` is unsafe and requires unsafe function or block + --> $DIR/safe-calls.rs:65:18 + | +LL | const name: () = sse2(); + | ^^^^^^ call to function with `#[target_feature]` + | + = note: can only be called if the required target features are available + +error: aborting due to 10 previous errors + +For more information about this error, try `rustc --explain E0133`. diff --git a/src/test/ui/rfcs/rfc-2396-target_feature-11/safe-calls.rs b/src/test/ui/rfcs/rfc-2396-target_feature-11/safe-calls.rs new file mode 100644 index 000000000..cebc6f947 --- /dev/null +++ b/src/test/ui/rfcs/rfc-2396-target_feature-11/safe-calls.rs @@ -0,0 +1,69 @@ +// revisions: mir thir +// [thir]compile-flags: -Z thir-unsafeck +// only-x86_64 + +#![feature(target_feature_11)] + +#[target_feature(enable = "sse2")] +const fn sse2() {} + +#[target_feature(enable = "avx")] +#[target_feature(enable = "bmi2")] +fn avx_bmi2() {} + +struct Quux; + +impl Quux { + #[target_feature(enable = "avx")] + #[target_feature(enable = "bmi2")] + fn avx_bmi2(&self) {} +} + +fn foo() { + sse2(); + //[mir]~^ ERROR call to function with `#[target_feature]` is unsafe + //[thir]~^^ ERROR call to function `sse2` with `#[target_feature]` is unsafe + avx_bmi2(); + //[mir]~^ ERROR call to function with `#[target_feature]` is unsafe + //[thir]~^^ ERROR call to function `avx_bmi2` with `#[target_feature]` is unsafe + Quux.avx_bmi2(); + //[mir]~^ ERROR call to function with `#[target_feature]` is unsafe + //[thir]~^^ ERROR call to function `Quux::avx_bmi2` with `#[target_feature]` is unsafe +} + +#[target_feature(enable = "sse2")] +fn bar() { + avx_bmi2(); + //[mir]~^ ERROR call to function with `#[target_feature]` is unsafe + //[thir]~^^ ERROR call to function `avx_bmi2` with `#[target_feature]` is unsafe + Quux.avx_bmi2(); + //[mir]~^ ERROR call to function with `#[target_feature]` is unsafe + //[thir]~^^ ERROR call to function `Quux::avx_bmi2` with `#[target_feature]` is unsafe +} + +#[target_feature(enable = "avx")] +fn baz() { + sse2(); + //[mir]~^ ERROR call to function with `#[target_feature]` is unsafe + //[thir]~^^ ERROR call to function `sse2` with `#[target_feature]` is unsafe + avx_bmi2(); + //[mir]~^ ERROR call to function with `#[target_feature]` is unsafe + //[thir]~^^ ERROR call to function `avx_bmi2` with `#[target_feature]` is unsafe + Quux.avx_bmi2(); + //[mir]~^ ERROR call to function with `#[target_feature]` is unsafe + //[thir]~^^ ERROR call to function `Quux::avx_bmi2` with `#[target_feature]` is unsafe +} + +#[target_feature(enable = "avx")] +#[target_feature(enable = "bmi2")] +fn qux() { + sse2(); + //[mir]~^ ERROR call to function with `#[target_feature]` is unsafe + //[thir]~^^ ERROR call to function `sse2` with `#[target_feature]` is unsafe +} + +const name: () = sse2(); +//[mir]~^ ERROR call to function with `#[target_feature]` is unsafe +//[thir]~^^ ERROR call to function `sse2` with `#[target_feature]` is unsafe + +fn main() {} diff --git a/src/test/ui/rfcs/rfc-2396-target_feature-11/safe-calls.thir.stderr b/src/test/ui/rfcs/rfc-2396-target_feature-11/safe-calls.thir.stderr new file mode 100644 index 000000000..c75ac6e8b --- /dev/null +++ b/src/test/ui/rfcs/rfc-2396-target_feature-11/safe-calls.thir.stderr @@ -0,0 +1,83 @@ +error[E0133]: call to function `sse2` with `#[target_feature]` is unsafe and requires unsafe function or block + --> $DIR/safe-calls.rs:23:5 + | +LL | sse2(); + | ^^^^^^ call to function with `#[target_feature]` + | + = note: can only be called if the required target features are available + +error[E0133]: call to function `avx_bmi2` with `#[target_feature]` is unsafe and requires unsafe function or block + --> $DIR/safe-calls.rs:26:5 + | +LL | avx_bmi2(); + | ^^^^^^^^^^ call to function with `#[target_feature]` + | + = note: can only be called if the required target features are available + +error[E0133]: call to function `Quux::avx_bmi2` with `#[target_feature]` is unsafe and requires unsafe function or block + --> $DIR/safe-calls.rs:29:5 + | +LL | Quux.avx_bmi2(); + | ^^^^^^^^^^^^^^^ call to function with `#[target_feature]` + | + = note: can only be called if the required target features are available + +error[E0133]: call to function `avx_bmi2` with `#[target_feature]` is unsafe and requires unsafe function or block + --> $DIR/safe-calls.rs:36:5 + | +LL | avx_bmi2(); + | ^^^^^^^^^^ call to function with `#[target_feature]` + | + = note: can only be called if the required target features are available + +error[E0133]: call to function `Quux::avx_bmi2` with `#[target_feature]` is unsafe and requires unsafe function or block + --> $DIR/safe-calls.rs:39:5 + | +LL | Quux.avx_bmi2(); + | ^^^^^^^^^^^^^^^ call to function with `#[target_feature]` + | + = note: can only be called if the required target features are available + +error[E0133]: call to function `sse2` with `#[target_feature]` is unsafe and requires unsafe function or block + --> $DIR/safe-calls.rs:46:5 + | +LL | sse2(); + | ^^^^^^ call to function with `#[target_feature]` + | + = note: can only be called if the required target features are available + +error[E0133]: call to function `avx_bmi2` with `#[target_feature]` is unsafe and requires unsafe function or block + --> $DIR/safe-calls.rs:49:5 + | +LL | avx_bmi2(); + | ^^^^^^^^^^ call to function with `#[target_feature]` + | + = note: can only be called if the required target features are available + +error[E0133]: call to function `Quux::avx_bmi2` with `#[target_feature]` is unsafe and requires unsafe function or block + --> $DIR/safe-calls.rs:52:5 + | +LL | Quux.avx_bmi2(); + | ^^^^^^^^^^^^^^^ call to function with `#[target_feature]` + | + = note: can only be called if the required target features are available + +error[E0133]: call to function `sse2` with `#[target_feature]` is unsafe and requires unsafe function or block + --> $DIR/safe-calls.rs:60:5 + | +LL | sse2(); + | ^^^^^^ call to function with `#[target_feature]` + | + = note: can only be called if the required target features are available + +error[E0133]: call to function `sse2` with `#[target_feature]` is unsafe and requires unsafe function or block + --> $DIR/safe-calls.rs:65:18 + | +LL | const name: () = sse2(); + | ^^^^^^ call to function with `#[target_feature]` + | + = note: can only be called if the required target features are available + +error: aborting due to 10 previous errors + +For more information about this error, try `rustc --explain E0133`. diff --git a/src/test/ui/rfcs/rfc-2396-target_feature-11/trait-impl.rs b/src/test/ui/rfcs/rfc-2396-target_feature-11/trait-impl.rs new file mode 100644 index 000000000..7314fa8cc --- /dev/null +++ b/src/test/ui/rfcs/rfc-2396-target_feature-11/trait-impl.rs @@ -0,0 +1,21 @@ +// only-x86_64 + +#![feature(target_feature_11)] + +trait Foo { + fn foo(&self); + unsafe fn unsf_foo(&self); +} + +struct Bar; + +impl Foo for Bar { + #[target_feature(enable = "sse2")] + //~^ ERROR cannot be applied to safe trait method + fn foo(&self) {} + + #[target_feature(enable = "sse2")] + unsafe fn unsf_foo(&self) {} +} + +fn main() {} diff --git a/src/test/ui/rfcs/rfc-2396-target_feature-11/trait-impl.stderr b/src/test/ui/rfcs/rfc-2396-target_feature-11/trait-impl.stderr new file mode 100644 index 000000000..07d6e0900 --- /dev/null +++ b/src/test/ui/rfcs/rfc-2396-target_feature-11/trait-impl.stderr @@ -0,0 +1,11 @@ +error: `#[target_feature(..)]` cannot be applied to safe trait method + --> $DIR/trait-impl.rs:13:5 + | +LL | #[target_feature(enable = "sse2")] + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ cannot be applied to safe trait method +LL | +LL | fn foo(&self) {} + | ------------- not an `unsafe` function + +error: aborting due to previous error + diff --git a/src/test/ui/rfcs/rfc-2421-unreserve-pure-offsetof-sizeof-alignof.rs b/src/test/ui/rfcs/rfc-2421-unreserve-pure-offsetof-sizeof-alignof.rs new file mode 100644 index 000000000..6d7bca4da --- /dev/null +++ b/src/test/ui/rfcs/rfc-2421-unreserve-pure-offsetof-sizeof-alignof.rs @@ -0,0 +1,15 @@ +// run-pass +#![allow(dead_code)] +#![allow(unused_variables)] +// Test that removed keywords are allowed as identifiers. +fn main () { + let offsetof = (); + let alignof = (); + let sizeof = (); + let pure = (); +} + +fn offsetof() {} +fn alignof() {} +fn sizeof() {} +fn pure() {} diff --git a/src/test/ui/rfcs/rfc-2528-type-changing-struct-update/coerce-in-base-expr.rs b/src/test/ui/rfcs/rfc-2528-type-changing-struct-update/coerce-in-base-expr.rs new file mode 100644 index 000000000..75e48bf4a --- /dev/null +++ b/src/test/ui/rfcs/rfc-2528-type-changing-struct-update/coerce-in-base-expr.rs @@ -0,0 +1,28 @@ +// check-pass + +#![feature(type_changing_struct_update)] +#![allow(incomplete_features)] + +use std::any::Any; + +struct Foo<A, B: ?Sized, C: ?Sized> { + a: A, + b: Box<B>, + c: Box<C>, +} + +struct B; +struct C; + +fn main() { + let y = Foo::<usize, dyn Any, dyn Any> { + a: 0, + b: Box::new(B), + ..Foo { + a: 0, + b: Box::new(B), + // C needs to be told to coerce to `Box<dyn Any>` + c: Box::new(C), + } + }; +} diff --git a/src/test/ui/rfcs/rfc-2528-type-changing-struct-update/feature-gate.rs b/src/test/ui/rfcs/rfc-2528-type-changing-struct-update/feature-gate.rs new file mode 100644 index 000000000..1e8b99ba5 --- /dev/null +++ b/src/test/ui/rfcs/rfc-2528-type-changing-struct-update/feature-gate.rs @@ -0,0 +1,29 @@ +// gate-test-type_changing_struct_update + +#[derive(Debug)] +struct Machine<S> { + state: S, + common_field1: &'static str, + common_field2: i32, +} +#[derive(Debug)] +struct State1; +#[derive(Debug, PartialEq)] +struct State2; + +fn update_to_state2() { + let m1: Machine<State1> = Machine { + state: State1, + common_field1: "hello", + common_field2: 2, + }; + let m2: Machine<State2> = Machine { + state: State2, + ..m1 + //~^ ERROR type changing struct updating is experimental [E0658] + //~| ERROR mismatched types [E0308] + }; + assert_eq!(State2, m2.state); +} + +fn main() {} diff --git a/src/test/ui/rfcs/rfc-2528-type-changing-struct-update/feature-gate.stderr b/src/test/ui/rfcs/rfc-2528-type-changing-struct-update/feature-gate.stderr new file mode 100644 index 000000000..2217b8c04 --- /dev/null +++ b/src/test/ui/rfcs/rfc-2528-type-changing-struct-update/feature-gate.stderr @@ -0,0 +1,22 @@ +error[E0658]: type changing struct updating is experimental + --> $DIR/feature-gate.rs:22:11 + | +LL | ..m1 + | ^^ + | + = note: see issue #86555 <https://github.com/rust-lang/rust/issues/86555> for more information + = help: add `#![feature(type_changing_struct_update)]` to the crate attributes to enable + +error[E0308]: mismatched types + --> $DIR/feature-gate.rs:22:11 + | +LL | ..m1 + | ^^ expected struct `State2`, found struct `State1` + | + = note: expected struct `Machine<State2>` + found struct `Machine<State1>` + +error: aborting due to 2 previous errors + +Some errors have detailed explanations: E0308, E0658. +For more information about an error, try `rustc --explain E0308`. diff --git a/src/test/ui/rfcs/rfc-2528-type-changing-struct-update/issue-92010-trait-bound-not-satisfied.rs b/src/test/ui/rfcs/rfc-2528-type-changing-struct-update/issue-92010-trait-bound-not-satisfied.rs new file mode 100644 index 000000000..f1a54ee58 --- /dev/null +++ b/src/test/ui/rfcs/rfc-2528-type-changing-struct-update/issue-92010-trait-bound-not-satisfied.rs @@ -0,0 +1,12 @@ +#[derive(Clone)] +struct P<T> { + x: T, + y: f64, +} + +impl<T> P<T> { + fn y(&self, y: f64) -> Self { P{y, .. self.clone() } } + //~^ mismatched types [E0308] +} + +fn main() {} diff --git a/src/test/ui/rfcs/rfc-2528-type-changing-struct-update/issue-92010-trait-bound-not-satisfied.stderr b/src/test/ui/rfcs/rfc-2528-type-changing-struct-update/issue-92010-trait-bound-not-satisfied.stderr new file mode 100644 index 000000000..5957ea7c9 --- /dev/null +++ b/src/test/ui/rfcs/rfc-2528-type-changing-struct-update/issue-92010-trait-bound-not-satisfied.stderr @@ -0,0 +1,12 @@ +error[E0308]: mismatched types + --> $DIR/issue-92010-trait-bound-not-satisfied.rs:8:43 + | +LL | fn y(&self, y: f64) -> Self { P{y, .. self.clone() } } + | ^^^^^^^^^^^^ expected struct `P`, found `&P<T>` + | + = note: expected struct `P<T>` + found reference `&P<T>` + +error: aborting due to previous error + +For more information about this error, try `rustc --explain E0308`. diff --git a/src/test/ui/rfcs/rfc-2528-type-changing-struct-update/issue-96878.rs b/src/test/ui/rfcs/rfc-2528-type-changing-struct-update/issue-96878.rs new file mode 100644 index 000000000..3dfbef0ee --- /dev/null +++ b/src/test/ui/rfcs/rfc-2528-type-changing-struct-update/issue-96878.rs @@ -0,0 +1,31 @@ +// check-pass + +#![feature(type_changing_struct_update)] +#![allow(incomplete_features)] + +use std::borrow::Cow; +use std::marker::PhantomData; + +#[derive(Default)] +struct NonGeneric { + field1: usize, +} + +#[derive(Default)] +struct Generic<T, U> { + field1: T, + field2: U, +} + +#[derive(Default)] +struct MoreGeneric<'a, const N: usize> { + // If only `for<const N: usize> [u32; N]: Default`... + field1: PhantomData<[u32; N]>, + field2: Cow<'a, str>, +} + +fn main() { + let default1 = NonGeneric { ..Default::default() }; + let default2: Generic<i32, f32> = Generic { ..Default::default() }; + let default3: MoreGeneric<'static, 12> = MoreGeneric { ..Default::default() }; +} diff --git a/src/test/ui/rfcs/rfc-2528-type-changing-struct-update/lifetime-update.rs b/src/test/ui/rfcs/rfc-2528-type-changing-struct-update/lifetime-update.rs new file mode 100644 index 000000000..df2fef55d --- /dev/null +++ b/src/test/ui/rfcs/rfc-2528-type-changing-struct-update/lifetime-update.rs @@ -0,0 +1,43 @@ +#![feature(type_changing_struct_update)] +#![allow(incomplete_features)] + +#[derive(Clone)] +struct Machine<'a, S> { + state: S, + lt_str: &'a str, + common_field: i32, +} + +#[derive(Clone)] +struct State1; +#[derive(Clone)] +struct State2; + +fn update_to_state2() { + let s = String::from("hello"); + let m1: Machine<State1> = Machine { + state: State1, + lt_str: &s, + //~^ ERROR `s` does not live long enough [E0597] + // FIXME: The error here actually comes from line 34. The + // span of the error message should be corrected to line 34 + common_field: 2, + }; + // update lifetime + let m3: Machine<'static, State1> = Machine { + lt_str: "hello, too", + ..m1.clone() + }; + // update lifetime and type + let m4: Machine<'static, State2> = Machine { + state: State2, + lt_str: "hello, again", + ..m1.clone() + }; + // updating to `static should fail. + let m2: Machine<'static, State1> = Machine { + ..m1 + }; +} + +fn main() {} diff --git a/src/test/ui/rfcs/rfc-2528-type-changing-struct-update/lifetime-update.stderr b/src/test/ui/rfcs/rfc-2528-type-changing-struct-update/lifetime-update.stderr new file mode 100644 index 000000000..5f93ad6e0 --- /dev/null +++ b/src/test/ui/rfcs/rfc-2528-type-changing-struct-update/lifetime-update.stderr @@ -0,0 +1,15 @@ +error[E0597]: `s` does not live long enough + --> $DIR/lifetime-update.rs:20:17 + | +LL | lt_str: &s, + | ^^ borrowed value does not live long enough +... +LL | let m2: Machine<'static, State1> = Machine { + | ------------------------ type annotation requires that `s` is borrowed for `'static` +... +LL | } + | - `s` dropped here while still borrowed + +error: aborting due to previous error + +For more information about this error, try `rustc --explain E0597`. diff --git a/src/test/ui/rfcs/rfc-2528-type-changing-struct-update/type-generic-update.rs b/src/test/ui/rfcs/rfc-2528-type-changing-struct-update/type-generic-update.rs new file mode 100644 index 000000000..dae1241d3 --- /dev/null +++ b/src/test/ui/rfcs/rfc-2528-type-changing-struct-update/type-generic-update.rs @@ -0,0 +1,56 @@ +#![feature(type_changing_struct_update)] +#![allow(incomplete_features)] + +struct Machine<'a, S, M> { + state: S, + message: M, + lt_str: &'a str, + common_field: i32, +} + +struct State1; +struct State2; + +struct Message1; +struct Message2; + +fn update() { + let m1: Machine<State1, Message1> = Machine { + state: State1, + message: Message1, + lt_str: "hello", + common_field: 2, + }; + // single type update + let m2: Machine<State2, Message1> = Machine { + state: State2, + ..m1 + }; + // multiple type update + let m3: Machine<State2, Message2> = Machine { + state: State2, + message: Message2, + ..m1 + }; +} + +fn fail_update() { + let m1: Machine<f64, f64> = Machine { + state: 3.2, + message: 6.4, + lt_str: "hello", + common_field: 2, + }; + // single type update fail + let m2: Machine<i32, f64> = Machine { + ..m1 + //~^ ERROR mismatched types [E0308] + }; + // multiple type update fail + let m3 = Machine::<i32, i32> { + ..m1 + //~^ ERROR mismatched types [E0308] + }; +} + +fn main() {} diff --git a/src/test/ui/rfcs/rfc-2528-type-changing-struct-update/type-generic-update.stderr b/src/test/ui/rfcs/rfc-2528-type-changing-struct-update/type-generic-update.stderr new file mode 100644 index 000000000..6f31b1a96 --- /dev/null +++ b/src/test/ui/rfcs/rfc-2528-type-changing-struct-update/type-generic-update.stderr @@ -0,0 +1,21 @@ +error[E0308]: mismatched types + --> $DIR/type-generic-update.rs:46:11 + | +LL | ..m1 + | ^^ expected `i32`, found `f64` + | + = note: expected struct `Machine<'_, i32, _>` + found struct `Machine<'_, f64, _>` + +error[E0308]: mismatched types + --> $DIR/type-generic-update.rs:51:11 + | +LL | ..m1 + | ^^ expected `i32`, found `f64` + | + = note: expected struct `Machine<'_, i32, i32>` + found struct `Machine<'_, f64, f64>` + +error: aborting due to 2 previous errors + +For more information about this error, try `rustc --explain E0308`. diff --git a/src/test/ui/rfcs/rfc1445/eq-allows-match-on-ty-in-macro.rs b/src/test/ui/rfcs/rfc1445/eq-allows-match-on-ty-in-macro.rs new file mode 100644 index 000000000..17174e22c --- /dev/null +++ b/src/test/ui/rfcs/rfc1445/eq-allows-match-on-ty-in-macro.rs @@ -0,0 +1,23 @@ +// run-pass +#![allow(dead_code)] + +macro_rules! foo { + (#[$attr:meta] $x:ident) => { + #[$attr] + struct $x { + x: u32 + } + } +} + +foo! { #[derive(PartialEq, Eq)] Foo } + +const FOO: Foo = Foo { x: 0 }; + +fn main() { + let y = Foo { x: 1 }; + match y { + FOO => { } + _ => { } + } +} diff --git a/src/test/ui/rfcs/rfc1445/eq-allows-match.rs b/src/test/ui/rfcs/rfc1445/eq-allows-match.rs new file mode 100644 index 000000000..405a69c94 --- /dev/null +++ b/src/test/ui/rfcs/rfc1445/eq-allows-match.rs @@ -0,0 +1,17 @@ +// run-pass +#![allow(dead_code)] + +#[derive(PartialEq, Eq)] +struct Foo { + x: u32 +} + +const FOO: Foo = Foo { x: 0 }; + +fn main() { + let y = Foo { x: 1 }; + match y { + FOO => { } + _ => { } + } +} diff --git a/src/test/ui/rfcs/rfc1623.rs b/src/test/ui/rfcs/rfc1623.rs new file mode 100644 index 000000000..adaf25c6b --- /dev/null +++ b/src/test/ui/rfcs/rfc1623.rs @@ -0,0 +1,75 @@ +// run-pass +#![allow(unused_variables)] +#![allow(non_upper_case_globals)] + +#![allow(dead_code)] + +// very simple test for a 'static static with default lifetime +static STATIC_STR: &str = "&'static str"; +const CONST_STR: &str = "&'static str"; + +// this should be the same as without default: +static EXPLICIT_STATIC_STR: &'static str = "&'static str"; +const EXPLICIT_CONST_STR: &'static str = "&'static str"; + +// a function that elides to an unbound lifetime for both in- and output +fn id_u8_slice(arg: &[u8]) -> &[u8] { + arg +} + +// one with a function, argument elided +static STATIC_SIMPLE_FN: &fn(&[u8]) -> &[u8] = &(id_u8_slice as fn(&[u8]) -> &[u8]); +const CONST_SIMPLE_FN: &fn(&[u8]) -> &[u8] = &(id_u8_slice as fn(&[u8]) -> &[u8]); + +// this should be the same as without elision +static STATIC_NON_ELIDED_fN: &for<'a> fn(&'a [u8]) -> &'a [u8] = + &(id_u8_slice as for<'a> fn(&'a [u8]) -> &'a [u8]); +const CONST_NON_ELIDED_fN: &for<'a> fn(&'a [u8]) -> &'a [u8] = + &(id_u8_slice as for<'a> fn(&'a [u8]) -> &'a [u8]); + +// another function that elides, each to a different unbound lifetime +fn multi_args(a: &u8, b: &u8, c: &u8) {} + +static STATIC_MULTI_FN: &fn(&u8, &u8, &u8) = &(multi_args as fn(&u8, &u8, &u8)); +const CONST_MULTI_FN: &fn(&u8, &u8, &u8) = &(multi_args as fn(&u8, &u8, &u8)); + +struct Foo<'a> { + bools: &'a [bool], +} + +static STATIC_FOO: Foo = Foo { bools: &[true, false] }; +const CONST_FOO: Foo = Foo { bools: &[true, false] }; + +type Bar<'a> = Foo<'a>; + +static STATIC_BAR: Bar = Bar { bools: &[true, false] }; +const CONST_BAR: Bar = Bar { bools: &[true, false] }; + +type Baz<'a> = fn(&'a [u8]) -> Option<u8>; + +fn baz(e: &[u8]) -> Option<u8> { + e.first().map(|x| *x) +} + +static STATIC_BAZ: &Baz = &(baz as Baz); +const CONST_BAZ: &Baz = &(baz as Baz); + +static BYTES: &[u8] = &[1, 2, 3]; + +fn main() { + // make sure that the lifetime is actually elided (and not defaulted) + let x = &[1u8, 2, 3]; + STATIC_SIMPLE_FN(x); + CONST_SIMPLE_FN(x); + + STATIC_BAZ(BYTES); // neees static lifetime + CONST_BAZ(BYTES); + + // make sure this works with different lifetimes + let a = &1; + { + let b = &2; + let c = &3; + CONST_MULTI_FN(a, b, c); + } +} diff --git a/src/test/ui/rfcs/rfc1717/library-override.rs b/src/test/ui/rfcs/rfc1717/library-override.rs new file mode 100644 index 000000000..014ccac31 --- /dev/null +++ b/src/test/ui/rfcs/rfc1717/library-override.rs @@ -0,0 +1,14 @@ +// run-pass +// ignore-wasm32-bare no libc to test ffi with +// compile-flags: -lstatic=wronglibrary:rust_test_helpers + +#[link(name = "wronglibrary", kind = "dylib")] +extern "C" { + pub fn rust_dbg_extern_identity_u32(x: u32) -> u32; +} + +fn main() { + unsafe { + rust_dbg_extern_identity_u32(42); + } +} diff --git a/src/test/ui/rfcs/rfc1857-drop-order.rs b/src/test/ui/rfcs/rfc1857-drop-order.rs new file mode 100644 index 000000000..243b7fb6f --- /dev/null +++ b/src/test/ui/rfcs/rfc1857-drop-order.rs @@ -0,0 +1,225 @@ +// run-pass +// needs-unwind +// ignore-wasm32-bare compiled with panic=abort by default + +#![allow(dead_code, unreachable_code)] + +use std::cell::RefCell; +use std::rc::Rc; +use std::panic::{self, AssertUnwindSafe, UnwindSafe}; + +// This struct is used to record the order in which elements are dropped +struct PushOnDrop { + vec: Rc<RefCell<Vec<u32>>>, + val: u32 +} + +impl PushOnDrop { + fn new(val: u32, vec: Rc<RefCell<Vec<u32>>>) -> PushOnDrop { + PushOnDrop { vec, val } + } +} + +impl Drop for PushOnDrop { + fn drop(&mut self) { + self.vec.borrow_mut().push(self.val) + } +} + +impl UnwindSafe for PushOnDrop { } + +// Structs +struct TestStruct { + x: PushOnDrop, + y: PushOnDrop, + z: PushOnDrop +} + +// Tuple structs +struct TestTupleStruct(PushOnDrop, PushOnDrop, PushOnDrop); + +// Enum variants +enum TestEnum { + Tuple(PushOnDrop, PushOnDrop, PushOnDrop), + Struct { x: PushOnDrop, y: PushOnDrop, z: PushOnDrop } +} + +fn test_drop_tuple() { + // Tuple fields are dropped in the same order they are declared + let dropped_fields = Rc::new(RefCell::new(Vec::new())); + let test_tuple = (PushOnDrop::new(1, dropped_fields.clone()), + PushOnDrop::new(2, dropped_fields.clone())); + drop(test_tuple); + assert_eq!(*dropped_fields.borrow(), &[1, 2]); + + // Panic during construction means that fields are treated as local variables + // Therefore they are dropped in reverse order of initialization + let dropped_fields = Rc::new(RefCell::new(Vec::new())); + let cloned = AssertUnwindSafe(dropped_fields.clone()); + panic::catch_unwind(|| { + (PushOnDrop::new(2, cloned.clone()), + PushOnDrop::new(1, cloned.clone()), + panic!("this panic is caught :D")); + }).err().unwrap(); + assert_eq!(*dropped_fields.borrow(), &[1, 2]); +} + +fn test_drop_struct() { + // Struct fields are dropped in the same order they are declared + let dropped_fields = Rc::new(RefCell::new(Vec::new())); + let test_struct = TestStruct { + x: PushOnDrop::new(1, dropped_fields.clone()), + y: PushOnDrop::new(2, dropped_fields.clone()), + z: PushOnDrop::new(3, dropped_fields.clone()), + }; + drop(test_struct); + assert_eq!(*dropped_fields.borrow(), &[1, 2, 3]); + + // The same holds for tuple structs + let dropped_fields = Rc::new(RefCell::new(Vec::new())); + let test_tuple_struct = TestTupleStruct(PushOnDrop::new(1, dropped_fields.clone()), + PushOnDrop::new(2, dropped_fields.clone()), + PushOnDrop::new(3, dropped_fields.clone())); + drop(test_tuple_struct); + assert_eq!(*dropped_fields.borrow(), &[1, 2, 3]); + + // Panic during struct construction means that fields are treated as local variables + // Therefore they are dropped in reverse order of initialization + let dropped_fields = Rc::new(RefCell::new(Vec::new())); + let cloned = AssertUnwindSafe(dropped_fields.clone()); + panic::catch_unwind(|| { + TestStruct { + x: PushOnDrop::new(2, cloned.clone()), + y: PushOnDrop::new(1, cloned.clone()), + z: panic!("this panic is caught :D") + }; + }).err().unwrap(); + assert_eq!(*dropped_fields.borrow(), &[1, 2]); + + // Test with different initialization order + let dropped_fields = Rc::new(RefCell::new(Vec::new())); + let cloned = AssertUnwindSafe(dropped_fields.clone()); + panic::catch_unwind(|| { + TestStruct { + y: PushOnDrop::new(2, cloned.clone()), + x: PushOnDrop::new(1, cloned.clone()), + z: panic!("this panic is caught :D") + }; + }).err().unwrap(); + assert_eq!(*dropped_fields.borrow(), &[1, 2]); + + // The same holds for tuple structs + let dropped_fields = Rc::new(RefCell::new(Vec::new())); + let cloned = AssertUnwindSafe(dropped_fields.clone()); + panic::catch_unwind(|| { + TestTupleStruct(PushOnDrop::new(2, cloned.clone()), + PushOnDrop::new(1, cloned.clone()), + panic!("this panic is caught :D")); + }).err().unwrap(); + assert_eq!(*dropped_fields.borrow(), &[1, 2]); +} + +fn test_drop_enum() { + // Enum variants are dropped in the same order they are declared + let dropped_fields = Rc::new(RefCell::new(Vec::new())); + let test_struct_enum = TestEnum::Struct { + x: PushOnDrop::new(1, dropped_fields.clone()), + y: PushOnDrop::new(2, dropped_fields.clone()), + z: PushOnDrop::new(3, dropped_fields.clone()) + }; + drop(test_struct_enum); + assert_eq!(*dropped_fields.borrow(), &[1, 2, 3]); + + // The same holds for tuple enum variants + let dropped_fields = Rc::new(RefCell::new(Vec::new())); + let test_tuple_enum = TestEnum::Tuple(PushOnDrop::new(1, dropped_fields.clone()), + PushOnDrop::new(2, dropped_fields.clone()), + PushOnDrop::new(3, dropped_fields.clone())); + drop(test_tuple_enum); + assert_eq!(*dropped_fields.borrow(), &[1, 2, 3]); + + // Panic during enum construction means that fields are treated as local variables + // Therefore they are dropped in reverse order of initialization + let dropped_fields = Rc::new(RefCell::new(Vec::new())); + let cloned = AssertUnwindSafe(dropped_fields.clone()); + panic::catch_unwind(|| { + TestEnum::Struct { + x: PushOnDrop::new(2, cloned.clone()), + y: PushOnDrop::new(1, cloned.clone()), + z: panic!("this panic is caught :D") + }; + }).err().unwrap(); + assert_eq!(*dropped_fields.borrow(), &[1, 2]); + + // Test with different initialization order + let dropped_fields = Rc::new(RefCell::new(Vec::new())); + let cloned = AssertUnwindSafe(dropped_fields.clone()); + panic::catch_unwind(|| { + TestEnum::Struct { + y: PushOnDrop::new(2, cloned.clone()), + x: PushOnDrop::new(1, cloned.clone()), + z: panic!("this panic is caught :D") + }; + }).err().unwrap(); + assert_eq!(*dropped_fields.borrow(), &[1, 2]); + + // The same holds for tuple enum variants + let dropped_fields = Rc::new(RefCell::new(Vec::new())); + let cloned = AssertUnwindSafe(dropped_fields.clone()); + panic::catch_unwind(|| { + TestEnum::Tuple(PushOnDrop::new(2, cloned.clone()), + PushOnDrop::new(1, cloned.clone()), + panic!("this panic is caught :D")); + }).err().unwrap(); + assert_eq!(*dropped_fields.borrow(), &[1, 2]); +} + +fn test_drop_list() { + // Elements in a Vec are dropped in the same order they are pushed + let dropped_fields = Rc::new(RefCell::new(Vec::new())); + let xs = vec![PushOnDrop::new(1, dropped_fields.clone()), + PushOnDrop::new(2, dropped_fields.clone()), + PushOnDrop::new(3, dropped_fields.clone())]; + drop(xs); + assert_eq!(*dropped_fields.borrow(), &[1, 2, 3]); + + // The same holds for arrays + let dropped_fields = Rc::new(RefCell::new(Vec::new())); + let xs = [PushOnDrop::new(1, dropped_fields.clone()), + PushOnDrop::new(2, dropped_fields.clone()), + PushOnDrop::new(3, dropped_fields.clone())]; + drop(xs); + assert_eq!(*dropped_fields.borrow(), &[1, 2, 3]); + + // Panic during vec construction means that fields are treated as local variables + // Therefore they are dropped in reverse order of initialization + let dropped_fields = Rc::new(RefCell::new(Vec::new())); + let cloned = AssertUnwindSafe(dropped_fields.clone()); + panic::catch_unwind(|| { + vec![ + PushOnDrop::new(2, cloned.clone()), + PushOnDrop::new(1, cloned.clone()), + panic!("this panic is caught :D") + ]; + }).err().unwrap(); + assert_eq!(*dropped_fields.borrow(), &[1, 2]); + + // The same holds for arrays + let dropped_fields = Rc::new(RefCell::new(Vec::new())); + let cloned = AssertUnwindSafe(dropped_fields.clone()); + panic::catch_unwind(|| { + [ + PushOnDrop::new(2, cloned.clone()), + PushOnDrop::new(1, cloned.clone()), + panic!("this panic is caught :D") + ]; + }).err().unwrap(); + assert_eq!(*dropped_fields.borrow(), &[1, 2]); +} + +fn main() { + test_drop_tuple(); + test_drop_struct(); + test_drop_enum(); + test_drop_list(); +} |