diff options
Diffstat (limited to 'tests/ui/rfcs')
543 files changed, 16490 insertions, 83 deletions
diff --git a/tests/ui/rfcs/rfc-0107-bind-by-move-pattern-guards/bind-by-move-no-guards.rs b/tests/ui/rfcs/rfc-0107-bind-by-move-pattern-guards/bind-by-move-no-guards.rs new file mode 100644 index 000000000..1e086160f --- /dev/null +++ b/tests/ui/rfcs/rfc-0107-bind-by-move-pattern-guards/bind-by-move-no-guards.rs @@ -0,0 +1,19 @@ +// Adaptation of existing ui test (from way back in +// rust-lang/rust#2329), that starts passing with this feature in +// place. + +// run-pass + +use std::sync::mpsc::channel; + +fn main() { + let (tx, rx) = channel(); + let x = Some(rx); + tx.send(false).unwrap(); + tx.send(false).unwrap(); + match x { + Some(z) if z.recv().unwrap() => { panic!() }, + Some(z) => { assert!(!z.recv().unwrap()); }, + None => panic!() + } +} diff --git a/tests/ui/rfcs/rfc-0107-bind-by-move-pattern-guards/former-E0008-now-pass.rs b/tests/ui/rfcs/rfc-0107-bind-by-move-pattern-guards/former-E0008-now-pass.rs new file mode 100644 index 000000000..3161d6fbb --- /dev/null +++ b/tests/ui/rfcs/rfc-0107-bind-by-move-pattern-guards/former-E0008-now-pass.rs @@ -0,0 +1,11 @@ +// This test used to emit E0008 but now passed since `bind_by_move_pattern_guards` +// have been stabilized. + +// check-pass + +fn main() { + match Some("hi".to_string()) { + Some(s) if s.len() == 0 => {}, + _ => {}, + } +} diff --git a/tests/ui/rfcs/rfc-0107-bind-by-move-pattern-guards/rfc-basic-examples.rs b/tests/ui/rfcs/rfc-0107-bind-by-move-pattern-guards/rfc-basic-examples.rs new file mode 100644 index 000000000..b716fc870 --- /dev/null +++ b/tests/ui/rfcs/rfc-0107-bind-by-move-pattern-guards/rfc-basic-examples.rs @@ -0,0 +1,43 @@ +// run-pass + +struct A { a: Box<i32> } + +impl A { + fn get(&self) -> i32 { *self.a } +} + +fn foo(n: i32) -> i32 { + let x = A { a: Box::new(n) }; + let y = match x { + A { a: v } if *v == 42 => v, + _ => Box::new(0), + }; + *y +} + +fn bar(n: i32) -> i32 { + let x = A { a: Box::new(n) }; + let y = match x { + A { a: v } if x.get() == 42 => v, + _ => Box::new(0), + }; + *y +} + +fn baz(n: i32) -> i32 { + let x = A { a: Box::new(n) }; + let y = match x { + A { a: v } if *v.clone() == 42 => v, + _ => Box::new(0), + }; + *y +} + +fn main() { + assert_eq!(foo(107), 0); + assert_eq!(foo(42), 42); + assert_eq!(bar(107), 0); + assert_eq!(bar(42), 42); + assert_eq!(baz(107), 0); + assert_eq!(baz(42), 42); +} diff --git a/tests/ui/rfcs/rfc-0107-bind-by-move-pattern-guards/rfc-reject-double-move-across-arms.rs b/tests/ui/rfcs/rfc-0107-bind-by-move-pattern-guards/rfc-reject-double-move-across-arms.rs new file mode 100644 index 000000000..6f0d2b045 --- /dev/null +++ b/tests/ui/rfcs/rfc-0107-bind-by-move-pattern-guards/rfc-reject-double-move-across-arms.rs @@ -0,0 +1,24 @@ +#![feature(if_let_guard)] + +enum VecWrapper { A(Vec<i32>) } + +fn if_guard(x: VecWrapper) -> usize { + match x { + VecWrapper::A(v) if { drop(v); false } => 1, + //~^ ERROR cannot move out of `v` in pattern guard + VecWrapper::A(v) => v.len() + } +} + +fn if_let_guard(x: VecWrapper) -> usize { + match x { + VecWrapper::A(v) if let Some(()) = { drop(v); None } => 1, + //~^ ERROR cannot move out of `v` in pattern guard + VecWrapper::A(v) => v.len() + } +} + +fn main() { + if_guard(VecWrapper::A(vec![107])); + if_let_guard(VecWrapper::A(vec![107])); +} diff --git a/tests/ui/rfcs/rfc-0107-bind-by-move-pattern-guards/rfc-reject-double-move-across-arms.stderr b/tests/ui/rfcs/rfc-0107-bind-by-move-pattern-guards/rfc-reject-double-move-across-arms.stderr new file mode 100644 index 000000000..a749361bf --- /dev/null +++ b/tests/ui/rfcs/rfc-0107-bind-by-move-pattern-guards/rfc-reject-double-move-across-arms.stderr @@ -0,0 +1,19 @@ +error[E0507]: cannot move out of `v` in pattern guard + --> $DIR/rfc-reject-double-move-across-arms.rs:7:36 + | +LL | VecWrapper::A(v) if { drop(v); false } => 1, + | ^ move occurs because `v` has type `Vec<i32>`, which does not implement the `Copy` trait + | + = note: variables bound in patterns cannot be moved from until after the end of the pattern guard + +error[E0507]: cannot move out of `v` in pattern guard + --> $DIR/rfc-reject-double-move-across-arms.rs:15:51 + | +LL | VecWrapper::A(v) if let Some(()) = { drop(v); None } => 1, + | ^ move occurs because `v` has type `Vec<i32>`, which does not implement the `Copy` trait + | + = note: variables bound in patterns cannot be moved from until after the end of the pattern guard + +error: aborting due to 2 previous errors + +For more information about this error, try `rustc --explain E0507`. diff --git a/tests/ui/rfcs/rfc-0107-bind-by-move-pattern-guards/rfc-reject-double-move-in-first-arm.rs b/tests/ui/rfcs/rfc-0107-bind-by-move-pattern-guards/rfc-reject-double-move-in-first-arm.rs new file mode 100644 index 000000000..827335f6a --- /dev/null +++ b/tests/ui/rfcs/rfc-0107-bind-by-move-pattern-guards/rfc-reject-double-move-in-first-arm.rs @@ -0,0 +1,26 @@ +#![feature(if_let_guard)] + +struct A { a: Box<i32> } + +fn if_guard(n: i32) { + let x = A { a: Box::new(n) }; + let _y = match x { + A { a: v } if { drop(v); true } => v, + //~^ ERROR cannot move out of `v` in pattern guard + _ => Box::new(0), + }; +} + +fn if_let_guard(n: i32) { + let x = A { a: Box::new(n) }; + let _y = match x { + A { a: v } if let Some(()) = { drop(v); Some(()) } => v, + //~^ ERROR cannot move out of `v` in pattern guard + _ => Box::new(0), + }; +} + +fn main() { + if_guard(107); + if_let_guard(107); +} diff --git a/tests/ui/rfcs/rfc-0107-bind-by-move-pattern-guards/rfc-reject-double-move-in-first-arm.stderr b/tests/ui/rfcs/rfc-0107-bind-by-move-pattern-guards/rfc-reject-double-move-in-first-arm.stderr new file mode 100644 index 000000000..9285492b2 --- /dev/null +++ b/tests/ui/rfcs/rfc-0107-bind-by-move-pattern-guards/rfc-reject-double-move-in-first-arm.stderr @@ -0,0 +1,19 @@ +error[E0507]: cannot move out of `v` in pattern guard + --> $DIR/rfc-reject-double-move-in-first-arm.rs:8:30 + | +LL | A { a: v } if { drop(v); true } => v, + | ^ move occurs because `v` has type `Box<i32>`, which does not implement the `Copy` trait + | + = note: variables bound in patterns cannot be moved from until after the end of the pattern guard + +error[E0507]: cannot move out of `v` in pattern guard + --> $DIR/rfc-reject-double-move-in-first-arm.rs:17:45 + | +LL | A { a: v } if let Some(()) = { drop(v); Some(()) } => v, + | ^ move occurs because `v` has type `Box<i32>`, which does not implement the `Copy` trait + | + = note: variables bound in patterns cannot be moved from until after the end of the pattern guard + +error: aborting due to 2 previous errors + +For more information about this error, try `rustc --explain E0507`. diff --git a/tests/ui/rfcs/rfc-1014-2.rs b/tests/ui/rfcs/rfc-1014-stdout-existential-crisis/rfc-1014-2.rs index 7dd65701f..7dd65701f 100644 --- a/tests/ui/rfcs/rfc-1014-2.rs +++ b/tests/ui/rfcs/rfc-1014-stdout-existential-crisis/rfc-1014-2.rs diff --git a/tests/ui/rfcs/rfc-1014.rs b/tests/ui/rfcs/rfc-1014-stdout-existential-crisis/rfc-1014.rs index c454dfa4e..c454dfa4e 100644 --- a/tests/ui/rfcs/rfc-1014.rs +++ b/tests/ui/rfcs/rfc-1014-stdout-existential-crisis/rfc-1014.rs diff --git a/tests/ui/rfcs/rfc-1445-restrict-constants-in-patterns/allow-hide-behind-direct-unsafe-ptr-embedded.rs b/tests/ui/rfcs/rfc-1445-restrict-constants-in-patterns/allow-hide-behind-direct-unsafe-ptr-embedded.rs new file mode 100644 index 000000000..1914e1554 --- /dev/null +++ b/tests/ui/rfcs/rfc-1445-restrict-constants-in-patterns/allow-hide-behind-direct-unsafe-ptr-embedded.rs @@ -0,0 +1,26 @@ +// Test explores how `#[structral_match]` behaves in tandem with +// `*const` and `*mut` pointers. + +// run-pass + +#![warn(pointer_structural_match)] + +struct NoDerive(#[allow(unused_tuple_struct_fields)] i32); + +// This impl makes NoDerive irreflexive +// (which doesn't matter here because `<*const T>::eq` won't recur on `T`). +impl PartialEq for NoDerive { fn eq(&self, _: &Self) -> bool { false } } + +impl Eq for NoDerive { } + +#[derive(PartialEq, Eq)] +struct WrapEmbedded(*const NoDerive); + +const WRAP_UNSAFE_EMBEDDED: WrapEmbedded = WrapEmbedded(std::ptr::null()); + +fn main() { + match WRAP_UNSAFE_EMBEDDED { + WRAP_UNSAFE_EMBEDDED => { println!("WRAP_UNSAFE_EMBEDDED correctly matched itself"); } + _ => { panic!("WRAP_UNSAFE_EMBEDDED did not match itself"); } + } +} diff --git a/tests/ui/rfcs/rfc-1445-restrict-constants-in-patterns/allow-hide-behind-direct-unsafe-ptr-param.rs b/tests/ui/rfcs/rfc-1445-restrict-constants-in-patterns/allow-hide-behind-direct-unsafe-ptr-param.rs new file mode 100644 index 000000000..e713b003b --- /dev/null +++ b/tests/ui/rfcs/rfc-1445-restrict-constants-in-patterns/allow-hide-behind-direct-unsafe-ptr-param.rs @@ -0,0 +1,26 @@ +// Test explores how `#[structral_match]` behaves in tandem with +// `*const` and `*mut` pointers. + +// run-pass + +#![warn(pointer_structural_match)] + +struct NoDerive(#[allow(unused_tuple_struct_fields)] i32); + +// This impl makes NoDerive irreflexive +// (which doesn't matter here because `<*const T>::eq` won't recur on `T`). +impl PartialEq for NoDerive { fn eq(&self, _: &Self) -> bool { false } } + +impl Eq for NoDerive { } + +#[derive(PartialEq, Eq)] +struct WrapParam<X>(*const X); + +const WRAP_UNSAFE_PARAM: WrapParam<NoDerive> = WrapParam(std::ptr::null()); + +fn main() { + match WRAP_UNSAFE_PARAM { + WRAP_UNSAFE_PARAM => { println!("WRAP_UNSAFE_PARAM correctly matched itself"); } + _ => { panic!("WRAP_UNSAFE_PARAM did not match itself"); } + } +} diff --git a/tests/ui/rfcs/rfc-1445-restrict-constants-in-patterns/allow-hide-behind-indirect-unsafe-ptr-embedded.rs b/tests/ui/rfcs/rfc-1445-restrict-constants-in-patterns/allow-hide-behind-indirect-unsafe-ptr-embedded.rs new file mode 100644 index 000000000..04da14c54 --- /dev/null +++ b/tests/ui/rfcs/rfc-1445-restrict-constants-in-patterns/allow-hide-behind-indirect-unsafe-ptr-embedded.rs @@ -0,0 +1,26 @@ +// Test explores how `#[structral_match]` behaves in tandem with +// `*const` and `*mut` pointers. + +// run-pass + +#![warn(pointer_structural_match)] + +struct NoDerive(#[allow(unused_tuple_struct_fields)] i32); + +// This impl makes NoDerive irreflexive +// (which doesn't matter here because `<*const T>::eq` won't recur on `T`). +impl PartialEq for NoDerive { fn eq(&self, _: &Self) -> bool { false } } + +impl Eq for NoDerive { } + +#[derive(PartialEq, Eq)] +struct WrapEmbedded(*const NoDerive); + +const WRAP_UNSAFE_EMBEDDED: & &WrapEmbedded = & &WrapEmbedded(std::ptr::null()); + +fn main() { + match WRAP_UNSAFE_EMBEDDED { + WRAP_UNSAFE_EMBEDDED => { println!("WRAP_UNSAFE_EMBEDDED correctly matched itself"); } + _ => { panic!("WRAP_UNSAFE_EMBEDDED did not match itself"); } + } +} diff --git a/tests/ui/rfcs/rfc-1445-restrict-constants-in-patterns/allow-hide-behind-indirect-unsafe-ptr-param.rs b/tests/ui/rfcs/rfc-1445-restrict-constants-in-patterns/allow-hide-behind-indirect-unsafe-ptr-param.rs new file mode 100644 index 000000000..8313c25e7 --- /dev/null +++ b/tests/ui/rfcs/rfc-1445-restrict-constants-in-patterns/allow-hide-behind-indirect-unsafe-ptr-param.rs @@ -0,0 +1,26 @@ +// Test explores how `#[structral_match]` behaves in tandem with +// `*const` and `*mut` pointers. + +// run-pass + +#![warn(pointer_structural_match)] + +struct NoDerive(#[allow(unused_tuple_struct_fields)] i32); + +// This impl makes NoDerive irreflexive +// (which doesn't matter here because `<*const T>::eq` won't recur on `T`). +impl PartialEq for NoDerive { fn eq(&self, _: &Self) -> bool { false } } + +impl Eq for NoDerive { } + +#[derive(PartialEq, Eq)] +struct WrapParam<X>(*const X); + +const WRAP_UNSAFE_PARAM: & &WrapParam<NoDerive> = & &WrapParam(std::ptr::null()); + +fn main() { + match WRAP_UNSAFE_PARAM { + WRAP_UNSAFE_PARAM => { println!("WRAP_UNSAFE_PARAM correctly matched itself"); } + _ => { panic!("WRAP_UNSAFE_PARAM did not match itself"); } + } +} diff --git a/tests/ui/rfcs/rfc-1445-restrict-constants-in-patterns/allow-use-behind-cousin-variant.rs b/tests/ui/rfcs/rfc-1445-restrict-constants-in-patterns/allow-use-behind-cousin-variant.rs new file mode 100644 index 000000000..dca8aaef1 --- /dev/null +++ b/tests/ui/rfcs/rfc-1445-restrict-constants-in-patterns/allow-use-behind-cousin-variant.rs @@ -0,0 +1,59 @@ +// rust-lang/rust#62614: we want to allow matching on constants of types that +// have non-structural-match variants, *if* the constant itself does not use +// any such variant. + +// NOTE: for now, deliberately leaving the lint `indirect_structural_match` set +// to its default, so that we will not issue a diangostic even if +// rust-lang/rust#62614 remains an open issue. + +// run-pass + +struct Sum(u32, u32); + +impl PartialEq for Sum { + fn eq(&self, other: &Self) -> bool { self.0 + self.1 == other.0 + other.1 } +} + +impl Eq for Sum { } + +#[derive(PartialEq, Eq)] +enum Eek { + TheConst, + UnusedByTheConst(Sum) +} + +const THE_CONST: Eek = Eek::TheConst; +const SUM_THREE: Eek = Eek::UnusedByTheConst(Sum(3,0)); + +const EEK_ZERO: &[Eek] = &[]; +const EEK_ONE: &[Eek] = &[THE_CONST]; + +pub fn main() { + match Eek::UnusedByTheConst(Sum(1,2)) { + ref sum if sum == &SUM_THREE => { println!("Hello 0"); } + _ => { println!("Gbye"); } + } + + match Eek::TheConst { + THE_CONST => { println!("Hello 1"); } + _ => { println!("Gbye"); } + } + + + match & &Eek::TheConst { + & & THE_CONST => { println!("Hello 2"); } + _ => { println!("Gbye"); } + } + + match & & &[][..] { + & & EEK_ZERO => { println!("Hello 3"); } + & & EEK_ONE => { println!("Gbye"); } + _ => { println!("Gbye"); } + } + + match & & &[Eek::TheConst][..] { + & & EEK_ZERO => { println!("Gby"); } + & & EEK_ONE => { println!("Hello 4"); } + _ => { println!("Gbye"); } + } +} diff --git a/tests/ui/rfcs/rfc-1445-restrict-constants-in-patterns/cant-hide-behind-direct-struct-embedded.rs b/tests/ui/rfcs/rfc-1445-restrict-constants-in-patterns/cant-hide-behind-direct-struct-embedded.rs new file mode 100644 index 000000000..7623839fd --- /dev/null +++ b/tests/ui/rfcs/rfc-1445-restrict-constants-in-patterns/cant-hide-behind-direct-struct-embedded.rs @@ -0,0 +1,26 @@ +// This is part of a set of tests exploring the different ways a +// structural-match ADT might try to hold a +// non-structural-match in hidden manner that lets matches +// through that we had intended to reject. +// +// See discussion on rust-lang/rust#62307 and rust-lang/rust#62339 + +struct NoDerive(#[allow(unused_tuple_struct_fields)] i32); + +// This impl makes NoDerive irreflexive. +impl PartialEq for NoDerive { fn eq(&self, _: &Self) -> bool { false } } + +impl Eq for NoDerive { } + +#[derive(PartialEq, Eq)] +struct WrapInline(NoDerive); + +const WRAP_DIRECT_INLINE: WrapInline = WrapInline(NoDerive(0)); + +fn main() { + match WRAP_DIRECT_INLINE { + WRAP_DIRECT_INLINE => { panic!("WRAP_DIRECT_INLINE matched itself"); } + //~^ ERROR must be annotated with `#[derive(PartialEq, Eq)]` + _ => { println!("WRAP_DIRECT_INLINE did not match itself"); } + } +} diff --git a/tests/ui/rfcs/rfc-1445-restrict-constants-in-patterns/cant-hide-behind-direct-struct-embedded.stderr b/tests/ui/rfcs/rfc-1445-restrict-constants-in-patterns/cant-hide-behind-direct-struct-embedded.stderr new file mode 100644 index 000000000..f08ba522a --- /dev/null +++ b/tests/ui/rfcs/rfc-1445-restrict-constants-in-patterns/cant-hide-behind-direct-struct-embedded.stderr @@ -0,0 +1,11 @@ +error: to use a constant of type `NoDerive` in a pattern, `NoDerive` must be annotated with `#[derive(PartialEq, Eq)]` + --> $DIR/cant-hide-behind-direct-struct-embedded.rs:22:9 + | +LL | WRAP_DIRECT_INLINE => { panic!("WRAP_DIRECT_INLINE matched itself"); } + | ^^^^^^^^^^^^^^^^^^ + | + = note: the traits must be derived, manual `impl`s are not sufficient + = note: see https://doc.rust-lang.org/stable/std/marker/trait.StructuralEq.html for details + +error: aborting due to previous error + diff --git a/tests/ui/rfcs/rfc-1445-restrict-constants-in-patterns/cant-hide-behind-direct-struct-param.rs b/tests/ui/rfcs/rfc-1445-restrict-constants-in-patterns/cant-hide-behind-direct-struct-param.rs new file mode 100644 index 000000000..93022a23d --- /dev/null +++ b/tests/ui/rfcs/rfc-1445-restrict-constants-in-patterns/cant-hide-behind-direct-struct-param.rs @@ -0,0 +1,26 @@ +// This is part of a set of tests exploring the different ways a +// structural-match ADT might try to hold a +// non-structural-match in hidden manner that lets matches +// through that we had intended to reject. +// +// See discussion on rust-lang/rust#62307 and rust-lang/rust#62339 +#![warn(indirect_structural_match)] +struct NoDerive(i32); + +// This impl makes NoDerive irreflexive. +impl PartialEq for NoDerive { fn eq(&self, _: &Self) -> bool { false } } + +impl Eq for NoDerive { } + +#[derive(PartialEq, Eq)] +struct WrapParam<T>(T); + +const WRAP_DIRECT_PARAM: WrapParam<NoDerive> = WrapParam(NoDerive(0)); + +fn main() { + match WRAP_DIRECT_PARAM { + WRAP_DIRECT_PARAM => { panic!("WRAP_DIRECT_PARAM matched itself"); } + //~^ ERROR must be annotated with `#[derive(PartialEq, Eq)]` + _ => { println!("WRAP_DIRECT_PARAM did not match itself"); } + } +} diff --git a/tests/ui/rfcs/rfc-1445-restrict-constants-in-patterns/cant-hide-behind-direct-struct-param.stderr b/tests/ui/rfcs/rfc-1445-restrict-constants-in-patterns/cant-hide-behind-direct-struct-param.stderr new file mode 100644 index 000000000..012ccab17 --- /dev/null +++ b/tests/ui/rfcs/rfc-1445-restrict-constants-in-patterns/cant-hide-behind-direct-struct-param.stderr @@ -0,0 +1,11 @@ +error: to use a constant of type `NoDerive` in a pattern, `NoDerive` must be annotated with `#[derive(PartialEq, Eq)]` + --> $DIR/cant-hide-behind-direct-struct-param.rs:22:9 + | +LL | WRAP_DIRECT_PARAM => { panic!("WRAP_DIRECT_PARAM matched itself"); } + | ^^^^^^^^^^^^^^^^^ + | + = note: the traits must be derived, manual `impl`s are not sufficient + = note: see https://doc.rust-lang.org/stable/std/marker/trait.StructuralEq.html for details + +error: aborting due to previous error + diff --git a/tests/ui/rfcs/rfc-1445-restrict-constants-in-patterns/cant-hide-behind-doubly-indirect-embedded.rs b/tests/ui/rfcs/rfc-1445-restrict-constants-in-patterns/cant-hide-behind-doubly-indirect-embedded.rs new file mode 100644 index 000000000..894739ff7 --- /dev/null +++ b/tests/ui/rfcs/rfc-1445-restrict-constants-in-patterns/cant-hide-behind-doubly-indirect-embedded.rs @@ -0,0 +1,29 @@ +// This is part of a set of tests exploring the different ways a +// structural-match ADT might try to hold a +// non-structural-match in hidden manner that lets matches +// through that we had intended to reject. +// +// See discussion on rust-lang/rust#62307 and rust-lang/rust#62339 +#![warn(indirect_structural_match)] +// run-pass + +struct NoDerive(#[allow(unused_tuple_struct_fields)] i32); + +// This impl makes NoDerive irreflexive. +impl PartialEq for NoDerive { fn eq(&self, _: &Self) -> bool { false } } + +impl Eq for NoDerive { } + +#[derive(PartialEq, Eq)] +struct WrapInline<'a>(&'a &'a NoDerive); + +const WRAP_DOUBLY_INDIRECT_INLINE: & &WrapInline = & &WrapInline(& & NoDerive(0)); + +fn main() { + match WRAP_DOUBLY_INDIRECT_INLINE { + WRAP_DOUBLY_INDIRECT_INLINE => { panic!("WRAP_DOUBLY_INDIRECT_INLINE matched itself"); } + //~^ WARN must be annotated with `#[derive(PartialEq, Eq)]` + //~| WARN this was previously accepted + _ => { println!("WRAP_DOUBLY_INDIRECT_INLINE correctly did not match itself"); } + } +} diff --git a/tests/ui/rfcs/rfc-1445-restrict-constants-in-patterns/cant-hide-behind-doubly-indirect-embedded.stderr b/tests/ui/rfcs/rfc-1445-restrict-constants-in-patterns/cant-hide-behind-doubly-indirect-embedded.stderr new file mode 100644 index 000000000..94ee2216e --- /dev/null +++ b/tests/ui/rfcs/rfc-1445-restrict-constants-in-patterns/cant-hide-behind-doubly-indirect-embedded.stderr @@ -0,0 +1,18 @@ +warning: to use a constant of type `NoDerive` in a pattern, `NoDerive` must be annotated with `#[derive(PartialEq, Eq)]` + --> $DIR/cant-hide-behind-doubly-indirect-embedded.rs:24:9 + | +LL | WRAP_DOUBLY_INDIRECT_INLINE => { panic!("WRAP_DOUBLY_INDIRECT_INLINE matched itself"); } + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^ + | + = warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release! + = note: for more information, see issue #62411 <https://github.com/rust-lang/rust/issues/62411> + = note: the traits must be derived, manual `impl`s are not sufficient + = note: see https://doc.rust-lang.org/stable/std/marker/trait.StructuralEq.html for details +note: the lint level is defined here + --> $DIR/cant-hide-behind-doubly-indirect-embedded.rs:7:9 + | +LL | #![warn(indirect_structural_match)] + | ^^^^^^^^^^^^^^^^^^^^^^^^^ + +warning: 1 warning emitted + diff --git a/tests/ui/rfcs/rfc-1445-restrict-constants-in-patterns/cant-hide-behind-doubly-indirect-param.rs b/tests/ui/rfcs/rfc-1445-restrict-constants-in-patterns/cant-hide-behind-doubly-indirect-param.rs new file mode 100644 index 000000000..1699dae46 --- /dev/null +++ b/tests/ui/rfcs/rfc-1445-restrict-constants-in-patterns/cant-hide-behind-doubly-indirect-param.rs @@ -0,0 +1,29 @@ +// This is part of a set of tests exploring the different ways a +// structural-match ADT might try to hold a +// non-structural-match in hidden manner that lets matches +// through that we had intended to reject. +// +// See discussion on rust-lang/rust#62307 and rust-lang/rust#62339 +#![warn(indirect_structural_match)] +// run-pass + +struct NoDerive(#[allow(unused_tuple_struct_fields)] i32); + +// This impl makes NoDerive irreflexive. +impl PartialEq for NoDerive { fn eq(&self, _: &Self) -> bool { false } } + +impl Eq for NoDerive { } + +#[derive(PartialEq, Eq)] +struct WrapParam<'a, T>(&'a &'a T); + +const WRAP_DOUBLY_INDIRECT_PARAM: & &WrapParam<NoDerive> = & &WrapParam(& & NoDerive(0)); + +fn main() { + match WRAP_DOUBLY_INDIRECT_PARAM { + WRAP_DOUBLY_INDIRECT_PARAM => { panic!("WRAP_DOUBLY_INDIRECT_PARAM matched itself"); } + //~^ WARN must be annotated with `#[derive(PartialEq, Eq)]` + //~| WARN this was previously accepted + _ => { println!("WRAP_DOUBLY_INDIRECT_PARAM correctly did not match itself"); } + } +} diff --git a/tests/ui/rfcs/rfc-1445-restrict-constants-in-patterns/cant-hide-behind-doubly-indirect-param.stderr b/tests/ui/rfcs/rfc-1445-restrict-constants-in-patterns/cant-hide-behind-doubly-indirect-param.stderr new file mode 100644 index 000000000..666b7b95e --- /dev/null +++ b/tests/ui/rfcs/rfc-1445-restrict-constants-in-patterns/cant-hide-behind-doubly-indirect-param.stderr @@ -0,0 +1,18 @@ +warning: to use a constant of type `NoDerive` in a pattern, `NoDerive` must be annotated with `#[derive(PartialEq, Eq)]` + --> $DIR/cant-hide-behind-doubly-indirect-param.rs:24:9 + | +LL | WRAP_DOUBLY_INDIRECT_PARAM => { panic!("WRAP_DOUBLY_INDIRECT_PARAM matched itself"); } + | ^^^^^^^^^^^^^^^^^^^^^^^^^^ + | + = warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release! + = note: for more information, see issue #62411 <https://github.com/rust-lang/rust/issues/62411> + = note: the traits must be derived, manual `impl`s are not sufficient + = note: see https://doc.rust-lang.org/stable/std/marker/trait.StructuralEq.html for details +note: the lint level is defined here + --> $DIR/cant-hide-behind-doubly-indirect-param.rs:7:9 + | +LL | #![warn(indirect_structural_match)] + | ^^^^^^^^^^^^^^^^^^^^^^^^^ + +warning: 1 warning emitted + diff --git a/tests/ui/rfcs/rfc-1445-restrict-constants-in-patterns/cant-hide-behind-indirect-struct-embedded.rs b/tests/ui/rfcs/rfc-1445-restrict-constants-in-patterns/cant-hide-behind-indirect-struct-embedded.rs new file mode 100644 index 000000000..2672bdd9e --- /dev/null +++ b/tests/ui/rfcs/rfc-1445-restrict-constants-in-patterns/cant-hide-behind-indirect-struct-embedded.rs @@ -0,0 +1,29 @@ +// This is part of a set of tests exploring the different ways a +// structural-match ADT might try to hold a +// non-structural-match in hidden manner that lets matches +// through that we had intended to reject. +// +// See discussion on rust-lang/rust#62307 and rust-lang/rust#62339 +#![warn(indirect_structural_match)] +// run-pass + +struct NoDerive(#[allow(unused_tuple_struct_fields)] i32); + +// This impl makes NoDerive irreflexive. +impl PartialEq for NoDerive { fn eq(&self, _: &Self) -> bool { false } } + +impl Eq for NoDerive { } + +#[derive(PartialEq, Eq)] +struct WrapInline(NoDerive); + +const WRAP_INDIRECT_INLINE: & &WrapInline = & &WrapInline(NoDerive(0)); + +fn main() { + match WRAP_INDIRECT_INLINE { + WRAP_INDIRECT_INLINE => { panic!("WRAP_INDIRECT_INLINE matched itself"); } + //~^ WARN must be annotated with `#[derive(PartialEq, Eq)]` + //~| WARN this was previously accepted + _ => { println!("WRAP_INDIRECT_INLINE did not match itself"); } + } +} diff --git a/tests/ui/rfcs/rfc-1445-restrict-constants-in-patterns/cant-hide-behind-indirect-struct-embedded.stderr b/tests/ui/rfcs/rfc-1445-restrict-constants-in-patterns/cant-hide-behind-indirect-struct-embedded.stderr new file mode 100644 index 000000000..ecbe83f3d --- /dev/null +++ b/tests/ui/rfcs/rfc-1445-restrict-constants-in-patterns/cant-hide-behind-indirect-struct-embedded.stderr @@ -0,0 +1,18 @@ +warning: to use a constant of type `NoDerive` in a pattern, `NoDerive` must be annotated with `#[derive(PartialEq, Eq)]` + --> $DIR/cant-hide-behind-indirect-struct-embedded.rs:24:9 + | +LL | WRAP_INDIRECT_INLINE => { panic!("WRAP_INDIRECT_INLINE matched itself"); } + | ^^^^^^^^^^^^^^^^^^^^ + | + = warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release! + = note: for more information, see issue #62411 <https://github.com/rust-lang/rust/issues/62411> + = note: the traits must be derived, manual `impl`s are not sufficient + = note: see https://doc.rust-lang.org/stable/std/marker/trait.StructuralEq.html for details +note: the lint level is defined here + --> $DIR/cant-hide-behind-indirect-struct-embedded.rs:7:9 + | +LL | #![warn(indirect_structural_match)] + | ^^^^^^^^^^^^^^^^^^^^^^^^^ + +warning: 1 warning emitted + diff --git a/tests/ui/rfcs/rfc-1445-restrict-constants-in-patterns/cant-hide-behind-indirect-struct-param.rs b/tests/ui/rfcs/rfc-1445-restrict-constants-in-patterns/cant-hide-behind-indirect-struct-param.rs new file mode 100644 index 000000000..3489995ae --- /dev/null +++ b/tests/ui/rfcs/rfc-1445-restrict-constants-in-patterns/cant-hide-behind-indirect-struct-param.rs @@ -0,0 +1,29 @@ +// This is part of a set of tests exploring the different ways a +// structural-match ADT might try to hold a +// non-structural-match in hidden manner that lets matches +// through that we had intended to reject. +// +// See discussion on rust-lang/rust#62307 and rust-lang/rust#62339 +#![warn(indirect_structural_match)] +// run-pass + +struct NoDerive(#[allow(unused_tuple_struct_fields)] i32); + +// This impl makes NoDerive irreflexive. +impl PartialEq for NoDerive { fn eq(&self, _: &Self) -> bool { false } } + +impl Eq for NoDerive { } + +#[derive(PartialEq, Eq)] +struct WrapParam<T>(T); + +const WRAP_INDIRECT_PARAM: & &WrapParam<NoDerive> = & &WrapParam(NoDerive(0)); + +fn main() { + match WRAP_INDIRECT_PARAM { + WRAP_INDIRECT_PARAM => { panic!("WRAP_INDIRECT_PARAM matched itself"); } + //~^ WARN must be annotated with `#[derive(PartialEq, Eq)]` + //~| WARN this was previously accepted + _ => { println!("WRAP_INDIRECT_PARAM correctly did not match itself"); } + } +} diff --git a/tests/ui/rfcs/rfc-1445-restrict-constants-in-patterns/cant-hide-behind-indirect-struct-param.stderr b/tests/ui/rfcs/rfc-1445-restrict-constants-in-patterns/cant-hide-behind-indirect-struct-param.stderr new file mode 100644 index 000000000..211990801 --- /dev/null +++ b/tests/ui/rfcs/rfc-1445-restrict-constants-in-patterns/cant-hide-behind-indirect-struct-param.stderr @@ -0,0 +1,18 @@ +warning: to use a constant of type `NoDerive` in a pattern, `NoDerive` must be annotated with `#[derive(PartialEq, Eq)]` + --> $DIR/cant-hide-behind-indirect-struct-param.rs:24:9 + | +LL | WRAP_INDIRECT_PARAM => { panic!("WRAP_INDIRECT_PARAM matched itself"); } + | ^^^^^^^^^^^^^^^^^^^ + | + = warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release! + = note: for more information, see issue #62411 <https://github.com/rust-lang/rust/issues/62411> + = note: the traits must be derived, manual `impl`s are not sufficient + = note: see https://doc.rust-lang.org/stable/std/marker/trait.StructuralEq.html for details +note: the lint level is defined here + --> $DIR/cant-hide-behind-indirect-struct-param.rs:7:9 + | +LL | #![warn(indirect_structural_match)] + | ^^^^^^^^^^^^^^^^^^^^^^^^^ + +warning: 1 warning emitted + diff --git a/tests/ui/rfcs/rfc-1445-restrict-constants-in-patterns/feature-gate.no_gate.stderr b/tests/ui/rfcs/rfc-1445-restrict-constants-in-patterns/feature-gate.no_gate.stderr new file mode 100644 index 000000000..bd2940479 --- /dev/null +++ b/tests/ui/rfcs/rfc-1445-restrict-constants-in-patterns/feature-gate.no_gate.stderr @@ -0,0 +1,21 @@ +error[E0658]: use of unstable library feature 'structural_match' + --> $DIR/feature-gate.rs:29:6 + | +LL | impl std::marker::StructuralPartialEq for Foo { } + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + | + = note: see issue #31434 <https://github.com/rust-lang/rust/issues/31434> for more information + = help: add `#![feature(structural_match)]` to the crate attributes to enable + +error[E0658]: use of unstable library feature 'structural_match' + --> $DIR/feature-gate.rs:31:6 + | +LL | impl std::marker::StructuralEq for Foo { } + | ^^^^^^^^^^^^^^^^^^^^^^^^^ + | + = note: see issue #31434 <https://github.com/rust-lang/rust/issues/31434> for more information + = help: add `#![feature(structural_match)]` to the crate attributes to enable + +error: aborting due to 2 previous errors + +For more information about this error, try `rustc --explain E0658`. diff --git a/tests/ui/rfcs/rfc-1445-restrict-constants-in-patterns/feature-gate.rs b/tests/ui/rfcs/rfc-1445-restrict-constants-in-patterns/feature-gate.rs new file mode 100644 index 000000000..ee6674097 --- /dev/null +++ b/tests/ui/rfcs/rfc-1445-restrict-constants-in-patterns/feature-gate.rs @@ -0,0 +1,39 @@ +// Test that use of structural-match traits is only permitted with a feature gate, +// and that if a feature gate is supplied, it permits the type to be +// used in a match. + +// revisions: with_gate no_gate + +// gate-test-structural_match + +#![allow(unused)] +#![feature(rustc_attrs)] +#![cfg_attr(with_gate, feature(structural_match))] + + +struct Foo { + x: u32 +} + +const FOO: Foo = Foo { x: 0 }; + +#[rustc_error] +fn main() { //[with_gate]~ ERROR fatal error triggered by #[rustc_error] + let y = Foo { x: 1 }; + match y { + FOO => { } + _ => { } + } +} + +impl std::marker::StructuralPartialEq for Foo { } +//[no_gate]~^ ERROR use of unstable library feature 'structural_match' +impl std::marker::StructuralEq for Foo { } +//[no_gate]~^ ERROR use of unstable library feature 'structural_match' + +impl PartialEq<Foo> for Foo { + fn eq(&self, other: &Self) -> bool { + self.x == other.x + } +} +impl Eq for Foo { } diff --git a/tests/ui/rfcs/rfc-1445-restrict-constants-in-patterns/feature-gate.with_gate.stderr b/tests/ui/rfcs/rfc-1445-restrict-constants-in-patterns/feature-gate.with_gate.stderr new file mode 100644 index 000000000..623fd585a --- /dev/null +++ b/tests/ui/rfcs/rfc-1445-restrict-constants-in-patterns/feature-gate.with_gate.stderr @@ -0,0 +1,8 @@ +error: fatal error triggered by #[rustc_error] + --> $DIR/feature-gate.rs:21:1 + | +LL | fn main() { + | ^^^^^^^^^ + +error: aborting due to previous error + diff --git a/tests/ui/rfcs/rfc-1445-restrict-constants-in-patterns/fn-ptr-is-structurally-matchable.rs b/tests/ui/rfcs/rfc-1445-restrict-constants-in-patterns/fn-ptr-is-structurally-matchable.rs new file mode 100644 index 000000000..2b3fbd2a4 --- /dev/null +++ b/tests/ui/rfcs/rfc-1445-restrict-constants-in-patterns/fn-ptr-is-structurally-matchable.rs @@ -0,0 +1,135 @@ +// run-pass + +// This file checks that fn ptrs are considered structurally matchable. +// See also rust-lang/rust#63479. + +fn main() { + let mut count = 0; + + // A type which is not structurally matchable: + struct NotSM; + + // And one that is: + #[derive(PartialEq, Eq)] + struct SM; + + fn trivial() {} + + fn sm_to(_: SM) {} + fn not_sm_to(_: NotSM) {} + fn to_sm() -> SM { SM } + fn to_not_sm() -> NotSM { NotSM } + + // To recreate the scenario of interest in #63479, we need to add + // a ref-level-of-indirection so that we descend into the type. + + fn r_sm_to(_: &SM) {} + fn r_not_sm_to(_: &NotSM) {} + fn r_to_r_sm(_: &()) -> &SM { &SM } + fn r_to_r_not_sm(_: &()) -> &NotSM { &NotSM } + + #[derive(PartialEq, Eq)] + struct Wrap<T>(T); + + // In the code below, we put the match input into a local so that + // we can assign it an explicit type that is an fn ptr instead of + // a singleton type of the fn itself that the type inference would + // otherwise assign. + + // Check that fn() is structural-match + const CFN1: Wrap<fn()> = Wrap(trivial); + let input: Wrap<fn()> = Wrap(trivial); + match Wrap(input) { + Wrap(CFN1) => count += 1, + Wrap(_) => {} + }; + + // Check that fn(T) is structural-match when T is too. + const CFN2: Wrap<fn(SM)> = Wrap(sm_to); + let input: Wrap<fn(SM)> = Wrap(sm_to); + match Wrap(input) { + Wrap(CFN2) => count += 1, + Wrap(_) => {} + }; + + // Check that fn() -> T is structural-match when T is too. + const CFN3: Wrap<fn() -> SM> = Wrap(to_sm); + let input: Wrap<fn() -> SM> = Wrap(to_sm); + match Wrap(input) { + Wrap(CFN3) => count += 1, + Wrap(_) => {} + }; + + // Check that fn(T) is structural-match even if T is not. + const CFN4: Wrap<fn(NotSM)> = Wrap(not_sm_to); + let input: Wrap<fn(NotSM)> = Wrap(not_sm_to); + match Wrap(input) { + Wrap(CFN4) => count += 1, + Wrap(_) => {} + }; + + // Check that fn() -> T is structural-match even if T is not. + const CFN5: Wrap<fn() -> NotSM> = Wrap(to_not_sm); + let input: Wrap<fn() -> NotSM> = Wrap(to_not_sm); + match Wrap(input) { + Wrap(CFN5) => count += 1, + Wrap(_) => {} + }; + + // Check that fn(&T) is structural-match when T is too. + const CFN6: Wrap<fn(&SM)> = Wrap(r_sm_to); + let input: Wrap<fn(&SM)> = Wrap(r_sm_to); + match Wrap(input) { + Wrap(CFN6) => count += 1, + Wrap(_) => {} + }; + + // Check that fn() -> &T is structural-match when T is too. + const CFN7: Wrap<fn(&()) -> &SM> = Wrap(r_to_r_sm); + let input: Wrap<fn(&()) -> &SM> = Wrap(r_to_r_sm); + match Wrap(input) { + Wrap(CFN7) => count += 1, + Wrap(_) => {} + }; + + // Check that fn(T) is structural-match even if T is not. + const CFN8: Wrap<fn(&NotSM)> = Wrap(r_not_sm_to); + let input: Wrap<fn(&NotSM)> = Wrap(r_not_sm_to); + match Wrap(input) { + Wrap(CFN8) => count += 1, + Wrap(_) => {} + }; + + // Check that fn() -> T is structural-match even if T is not. + const CFN9: Wrap<fn(&()) -> &NotSM> = Wrap(r_to_r_not_sm); + let input: Wrap<fn(&()) -> &NotSM> = Wrap(r_to_r_not_sm); + match Wrap(input) { + Wrap(CFN9) => count += 1, + Wrap(_) => {} + }; + + // Check that a type which has fn ptrs is structural-match. + #[derive(PartialEq, Eq)] + struct Foo { + alpha: fn(NotSM), + beta: fn() -> NotSM, + gamma: fn(SM), + delta: fn() -> SM, + } + + const CFOO: Foo = Foo { + alpha: not_sm_to, + beta: to_not_sm, + gamma: sm_to, + delta: to_sm, + }; + + let input = Foo { alpha: not_sm_to, beta: to_not_sm, gamma: sm_to, delta: to_sm }; + match input { + CFOO => count += 1, + Foo { .. } => {} + }; + + // Final count must be 10 now if all + assert_eq!(count, 10); +} diff --git a/tests/ui/rfcs/rfc-1445-restrict-constants-in-patterns/issue-61188-match-slice-forbidden-without-eq.rs b/tests/ui/rfcs/rfc-1445-restrict-constants-in-patterns/issue-61188-match-slice-forbidden-without-eq.rs new file mode 100644 index 000000000..2a915d61e --- /dev/null +++ b/tests/ui/rfcs/rfc-1445-restrict-constants-in-patterns/issue-61188-match-slice-forbidden-without-eq.rs @@ -0,0 +1,19 @@ +// Issue 61188 pointed out a case where we hit an ICE during code gen: +// the compiler assumed that `PartialEq` was always implemented on any +// use of a `const` item in a pattern context, but the pre-existing +// structural-match checking was too shallow +// (see rust-lang/rust#62307), and so we hit cases where we were +// trying to dispatch to `PartialEq` on types that did not implement +// that trait. + +struct B(i32); + +const A: &[B] = &[]; + +pub fn main() { + match &[][..] { + A => (), + //~^ ERROR must be annotated with `#[derive(PartialEq, Eq)]` + _ => (), + } +} diff --git a/tests/ui/rfcs/rfc-1445-restrict-constants-in-patterns/issue-61188-match-slice-forbidden-without-eq.stderr b/tests/ui/rfcs/rfc-1445-restrict-constants-in-patterns/issue-61188-match-slice-forbidden-without-eq.stderr new file mode 100644 index 000000000..46600e7b2 --- /dev/null +++ b/tests/ui/rfcs/rfc-1445-restrict-constants-in-patterns/issue-61188-match-slice-forbidden-without-eq.stderr @@ -0,0 +1,11 @@ +error: to use a constant of type `B` in a pattern, `B` must be annotated with `#[derive(PartialEq, Eq)]` + --> $DIR/issue-61188-match-slice-forbidden-without-eq.rs:15:9 + | +LL | A => (), + | ^ + | + = note: the traits must be derived, manual `impl`s are not sufficient + = note: see https://doc.rust-lang.org/stable/std/marker/trait.StructuralEq.html for details + +error: aborting due to previous error + diff --git a/tests/ui/rfcs/rfc-1445-restrict-constants-in-patterns/issue-62307-match-ref-ref-forbidden-without-eq.rs b/tests/ui/rfcs/rfc-1445-restrict-constants-in-patterns/issue-62307-match-ref-ref-forbidden-without-eq.rs new file mode 100644 index 000000000..46d8ee3b6 --- /dev/null +++ b/tests/ui/rfcs/rfc-1445-restrict-constants-in-patterns/issue-62307-match-ref-ref-forbidden-without-eq.rs @@ -0,0 +1,43 @@ +// RFC 1445 introduced `#[structural_match]`; this attribute must +// appear on the `struct`/`enum` definition for any `const` used in a +// pattern. +// +// This is our (forever-unstable) way to mark a datatype as having a +// `PartialEq` implementation that is equivalent to recursion over its +// substructure. This avoids (at least in the short term) any need to +// resolve the question of what semantics is used for such matching. +// (See RFC 1445 for more details and discussion.) + +// Issue 62307 pointed out a case where the structural-match checking +// was too shallow. +#![warn(indirect_structural_match, nontrivial_structural_match)] +// run-pass + +#[derive(Debug)] +struct B(i32); + +// Overriding `PartialEq` to use this strange notion of "equality" exposes +// whether `match` is using structural-equality or method-dispatch +// under the hood, which is the antithesis of rust-lang/rfcs#1445 +impl PartialEq for B { + fn eq(&self, other: &B) -> bool { std::cmp::min(self.0, other.0) == 0 } +} + +fn main() { + const RR_B0: & & B = & & B(0); + const RR_B1: & & B = & & B(1); + + match RR_B0 { + RR_B1 => { println!("CLAIM RR0: {:?} matches {:?}", RR_B1, RR_B0); } + //~^ WARN must be annotated with `#[derive(PartialEq, Eq)]` + //~| WARN this was previously accepted + _ => { } + } + + match RR_B1 { + RR_B1 => { println!("CLAIM RR1: {:?} matches {:?}", RR_B1, RR_B1); } + //~^ WARN must be annotated with `#[derive(PartialEq, Eq)]` + //~| WARN this was previously accepted + _ => { } + } +} diff --git a/tests/ui/rfcs/rfc-1445-restrict-constants-in-patterns/issue-62307-match-ref-ref-forbidden-without-eq.stderr b/tests/ui/rfcs/rfc-1445-restrict-constants-in-patterns/issue-62307-match-ref-ref-forbidden-without-eq.stderr new file mode 100644 index 000000000..435812306 --- /dev/null +++ b/tests/ui/rfcs/rfc-1445-restrict-constants-in-patterns/issue-62307-match-ref-ref-forbidden-without-eq.stderr @@ -0,0 +1,29 @@ +warning: to use a constant of type `B` in a pattern, `B` must be annotated with `#[derive(PartialEq, Eq)]` + --> $DIR/issue-62307-match-ref-ref-forbidden-without-eq.rs:31:9 + | +LL | RR_B1 => { println!("CLAIM RR0: {:?} matches {:?}", RR_B1, RR_B0); } + | ^^^^^ + | + = warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release! + = note: for more information, see issue #62411 <https://github.com/rust-lang/rust/issues/62411> + = note: the traits must be derived, manual `impl`s are not sufficient + = note: see https://doc.rust-lang.org/stable/std/marker/trait.StructuralEq.html for details +note: the lint level is defined here + --> $DIR/issue-62307-match-ref-ref-forbidden-without-eq.rs:13:9 + | +LL | #![warn(indirect_structural_match, nontrivial_structural_match)] + | ^^^^^^^^^^^^^^^^^^^^^^^^^ + +warning: to use a constant of type `B` in a pattern, `B` must be annotated with `#[derive(PartialEq, Eq)]` + --> $DIR/issue-62307-match-ref-ref-forbidden-without-eq.rs:38:9 + | +LL | RR_B1 => { println!("CLAIM RR1: {:?} matches {:?}", RR_B1, RR_B1); } + | ^^^^^ + | + = warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release! + = note: for more information, see issue #62411 <https://github.com/rust-lang/rust/issues/62411> + = note: the traits must be derived, manual `impl`s are not sufficient + = note: see https://doc.rust-lang.org/stable/std/marker/trait.StructuralEq.html for details + +warning: 2 warnings emitted + diff --git a/tests/ui/rfcs/rfc-1445-restrict-constants-in-patterns/issue-63479-match-fnptr.rs b/tests/ui/rfcs/rfc-1445-restrict-constants-in-patterns/issue-63479-match-fnptr.rs new file mode 100644 index 000000000..567685950 --- /dev/null +++ b/tests/ui/rfcs/rfc-1445-restrict-constants-in-patterns/issue-63479-match-fnptr.rs @@ -0,0 +1,40 @@ +// run-pass + +// The actual regression test from #63479. (Including this because my +// first draft at fn-ptr-is-structurally-matchable.rs failed to actually +// cover the case this hit; I've since expanded it accordingly, but the +// experience left me wary of leaving this regression test out.) + +#![warn(pointer_structural_match)] + +#[derive(Eq)] +struct A { + a: i64 +} + +impl PartialEq for A { + #[inline] + fn eq(&self, other: &Self) -> bool { + self.a.eq(&other.a) + } +} + +type Fn = fn(&[A]); + +fn my_fn(_args: &[A]) { + println!("hello world"); +} + +const TEST: Fn = my_fn; + +struct B(Fn); + +fn main() { + let s = B(my_fn); + match s { + B(TEST) => println!("matched"), + //~^ WARN pointers in patterns behave unpredictably + //~| WARN this was previously accepted by the compiler but is being phased out + _ => panic!("didn't match") + }; +} diff --git a/tests/ui/rfcs/rfc-1445-restrict-constants-in-patterns/issue-63479-match-fnptr.stderr b/tests/ui/rfcs/rfc-1445-restrict-constants-in-patterns/issue-63479-match-fnptr.stderr new file mode 100644 index 000000000..d6afc0255 --- /dev/null +++ b/tests/ui/rfcs/rfc-1445-restrict-constants-in-patterns/issue-63479-match-fnptr.stderr @@ -0,0 +1,16 @@ +warning: function pointers and unsized pointers in patterns behave unpredictably and should not be relied upon. See https://github.com/rust-lang/rust/issues/70861 for details. + --> $DIR/issue-63479-match-fnptr.rs:35:7 + | +LL | B(TEST) => println!("matched"), + | ^^^^ + | + = warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release! + = note: for more information, see issue #62411 <https://github.com/rust-lang/rust/issues/70861> +note: the lint level is defined here + --> $DIR/issue-63479-match-fnptr.rs:8:9 + | +LL | #![warn(pointer_structural_match)] + | ^^^^^^^^^^^^^^^^^^^^^^^^ + +warning: 1 warning emitted + diff --git a/tests/ui/rfcs/rfc-1445-restrict-constants-in-patterns/issue-6804.rs b/tests/ui/rfcs/rfc-1445-restrict-constants-in-patterns/issue-6804.rs new file mode 100644 index 000000000..0260caa82 --- /dev/null +++ b/tests/ui/rfcs/rfc-1445-restrict-constants-in-patterns/issue-6804.rs @@ -0,0 +1,21 @@ +// Matching against NaN should result in a warning + +#![allow(unused)] +#![deny(illegal_floating_point_literal_pattern)] + +const NAN: f64 = f64::NAN; + +fn main() { + let x = NAN; + match x { + NAN => {}, //~ ERROR floating-point types cannot be used + //~| WARN this was previously accepted by the compiler but is being phased out + _ => {}, + }; + + match [x, 1.0] { + [NAN, _] => {}, //~ ERROR floating-point types cannot be used + //~| WARN this was previously accepted by the compiler but is being phased out + _ => {}, + }; +} diff --git a/tests/ui/rfcs/rfc-1445-restrict-constants-in-patterns/issue-6804.stderr b/tests/ui/rfcs/rfc-1445-restrict-constants-in-patterns/issue-6804.stderr new file mode 100644 index 000000000..f37255d08 --- /dev/null +++ b/tests/ui/rfcs/rfc-1445-restrict-constants-in-patterns/issue-6804.stderr @@ -0,0 +1,25 @@ +error: floating-point types cannot be used in patterns + --> $DIR/issue-6804.rs:11:9 + | +LL | NAN => {}, + | ^^^ + | + = warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release! + = note: for more information, see issue #41620 <https://github.com/rust-lang/rust/issues/41620> +note: the lint level is defined here + --> $DIR/issue-6804.rs:4:9 + | +LL | #![deny(illegal_floating_point_literal_pattern)] + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + +error: floating-point types cannot be used in patterns + --> $DIR/issue-6804.rs:17:10 + | +LL | [NAN, _] => {}, + | ^^^ + | + = warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release! + = note: for more information, see issue #41620 <https://github.com/rust-lang/rust/issues/41620> + +error: aborting due to 2 previous errors + diff --git a/tests/ui/rfcs/rfc-1445-restrict-constants-in-patterns/match-empty-array-allowed-without-eq-issue-62336.rs b/tests/ui/rfcs/rfc-1445-restrict-constants-in-patterns/match-empty-array-allowed-without-eq-issue-62336.rs new file mode 100644 index 000000000..7ba0f3a9e --- /dev/null +++ b/tests/ui/rfcs/rfc-1445-restrict-constants-in-patterns/match-empty-array-allowed-without-eq-issue-62336.rs @@ -0,0 +1,17 @@ +// Pre-existing behavior has been to reject patterns with consts +// denoting non-empty arrays of non-`Eq` types, but *accept* empty +// arrays of such types. +// +// See rust-lang/rust#62336. + +// run-pass + +#[derive(PartialEq, Debug)] +struct B(i32); + +fn main() { + const FOO: [B; 0] = []; + match [] { + FOO => { } + } +} diff --git a/tests/ui/rfcs/rfc-1445-restrict-constants-in-patterns/match-forbidden-without-eq.rs b/tests/ui/rfcs/rfc-1445-restrict-constants-in-patterns/match-forbidden-without-eq.rs new file mode 100644 index 000000000..59a22c337 --- /dev/null +++ b/tests/ui/rfcs/rfc-1445-restrict-constants-in-patterns/match-forbidden-without-eq.rs @@ -0,0 +1,23 @@ +#[derive(PartialEq)] +struct Foo { + x: u32 +} + +const FOO: Foo = Foo { x: 0 }; + +fn main() { + let y = Foo { x: 1 }; + match y { + FOO => { } + //~^ ERROR must be annotated with `#[derive(PartialEq, Eq)]` + _ => { } + } + + let x = 0.0; + match x { + f32::INFINITY => { } + //~^ WARNING floating-point types cannot be used in patterns + //~| WARNING this was previously accepted by the compiler but is being phased out + _ => { } + } +} diff --git a/tests/ui/rfcs/rfc-1445-restrict-constants-in-patterns/match-forbidden-without-eq.stderr b/tests/ui/rfcs/rfc-1445-restrict-constants-in-patterns/match-forbidden-without-eq.stderr new file mode 100644 index 000000000..1c4fb9146 --- /dev/null +++ b/tests/ui/rfcs/rfc-1445-restrict-constants-in-patterns/match-forbidden-without-eq.stderr @@ -0,0 +1,21 @@ +error: to use a constant of type `Foo` in a pattern, `Foo` must be annotated with `#[derive(PartialEq, Eq)]` + --> $DIR/match-forbidden-without-eq.rs:11:9 + | +LL | FOO => { } + | ^^^ + | + = note: the traits must be derived, manual `impl`s are not sufficient + = note: see https://doc.rust-lang.org/stable/std/marker/trait.StructuralEq.html for details + +warning: floating-point types cannot be used in patterns + --> $DIR/match-forbidden-without-eq.rs:18:9 + | +LL | f32::INFINITY => { } + | ^^^^^^^^^^^^^ + | + = warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release! + = note: for more information, see issue #41620 <https://github.com/rust-lang/rust/issues/41620> + = note: `#[warn(illegal_floating_point_literal_pattern)]` on by default + +error: aborting due to previous error; 1 warning emitted + diff --git a/tests/ui/rfcs/rfc-1445-restrict-constants-in-patterns/match-nonempty-array-forbidden-without-eq.rs b/tests/ui/rfcs/rfc-1445-restrict-constants-in-patterns/match-nonempty-array-forbidden-without-eq.rs new file mode 100644 index 000000000..151a475c9 --- /dev/null +++ b/tests/ui/rfcs/rfc-1445-restrict-constants-in-patterns/match-nonempty-array-forbidden-without-eq.rs @@ -0,0 +1,19 @@ +// Issue 62307 pointed out a case where the structural-match checking +// was too shallow. +// +// Here we check similar behavior for non-empty arrays of types that +// do not derive `Eq`. +// +// (Current behavior for empty arrays differs and thus is not tested +// here; see rust-lang/rust#62336.) + +#[derive(PartialEq, Debug)] +struct B(i32); + +fn main() { + const FOO: [B; 1] = [B(0)]; + match [B(1)] { + FOO => { } + //~^ ERROR must be annotated with `#[derive(PartialEq, Eq)]` + } +} diff --git a/tests/ui/rfcs/rfc-1445-restrict-constants-in-patterns/match-nonempty-array-forbidden-without-eq.stderr b/tests/ui/rfcs/rfc-1445-restrict-constants-in-patterns/match-nonempty-array-forbidden-without-eq.stderr new file mode 100644 index 000000000..6adebada0 --- /dev/null +++ b/tests/ui/rfcs/rfc-1445-restrict-constants-in-patterns/match-nonempty-array-forbidden-without-eq.stderr @@ -0,0 +1,11 @@ +error: to use a constant of type `B` in a pattern, `B` must be annotated with `#[derive(PartialEq, Eq)]` + --> $DIR/match-nonempty-array-forbidden-without-eq.rs:16:9 + | +LL | FOO => { } + | ^^^ + | + = note: the traits must be derived, manual `impl`s are not sufficient + = note: see https://doc.rust-lang.org/stable/std/marker/trait.StructuralEq.html for details + +error: aborting due to previous error + diff --git a/tests/ui/rfcs/rfc-1445-restrict-constants-in-patterns/match-requires-both-partialeq-and-eq.rs b/tests/ui/rfcs/rfc-1445-restrict-constants-in-patterns/match-requires-both-partialeq-and-eq.rs new file mode 100644 index 000000000..a8deb8a75 --- /dev/null +++ b/tests/ui/rfcs/rfc-1445-restrict-constants-in-patterns/match-requires-both-partialeq-and-eq.rs @@ -0,0 +1,21 @@ +#[derive(Eq)] +struct Foo { + x: u32 +} + +impl PartialEq for Foo { + fn eq(&self, _: &Foo) -> bool { + false // ha ha! + } +} + +const FOO: Foo = Foo { x: 0 }; + +fn main() { + let y = Foo { x: 1 }; + match y { + FOO => { } + //~^ ERROR must be annotated with `#[derive(PartialEq, Eq)]` + _ => { } + } +} diff --git a/tests/ui/rfcs/rfc-1445-restrict-constants-in-patterns/match-requires-both-partialeq-and-eq.stderr b/tests/ui/rfcs/rfc-1445-restrict-constants-in-patterns/match-requires-both-partialeq-and-eq.stderr new file mode 100644 index 000000000..f5b10f062 --- /dev/null +++ b/tests/ui/rfcs/rfc-1445-restrict-constants-in-patterns/match-requires-both-partialeq-and-eq.stderr @@ -0,0 +1,11 @@ +error: to use a constant of type `Foo` in a pattern, `Foo` must be annotated with `#[derive(PartialEq, Eq)]` + --> $DIR/match-requires-both-partialeq-and-eq.rs:17:9 + | +LL | FOO => { } + | ^^^ + | + = note: the traits must be derived, manual `impl`s are not sufficient + = note: see https://doc.rust-lang.org/stable/std/marker/trait.StructuralEq.html for details + +error: aborting due to previous error + diff --git a/tests/ui/rfcs/rfc-1445-restrict-constants-in-patterns/phantom-data-is-structurally-matchable.rs b/tests/ui/rfcs/rfc-1445-restrict-constants-in-patterns/phantom-data-is-structurally-matchable.rs new file mode 100644 index 000000000..50f91420c --- /dev/null +++ b/tests/ui/rfcs/rfc-1445-restrict-constants-in-patterns/phantom-data-is-structurally-matchable.rs @@ -0,0 +1,53 @@ +// run-pass + +// This file checks that `PhantomData` is considered structurally matchable. + +use std::marker::PhantomData; + +fn main() { + let mut count = 0; + + // A type which is not structurally matchable: + struct NotSM; + + // And one that is: + #[derive(PartialEq, Eq)] + struct SM; + + // Check that SM is structural-match: + const CSM: SM = SM; + match SM { + CSM => count += 1, + }; + + // Check that PhantomData<T> is structural-match even if T is not. + const CPD1: PhantomData<NotSM> = PhantomData; + match PhantomData { + CPD1 => count += 1, + }; + + // Check that PhantomData<T> is structural-match when T is. + const CPD2: PhantomData<SM> = PhantomData; + match PhantomData { + CPD2 => count += 1, + }; + + // Check that a type which has a PhantomData is structural-match. + #[derive(PartialEq, Eq, Default)] + struct Foo { + alpha: PhantomData<NotSM>, + beta: PhantomData<SM>, + } + + const CFOO: Foo = Foo { + alpha: PhantomData, + beta: PhantomData, + }; + + match Foo::default() { + CFOO => count += 1, + }; + + // Final count must be 4 now if all + assert_eq!(count, 4); +} diff --git a/tests/ui/rfcs/rfc1445/eq-allows-match-on-ty-in-macro.rs b/tests/ui/rfcs/rfc-1445-restrict-constants-in-patterns/rfc1445/eq-allows-match-on-ty-in-macro.rs index 17174e22c..17174e22c 100644 --- a/tests/ui/rfcs/rfc1445/eq-allows-match-on-ty-in-macro.rs +++ b/tests/ui/rfcs/rfc-1445-restrict-constants-in-patterns/rfc1445/eq-allows-match-on-ty-in-macro.rs diff --git a/tests/ui/rfcs/rfc1445/eq-allows-match.rs b/tests/ui/rfcs/rfc-1445-restrict-constants-in-patterns/rfc1445/eq-allows-match.rs index 405a69c94..405a69c94 100644 --- a/tests/ui/rfcs/rfc1445/eq-allows-match.rs +++ b/tests/ui/rfcs/rfc-1445-restrict-constants-in-patterns/rfc1445/eq-allows-match.rs diff --git a/tests/ui/rfcs/rfc1623-2.rs b/tests/ui/rfcs/rfc-1623-static/rfc1623-2.rs index c0e13a5f5..c0e13a5f5 100644 --- a/tests/ui/rfcs/rfc1623-2.rs +++ b/tests/ui/rfcs/rfc-1623-static/rfc1623-2.rs diff --git a/tests/ui/rfcs/rfc1623-2.stderr b/tests/ui/rfcs/rfc-1623-static/rfc1623-2.stderr index d183eaaa6..d183eaaa6 100644 --- a/tests/ui/rfcs/rfc1623-2.stderr +++ b/tests/ui/rfcs/rfc-1623-static/rfc1623-2.stderr diff --git a/tests/ui/rfcs/rfc1623-3.rs b/tests/ui/rfcs/rfc-1623-static/rfc1623-3.rs index 26fa6fdb5..26fa6fdb5 100644 --- a/tests/ui/rfcs/rfc1623-3.rs +++ b/tests/ui/rfcs/rfc-1623-static/rfc1623-3.rs diff --git a/tests/ui/rfcs/rfc1623-3.stderr b/tests/ui/rfcs/rfc-1623-static/rfc1623-3.stderr index 77fc3f041..77fc3f041 100644 --- a/tests/ui/rfcs/rfc1623-3.stderr +++ b/tests/ui/rfcs/rfc-1623-static/rfc1623-3.stderr diff --git a/tests/ui/rfcs/rfc1623.rs b/tests/ui/rfcs/rfc-1623-static/rfc1623.rs index adaf25c6b..adaf25c6b 100644 --- a/tests/ui/rfcs/rfc1623.rs +++ b/tests/ui/rfcs/rfc-1623-static/rfc1623.rs diff --git a/tests/ui/rfcs/rfc1717/library-override.rs b/tests/ui/rfcs/rfc-1717-dllimport/1717-dllimport/library-override.rs index 014ccac31..014ccac31 100644 --- a/tests/ui/rfcs/rfc1717/library-override.rs +++ b/tests/ui/rfcs/rfc-1717-dllimport/1717-dllimport/library-override.rs diff --git a/tests/ui/rfcs/rfc-1717-dllimport/missing-link-attr.rs b/tests/ui/rfcs/rfc-1717-dllimport/missing-link-attr.rs new file mode 100644 index 000000000..b46d85160 --- /dev/null +++ b/tests/ui/rfcs/rfc-1717-dllimport/missing-link-attr.rs @@ -0,0 +1,4 @@ +// compile-flags: -l foo:bar +// error-pattern: renaming of the library `foo` was specified + +#![crate_type = "lib"] diff --git a/tests/ui/rfcs/rfc-1717-dllimport/missing-link-attr.stderr b/tests/ui/rfcs/rfc-1717-dllimport/missing-link-attr.stderr new file mode 100644 index 000000000..d4410e147 --- /dev/null +++ b/tests/ui/rfcs/rfc-1717-dllimport/missing-link-attr.stderr @@ -0,0 +1,4 @@ +error: renaming of the library `foo` was specified, however this crate contains no `#[link(...)]` attributes referencing this library + +error: aborting due to previous error + diff --git a/tests/ui/rfcs/rfc-1717-dllimport/multiple-renames.rs b/tests/ui/rfcs/rfc-1717-dllimport/multiple-renames.rs new file mode 100644 index 000000000..106f196b4 --- /dev/null +++ b/tests/ui/rfcs/rfc-1717-dllimport/multiple-renames.rs @@ -0,0 +1,7 @@ +// compile-flags: -l foo:bar -l foo:baz +// error-pattern: multiple renamings were specified for library + +#![crate_type = "lib"] + +#[link(name = "foo")] +extern "C" {} diff --git a/tests/ui/rfcs/rfc-1717-dllimport/multiple-renames.stderr b/tests/ui/rfcs/rfc-1717-dllimport/multiple-renames.stderr new file mode 100644 index 000000000..a6fec9c4e --- /dev/null +++ b/tests/ui/rfcs/rfc-1717-dllimport/multiple-renames.stderr @@ -0,0 +1,4 @@ +error: multiple renamings were specified for library `foo` + +error: aborting due to previous error + diff --git a/tests/ui/rfcs/rfc-1717-dllimport/rename-modifiers.rs b/tests/ui/rfcs/rfc-1717-dllimport/rename-modifiers.rs new file mode 100644 index 000000000..30f4db718 --- /dev/null +++ b/tests/ui/rfcs/rfc-1717-dllimport/rename-modifiers.rs @@ -0,0 +1,9 @@ +// compile-flags: -l dylib=foo:bar +// error-pattern: overriding linking modifiers from command line is not supported + +#![feature(native_link_modifiers_as_needed)] + +#![crate_type = "lib"] + +#[link(name = "foo", kind = "dylib", modifiers = "-as-needed")] +extern "C" {} diff --git a/tests/ui/rfcs/rfc-1717-dllimport/rename-modifiers.stderr b/tests/ui/rfcs/rfc-1717-dllimport/rename-modifiers.stderr new file mode 100644 index 000000000..bee639bf2 --- /dev/null +++ b/tests/ui/rfcs/rfc-1717-dllimport/rename-modifiers.stderr @@ -0,0 +1,8 @@ +error: overriding linking modifiers from command line is not supported + --> $DIR/rename-modifiers.rs:9:1 + | +LL | extern "C" {} + | ^^^^^^^^^^^^^ + +error: aborting due to previous error + diff --git a/tests/ui/rfcs/rfc-1717-dllimport/rename-to-empty.rs b/tests/ui/rfcs/rfc-1717-dllimport/rename-to-empty.rs new file mode 100644 index 000000000..9356c4129 --- /dev/null +++ b/tests/ui/rfcs/rfc-1717-dllimport/rename-to-empty.rs @@ -0,0 +1,7 @@ +// compile-flags: -l foo: +// error-pattern: an empty renaming target was specified for library + +#![crate_type = "lib"] + +#[link(name = "foo")] +extern "C" {} diff --git a/tests/ui/rfcs/rfc-1717-dllimport/rename-to-empty.stderr b/tests/ui/rfcs/rfc-1717-dllimport/rename-to-empty.stderr new file mode 100644 index 000000000..aca839d80 --- /dev/null +++ b/tests/ui/rfcs/rfc-1717-dllimport/rename-to-empty.stderr @@ -0,0 +1,4 @@ +error: an empty renaming target was specified for library `foo` + +error: aborting due to previous error + diff --git a/tests/ui/rfcs/rfc1857-drop-order.rs b/tests/ui/rfcs/rfc-1857-stabilize-drop-order/drop-order.rs index 4c4816c2f..4c4816c2f 100644 --- a/tests/ui/rfcs/rfc1857-drop-order.rs +++ b/tests/ui/rfcs/rfc-1857-stabilize-drop-order/drop-order.rs diff --git a/tests/ui/rfcs/rfc-1937-termination-trait/issue-103052-1.rs b/tests/ui/rfcs/rfc-1937-termination-trait/issue-103052-1.rs new file mode 100644 index 000000000..a75c91cc9 --- /dev/null +++ b/tests/ui/rfcs/rfc-1937-termination-trait/issue-103052-1.rs @@ -0,0 +1,11 @@ +// Check that we don't blindly emit a diagnostic claiming that "`main` has an invalid return type" +// if we encounter a type that doesn't implement `std::process::Termination` and is not actually +// the return type of the program entry `main`. + +fn receive(_: impl std::process::Termination) {} + +struct Something; + +fn main() { + receive(Something); //~ ERROR the trait bound `Something: Termination` is not satisfied +} diff --git a/tests/ui/rfcs/rfc-1937-termination-trait/issue-103052-1.stderr b/tests/ui/rfcs/rfc-1937-termination-trait/issue-103052-1.stderr new file mode 100644 index 000000000..409dede1a --- /dev/null +++ b/tests/ui/rfcs/rfc-1937-termination-trait/issue-103052-1.stderr @@ -0,0 +1,17 @@ +error[E0277]: the trait bound `Something: Termination` is not satisfied + --> $DIR/issue-103052-1.rs:10:13 + | +LL | receive(Something); + | ------- ^^^^^^^^^ the trait `Termination` is not implemented for `Something` + | | + | required by a bound introduced by this call + | +note: required by a bound in `receive` + --> $DIR/issue-103052-1.rs:5:20 + | +LL | fn receive(_: impl std::process::Termination) {} + | ^^^^^^^^^^^^^^^^^^^^^^^^^ required by this bound in `receive` + +error: aborting due to previous error + +For more information about this error, try `rustc --explain E0277`. diff --git a/tests/ui/rfcs/rfc-1937-termination-trait/issue-103052-2.current.stderr b/tests/ui/rfcs/rfc-1937-termination-trait/issue-103052-2.current.stderr new file mode 100644 index 000000000..f72b3ab02 --- /dev/null +++ b/tests/ui/rfcs/rfc-1937-termination-trait/issue-103052-2.current.stderr @@ -0,0 +1,15 @@ +error[E0277]: the trait bound `Something: Termination` is not satisfied + --> $DIR/issue-103052-2.rs:15:22 + | +LL | fn main() -> Something { + | ^^^^^^^^^ the trait `Termination` is not implemented for `Something` + | +note: required by a bound in `Main::main::{opaque#0}` + --> $DIR/issue-103052-2.rs:9:27 + | +LL | fn main() -> impl std::process::Termination; + | ^^^^^^^^^^^^^^^^^^^^^^^^^ required by this bound in `Main::main::{opaque#0}` + +error: aborting due to previous error + +For more information about this error, try `rustc --explain E0277`. diff --git a/tests/ui/rfcs/rfc-1937-termination-trait/issue-103052-2.next.stderr b/tests/ui/rfcs/rfc-1937-termination-trait/issue-103052-2.next.stderr new file mode 100644 index 000000000..8b01941b4 --- /dev/null +++ b/tests/ui/rfcs/rfc-1937-termination-trait/issue-103052-2.next.stderr @@ -0,0 +1,15 @@ +error[E0277]: the trait bound `Something: Termination` is not satisfied + --> $DIR/issue-103052-2.rs:15:22 + | +LL | fn main() -> Something { + | ^^^^^^^^^ the trait `Termination` is not implemented for `Something` + | +note: required by a bound in `Main::{opaque#0}` + --> $DIR/issue-103052-2.rs:9:27 + | +LL | fn main() -> impl std::process::Termination; + | ^^^^^^^^^^^^^^^^^^^^^^^^^ required by this bound in `Main::{opaque#0}` + +error: aborting due to previous error + +For more information about this error, try `rustc --explain E0277`. diff --git a/tests/ui/rfcs/rfc-1937-termination-trait/issue-103052-2.rs b/tests/ui/rfcs/rfc-1937-termination-trait/issue-103052-2.rs new file mode 100644 index 000000000..ca5fa6df2 --- /dev/null +++ b/tests/ui/rfcs/rfc-1937-termination-trait/issue-103052-2.rs @@ -0,0 +1,22 @@ +// [next] compile-flags: -Zlower-impl-trait-in-trait-to-assoc-ty +// revisions: current next + +#![feature(return_position_impl_trait_in_trait)] +#![allow(incomplete_features)] + +mod child { + trait Main { + fn main() -> impl std::process::Termination; + } + + struct Something; + + impl Main for () { + fn main() -> Something { + //~^ ERROR the trait bound `Something: Termination` is not satisfied + Something + } + } +} + +fn main() {} diff --git a/tests/ui/rfcs/rfc-1937-termination-trait/termination-trait-for-box-dyn-error-err.rs b/tests/ui/rfcs/rfc-1937-termination-trait/termination-trait-for-box-dyn-error-err.rs new file mode 100644 index 000000000..10dc6115d --- /dev/null +++ b/tests/ui/rfcs/rfc-1937-termination-trait/termination-trait-for-box-dyn-error-err.rs @@ -0,0 +1,11 @@ +// run-fail +// error-pattern:returned Box<dyn Error> from main() +// failure-status: 1 +// ignore-emscripten no processes + +use std::error::Error; +use std::io; + +fn main() -> Result<(), Box<dyn Error>> { + Err(Box::new(io::Error::new(io::ErrorKind::Other, "returned Box<dyn Error> from main()"))) +} diff --git a/tests/ui/rfcs/rfc-1937-termination-trait/termination-trait-for-box-dyn-error.rs b/tests/ui/rfcs/rfc-1937-termination-trait/termination-trait-for-box-dyn-error-ok.rs index e98582cbc..e98582cbc 100644 --- a/tests/ui/rfcs/rfc-1937-termination-trait/termination-trait-for-box-dyn-error.rs +++ b/tests/ui/rfcs/rfc-1937-termination-trait/termination-trait-for-box-dyn-error-ok.rs diff --git a/tests/ui/rfcs/rfc-1937-termination-trait/termination-trait-for-never.rs b/tests/ui/rfcs/rfc-1937-termination-trait/termination-trait-for-never.rs new file mode 100644 index 000000000..faf2526c8 --- /dev/null +++ b/tests/ui/rfcs/rfc-1937-termination-trait/termination-trait-for-never.rs @@ -0,0 +1,7 @@ +// run-fail +// error-pattern:oh, dear +// ignore-emscripten no processes + +fn main() -> ! { + panic!("oh, dear"); +} diff --git a/tests/ui/rfcs/rfc-1937-termination-trait/termination-trait-for-result-box-error_err.rs b/tests/ui/rfcs/rfc-1937-termination-trait/termination-trait-for-result-box-error_err.rs new file mode 100644 index 000000000..6a625fb05 --- /dev/null +++ b/tests/ui/rfcs/rfc-1937-termination-trait/termination-trait-for-result-box-error_err.rs @@ -0,0 +1,10 @@ +// run-fail +// error-pattern:returned Box<Error> from main() +// failure-status: 1 +// ignore-emscripten no processes + +use std::io::{Error, ErrorKind}; + +fn main() -> Result<(), Box<Error>> { + Err(Box::new(Error::new(ErrorKind::Other, "returned Box<Error> from main()"))) +} diff --git a/tests/ui/rfcs/rfc-1937-termination-trait/termination-trait-for-str-err.rs b/tests/ui/rfcs/rfc-1937-termination-trait/termination-trait-for-str-err.rs new file mode 100644 index 000000000..94f16c6fd --- /dev/null +++ b/tests/ui/rfcs/rfc-1937-termination-trait/termination-trait-for-str-err.rs @@ -0,0 +1,8 @@ +// run-fail +// error-pattern: An error message for you +// failure-status: 1 +// ignore-emscripten no processes + +fn main() -> Result<(), &'static str> { + Err("An error message for you") +} diff --git a/tests/ui/rfcs/rfc-1937-termination-trait/termination-trait-for-str.rs b/tests/ui/rfcs/rfc-1937-termination-trait/termination-trait-for-str-ok.rs index f0591c38c..f0591c38c 100644 --- a/tests/ui/rfcs/rfc-1937-termination-trait/termination-trait-for-str.rs +++ b/tests/ui/rfcs/rfc-1937-termination-trait/termination-trait-for-str-ok.rs diff --git a/tests/ui/rfcs/rfc-1937-termination-trait/termination-trait-impl-trait.rs b/tests/ui/rfcs/rfc-1937-termination-trait/termination-trait-impl-trait.rs new file mode 100644 index 000000000..3b60cbc57 --- /dev/null +++ b/tests/ui/rfcs/rfc-1937-termination-trait/termination-trait-impl-trait.rs @@ -0,0 +1,3 @@ +// Tests that an `impl Trait` that is not `impl Termination` will not work. +fn main() -> impl Copy { } +//~^ ERROR `main` has invalid return type `impl Copy` diff --git a/tests/ui/rfcs/rfc-1937-termination-trait/termination-trait-impl-trait.stderr b/tests/ui/rfcs/rfc-1937-termination-trait/termination-trait-impl-trait.stderr new file mode 100644 index 000000000..5ee6d127e --- /dev/null +++ b/tests/ui/rfcs/rfc-1937-termination-trait/termination-trait-impl-trait.stderr @@ -0,0 +1,11 @@ +error[E0277]: `main` has invalid return type `impl Copy` + --> $DIR/termination-trait-impl-trait.rs:2:14 + | +LL | fn main() -> impl Copy { } + | ^^^^^^^^^ `main` can only return types that implement `Termination` + | + = help: consider using `()`, or a `Result` + +error: aborting due to previous error + +For more information about this error, try `rustc --explain E0277`. diff --git a/tests/ui/rfcs/rfc-1937-termination-trait/termination-trait-in-test-should-panic.rs b/tests/ui/rfcs/rfc-1937-termination-trait/termination-trait-in-test-should-panic.rs new file mode 100644 index 000000000..96808a3ed --- /dev/null +++ b/tests/ui/rfcs/rfc-1937-termination-trait/termination-trait-in-test-should-panic.rs @@ -0,0 +1,15 @@ +// compile-flags: --test + +#![feature(test)] + +extern crate test; +use std::num::ParseIntError; +use test::Bencher; + +#[test] +#[should_panic] +fn not_a_num() -> Result<(), ParseIntError> { + //~^ ERROR functions using `#[should_panic]` must return `()` + let _: u32 = "abc".parse()?; + Ok(()) +} diff --git a/tests/ui/rfcs/rfc-1937-termination-trait/termination-trait-in-test-should-panic.stderr b/tests/ui/rfcs/rfc-1937-termination-trait/termination-trait-in-test-should-panic.stderr new file mode 100644 index 000000000..7f6749fc9 --- /dev/null +++ b/tests/ui/rfcs/rfc-1937-termination-trait/termination-trait-in-test-should-panic.stderr @@ -0,0 +1,12 @@ +error: functions using `#[should_panic]` must return `()` + --> $DIR/termination-trait-in-test-should-panic.rs:11:1 + | +LL | / fn not_a_num() -> Result<(), ParseIntError> { +LL | | +LL | | let _: u32 = "abc".parse()?; +LL | | Ok(()) +LL | | } + | |_^ + +error: aborting due to previous error + diff --git a/tests/ui/rfcs/rfc-1937-termination-trait/termination-trait-in-test.rs b/tests/ui/rfcs/rfc-1937-termination-trait/termination-trait-in-test.rs new file mode 100644 index 000000000..43888cece --- /dev/null +++ b/tests/ui/rfcs/rfc-1937-termination-trait/termination-trait-in-test.rs @@ -0,0 +1,28 @@ +// compile-flags: --test +// run-pass +// needs-unwind + + +#![feature(test)] + +extern crate test; +use std::num::ParseIntError; +use test::Bencher; + +#[test] +fn is_a_num() -> Result<(), ParseIntError> { + let _: u32 = "22".parse()?; + Ok(()) +} + +#[bench] +fn test_a_positive_bench(_: &mut Bencher) -> Result<(), ParseIntError> { + Ok(()) +} + +#[bench] +#[should_panic] +fn test_a_neg_bench(_: &mut Bencher) -> Result<(), ParseIntError> { + let _: u32 = "abc".parse()?; + Ok(()) +} diff --git a/tests/ui/rfcs/rfc-1937-termination-trait/termination-trait-main-i32.rs b/tests/ui/rfcs/rfc-1937-termination-trait/termination-trait-main-i32.rs new file mode 100644 index 000000000..10f7d2215 --- /dev/null +++ b/tests/ui/rfcs/rfc-1937-termination-trait/termination-trait-main-i32.rs @@ -0,0 +1,6 @@ +fn main() -> i32 { +//~^ ERROR `main` has invalid return type `i32` +//~| NOTE `main` can only return types that implement `Termination` +//~| HELP consider using `()`, or a `Result` + 0 +} diff --git a/tests/ui/rfcs/rfc-1937-termination-trait/termination-trait-main-i32.stderr b/tests/ui/rfcs/rfc-1937-termination-trait/termination-trait-main-i32.stderr new file mode 100644 index 000000000..53779d365 --- /dev/null +++ b/tests/ui/rfcs/rfc-1937-termination-trait/termination-trait-main-i32.stderr @@ -0,0 +1,11 @@ +error[E0277]: `main` has invalid return type `i32` + --> $DIR/termination-trait-main-i32.rs:1:14 + | +LL | fn main() -> i32 { + | ^^^ `main` can only return types that implement `Termination` + | + = help: consider using `()`, or a `Result` + +error: aborting due to previous error + +For more information about this error, try `rustc --explain E0277`. diff --git a/tests/ui/rfcs/rfc-1937-termination-trait/termination-trait-main-wrong-type.rs b/tests/ui/rfcs/rfc-1937-termination-trait/termination-trait-main-wrong-type.rs new file mode 100644 index 000000000..687d5f144 --- /dev/null +++ b/tests/ui/rfcs/rfc-1937-termination-trait/termination-trait-main-wrong-type.rs @@ -0,0 +1,3 @@ +fn main() -> char { //~ ERROR + ' ' +} diff --git a/tests/ui/rfcs/rfc-1937-termination-trait/termination-trait-main-wrong-type.stderr b/tests/ui/rfcs/rfc-1937-termination-trait/termination-trait-main-wrong-type.stderr new file mode 100644 index 000000000..bc8fd92ce --- /dev/null +++ b/tests/ui/rfcs/rfc-1937-termination-trait/termination-trait-main-wrong-type.stderr @@ -0,0 +1,11 @@ +error[E0277]: `main` has invalid return type `char` + --> $DIR/termination-trait-main-wrong-type.rs:1:14 + | +LL | fn main() -> char { + | ^^^^ `main` can only return types that implement `Termination` + | + = help: consider using `()`, or a `Result` + +error: aborting due to previous error + +For more information about this error, try `rustc --explain E0277`. diff --git a/tests/ui/rfcs/rfc-1937-termination-trait/termination-trait-not-satisfied.rs b/tests/ui/rfcs/rfc-1937-termination-trait/termination-trait-not-satisfied.rs new file mode 100644 index 000000000..4c6168abb --- /dev/null +++ b/tests/ui/rfcs/rfc-1937-termination-trait/termination-trait-not-satisfied.rs @@ -0,0 +1,5 @@ +struct ReturnType {} + +fn main() -> ReturnType { //~ ERROR `main` has invalid return type `ReturnType` + ReturnType {} +} diff --git a/tests/ui/rfcs/rfc-1937-termination-trait/termination-trait-not-satisfied.stderr b/tests/ui/rfcs/rfc-1937-termination-trait/termination-trait-not-satisfied.stderr new file mode 100644 index 000000000..cb329548d --- /dev/null +++ b/tests/ui/rfcs/rfc-1937-termination-trait/termination-trait-not-satisfied.stderr @@ -0,0 +1,11 @@ +error[E0277]: `main` has invalid return type `ReturnType` + --> $DIR/termination-trait-not-satisfied.rs:3:14 + | +LL | fn main() -> ReturnType { + | ^^^^^^^^^^ `main` can only return types that implement `Termination` + | + = help: consider using `()`, or a `Result` + +error: aborting due to previous error + +For more information about this error, try `rustc --explain E0277`. diff --git a/tests/ui/rfcs/rfc-1937-termination-trait/termination-trait-test-wrong-type.rs b/tests/ui/rfcs/rfc-1937-termination-trait/termination-trait-test-wrong-type.rs new file mode 100644 index 000000000..193a523ae --- /dev/null +++ b/tests/ui/rfcs/rfc-1937-termination-trait/termination-trait-test-wrong-type.rs @@ -0,0 +1,8 @@ +// compile-flags: --test + +use std::num::ParseFloatError; + +#[test] +fn can_parse_zero_as_f32() -> Result<f32, ParseFloatError> { //~ ERROR + "0".parse() +} diff --git a/tests/ui/rfcs/rfc-1937-termination-trait/termination-trait-test-wrong-type.stderr b/tests/ui/rfcs/rfc-1937-termination-trait/termination-trait-test-wrong-type.stderr new file mode 100644 index 000000000..a19750cc7 --- /dev/null +++ b/tests/ui/rfcs/rfc-1937-termination-trait/termination-trait-test-wrong-type.stderr @@ -0,0 +1,16 @@ +error[E0277]: the trait bound `f32: Termination` is not satisfied + --> $DIR/termination-trait-test-wrong-type.rs:6:31 + | +LL | #[test] + | ------- in this procedural macro expansion +LL | fn can_parse_zero_as_f32() -> Result<f32, ParseFloatError> { + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^ the trait `Termination` is not implemented for `f32` + | + = note: required for `Result<f32, ParseFloatError>` to implement `Termination` +note: required by a bound in `assert_test_result` + --> $SRC_DIR/test/src/lib.rs:LL:COL + = note: this error originates in the attribute macro `test` (in Nightly builds, run with -Z macro-backtrace for more info) + +error: aborting due to previous error + +For more information about this error, try `rustc --explain E0277`. diff --git a/tests/ui/rfcs/rfc-2005-default-binding-mode/borrowck-issue-49631.rs b/tests/ui/rfcs/rfc-2005-default-binding-mode/borrowck-issue-49631.rs new file mode 100644 index 000000000..54ab9f0ad --- /dev/null +++ b/tests/ui/rfcs/rfc-2005-default-binding-mode/borrowck-issue-49631.rs @@ -0,0 +1,24 @@ +#[derive(Copy, Clone, Debug, Eq, PartialEq)] +pub struct Foo { +} + +impl Foo { + fn get(&self) -> Option<&Result<String, String>> { + None + } + + fn mutate(&mut self) { } +} + +fn main() { + let mut foo = Foo { }; + + // foo.get() returns type Option<&Result<String, String>>, so + // using `string` keeps borrow of `foo` alive. Hence calling + // `foo.mutate()` should be an error. + while let Some(Ok(string)) = foo.get() { + foo.mutate(); + //~^ ERROR cannot borrow `foo` as mutable + println!("foo={:?}", *string); + } +} diff --git a/tests/ui/rfcs/rfc-2005-default-binding-mode/borrowck-issue-49631.stderr b/tests/ui/rfcs/rfc-2005-default-binding-mode/borrowck-issue-49631.stderr new file mode 100644 index 000000000..b7c0b0bb6 --- /dev/null +++ b/tests/ui/rfcs/rfc-2005-default-binding-mode/borrowck-issue-49631.stderr @@ -0,0 +1,14 @@ +error[E0502]: cannot borrow `foo` as mutable because it is also borrowed as immutable + --> $DIR/borrowck-issue-49631.rs:20:9 + | +LL | while let Some(Ok(string)) = foo.get() { + | --------- immutable borrow occurs here +LL | foo.mutate(); + | ^^^^^^^^^^^^ mutable borrow occurs here +LL | +LL | println!("foo={:?}", *string); + | ------- immutable borrow later used here + +error: aborting due to previous error + +For more information about this error, try `rustc --explain E0502`. diff --git a/tests/ui/rfcs/rfc-2005-default-binding-mode/const.rs b/tests/ui/rfcs/rfc-2005-default-binding-mode/const.rs new file mode 100644 index 000000000..93df88040 --- /dev/null +++ b/tests/ui/rfcs/rfc-2005-default-binding-mode/const.rs @@ -0,0 +1,17 @@ +// FIXME(tschottdorf): this test should pass. + +#[derive(PartialEq, Eq)] +struct Foo { + bar: i32, +} + +const FOO: Foo = Foo{bar: 5}; + +fn main() { + let f = Foo{bar:6}; + + match &f { + FOO => {}, //~ ERROR mismatched types + _ => panic!(), + } +} diff --git a/tests/ui/rfcs/rfc-2005-default-binding-mode/const.stderr b/tests/ui/rfcs/rfc-2005-default-binding-mode/const.stderr new file mode 100644 index 000000000..fc06de90a --- /dev/null +++ b/tests/ui/rfcs/rfc-2005-default-binding-mode/const.stderr @@ -0,0 +1,18 @@ +error[E0308]: mismatched types + --> $DIR/const.rs:14:9 + | +LL | const FOO: Foo = Foo{bar: 5}; + | -------------- constant defined here +... +LL | match &f { + | -- this expression has type `&Foo` +LL | FOO => {}, + | ^^^ + | | + | expected `&Foo`, found `Foo` + | `FOO` is interpreted as a constant, not a new binding + | help: introduce a new binding instead: `other_foo` + +error: aborting due to previous error + +For more information about this error, try `rustc --explain E0308`. diff --git a/tests/ui/rfcs/rfc-2005-default-binding-mode/enum-ok.rs b/tests/ui/rfcs/rfc-2005-default-binding-mode/enum-ok.rs new file mode 100644 index 000000000..52fbb90ed --- /dev/null +++ b/tests/ui/rfcs/rfc-2005-default-binding-mode/enum-ok.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/tests/ui/rfcs/rfc-2005-default-binding-mode/enum.rs b/tests/ui/rfcs/rfc-2005-default-binding-mode/enum.rs index 52fbb90ed..4e57769d6 100644 --- a/tests/ui/rfcs/rfc-2005-default-binding-mode/enum.rs +++ b/tests/ui/rfcs/rfc-2005-default-binding-mode/enum.rs @@ -1,4 +1,3 @@ -// run-pass enum Wrapper { Wrap(i32), } @@ -7,39 +6,17 @@ use Wrapper::Wrap; pub fn main() { let Wrap(x) = &Wrap(3); - println!("{}", *x); + *x += 1; //~ ERROR cannot assign to `*x`, which is behind a `&` reference - 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; + *x += 1; //~ ERROR cannot assign to `*x`, which is behind a `&` reference } 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; + *x += 1; //~ ERROR cannot assign to `*x`, which is behind a `&` reference break; } } diff --git a/tests/ui/rfcs/rfc-2005-default-binding-mode/enum.stderr b/tests/ui/rfcs/rfc-2005-default-binding-mode/enum.stderr new file mode 100644 index 000000000..21e3d3d27 --- /dev/null +++ b/tests/ui/rfcs/rfc-2005-default-binding-mode/enum.stderr @@ -0,0 +1,21 @@ +error[E0594]: cannot assign to `*x`, which is behind a `&` reference + --> $DIR/enum.rs:9:5 + | +LL | *x += 1; + | ^^^^^^^ `x` is a `&` reference, so the data it refers to cannot be written + +error[E0594]: cannot assign to `*x`, which is behind a `&` reference + --> $DIR/enum.rs:13:9 + | +LL | *x += 1; + | ^^^^^^^ `x` is a `&` reference, so the data it refers to cannot be written + +error[E0594]: cannot assign to `*x`, which is behind a `&` reference + --> $DIR/enum.rs:19:9 + | +LL | *x += 1; + | ^^^^^^^ `x` is a `&` reference, so the data it refers to cannot be written + +error: aborting due to 3 previous errors + +For more information about this error, try `rustc --explain E0594`. diff --git a/tests/ui/rfcs/rfc-2005-default-binding-mode/explicit-mut.rs b/tests/ui/rfcs/rfc-2005-default-binding-mode/explicit-mut.rs new file mode 100644 index 000000000..b8fde2208 --- /dev/null +++ b/tests/ui/rfcs/rfc-2005-default-binding-mode/explicit-mut.rs @@ -0,0 +1,28 @@ +// Verify the binding mode shifts - only when no `&` are auto-dereferenced is the +// final default binding mode mutable. + +fn main() { + match &&Some(5i32) { + Some(n) => { + *n += 1; //~ ERROR cannot assign to `*n`, which is behind a `&` reference + let _ = n; + } + None => {}, + }; + + match &mut &Some(5i32) { + Some(n) => { + *n += 1; //~ ERROR cannot assign to `*n`, which is behind a `&` reference + let _ = n; + } + None => {}, + }; + + match &&mut Some(5i32) { + Some(n) => { + *n += 1; //~ ERROR cannot assign to `*n`, which is behind a `&` reference + let _ = n; + } + None => {}, + }; +} diff --git a/tests/ui/rfcs/rfc-2005-default-binding-mode/explicit-mut.stderr b/tests/ui/rfcs/rfc-2005-default-binding-mode/explicit-mut.stderr new file mode 100644 index 000000000..c3f64f65a --- /dev/null +++ b/tests/ui/rfcs/rfc-2005-default-binding-mode/explicit-mut.stderr @@ -0,0 +1,21 @@ +error[E0594]: cannot assign to `*n`, which is behind a `&` reference + --> $DIR/explicit-mut.rs:7:13 + | +LL | *n += 1; + | ^^^^^^^ `n` is a `&` reference, so the data it refers to cannot be written + +error[E0594]: cannot assign to `*n`, which is behind a `&` reference + --> $DIR/explicit-mut.rs:15:13 + | +LL | *n += 1; + | ^^^^^^^ `n` is a `&` reference, so the data it refers to cannot be written + +error[E0594]: cannot assign to `*n`, which is behind a `&` reference + --> $DIR/explicit-mut.rs:23:13 + | +LL | *n += 1; + | ^^^^^^^ `n` is a `&` reference, so the data it refers to cannot be written + +error: aborting due to 3 previous errors + +For more information about this error, try `rustc --explain E0594`. diff --git a/tests/ui/rfcs/rfc-2005-default-binding-mode/for-ok.rs b/tests/ui/rfcs/rfc-2005-default-binding-mode/for-ok.rs new file mode 100644 index 000000000..a5a24a806 --- /dev/null +++ b/tests/ui/rfcs/rfc-2005-default-binding-mode/for-ok.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/tests/ui/rfcs/rfc-2005-default-binding-mode/for.rs b/tests/ui/rfcs/rfc-2005-default-binding-mode/for.rs index a5a24a806..d6c5a13b1 100644 --- a/tests/ui/rfcs/rfc-2005-default-binding-mode/for.rs +++ b/tests/ui/rfcs/rfc-2005-default-binding-mode/for.rs @@ -1,20 +1,9 @@ -// run-pass -pub fn main() { - let mut tups = vec![(0u8, 1u8)]; - - for (n, m) in &tups { - let _: &u8 = n; - let _: &u8 = m; - } +struct Foo {} - for (n, m) in &mut tups { - *n += 1; - *m += 2; - } - - assert_eq!(tups, vec![(1u8, 3u8)]); - - for (n, m) in tups { - println!("{} {}", m, n); +pub fn main() { + let mut tups = vec![(Foo {}, Foo {})]; + // The below desugars to &(ref n, mut m). + for (n, mut m) in &tups { + //~^ ERROR cannot move out of a shared reference } } diff --git a/tests/ui/rfcs/rfc-2005-default-binding-mode/for.stderr b/tests/ui/rfcs/rfc-2005-default-binding-mode/for.stderr new file mode 100644 index 000000000..07991af6e --- /dev/null +++ b/tests/ui/rfcs/rfc-2005-default-binding-mode/for.stderr @@ -0,0 +1,17 @@ +error[E0507]: cannot move out of a shared reference + --> $DIR/for.rs:6:23 + | +LL | for (n, mut m) in &tups { + | ----- ^^^^^ + | | + | data moved here + | move occurs because `m` has type `Foo`, which does not implement the `Copy` trait + | +help: consider borrowing the pattern binding + | +LL | for (n, ref mut m) in &tups { + | +++ + +error: aborting due to previous error + +For more information about this error, try `rustc --explain E0507`. diff --git a/tests/ui/rfcs/rfc-2005-default-binding-mode/issue-44912-or.rs b/tests/ui/rfcs/rfc-2005-default-binding-mode/issue-44912-or.rs new file mode 100644 index 000000000..b4a0d8145 --- /dev/null +++ b/tests/ui/rfcs/rfc-2005-default-binding-mode/issue-44912-or.rs @@ -0,0 +1,10 @@ +// FIXME(tschottdorf): This should compile. See #44912. + +pub fn main() { + let x = &Some((3, 3)); + let _: &i32 = match x { + Some((x, 3)) | &Some((ref x, 5)) => x, + //~^ ERROR is bound inconsistently + _ => &5i32, + }; +} diff --git a/tests/ui/rfcs/rfc-2005-default-binding-mode/issue-44912-or.stderr b/tests/ui/rfcs/rfc-2005-default-binding-mode/issue-44912-or.stderr new file mode 100644 index 000000000..e1e1bf7f6 --- /dev/null +++ b/tests/ui/rfcs/rfc-2005-default-binding-mode/issue-44912-or.stderr @@ -0,0 +1,9 @@ +error[E0409]: variable `x` is bound inconsistently across alternatives separated by `|` + --> $DIR/issue-44912-or.rs:6:35 + | +LL | Some((x, 3)) | &Some((ref x, 5)) => x, + | - first binding ^ bound in different ways + +error: aborting due to previous error + +For more information about this error, try `rustc --explain E0409`. diff --git a/tests/ui/rfcs/rfc-2005-default-binding-mode/lit-ok.rs b/tests/ui/rfcs/rfc-2005-default-binding-mode/lit-ok.rs new file mode 100644 index 000000000..937975359 --- /dev/null +++ b/tests/ui/rfcs/rfc-2005-default-binding-mode/lit-ok.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/tests/ui/rfcs/rfc-2005-default-binding-mode/lit.rs b/tests/ui/rfcs/rfc-2005-default-binding-mode/lit.rs index 937975359..ce79cfbdc 100644 --- a/tests/ui/rfcs/rfc-2005-default-binding-mode/lit.rs +++ b/tests/ui/rfcs/rfc-2005-default-binding-mode/lit.rs @@ -1,34 +1,24 @@ -// run-pass -#![allow(dead_code)] -fn with_u8() { - let s = 5u8; - let r = match &s { - 4 => false, - 5 => true, - _ => false, - }; - assert!(r); -} +// FIXME(tschottdorf): we want these to compile, but they don't. -// 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, + + match &s { + "abc" => true, //~ ERROR mismatched types _ => panic!(), }; } -// Ditto with byte strings. fn with_bytes() { let s: &'static [u8] = b"abc"; - match s { - b"abc" => true, + + match &s { + b"abc" => true, //~ ERROR mismatched types _ => panic!(), }; } pub fn main() { with_str(); + with_bytes(); } diff --git a/tests/ui/rfcs/rfc-2005-default-binding-mode/lit.stderr b/tests/ui/rfcs/rfc-2005-default-binding-mode/lit.stderr new file mode 100644 index 000000000..181f57899 --- /dev/null +++ b/tests/ui/rfcs/rfc-2005-default-binding-mode/lit.stderr @@ -0,0 +1,25 @@ +error[E0308]: mismatched types + --> $DIR/lit.rs:7:13 + | +LL | match &s { + | -- this expression has type `&&str` +LL | "abc" => true, + | ^^^^^ expected `&&str`, found `&str` + | + = note: expected reference `&&str` + found reference `&'static str` + +error[E0308]: mismatched types + --> $DIR/lit.rs:16:9 + | +LL | match &s { + | -- this expression has type `&&[u8]` +LL | b"abc" => true, + | ^^^^^^ expected `&&[u8]`, found `&[u8; 3]` + | + = note: expected reference `&&[u8]` + found reference `&'static [u8; 3]` + +error: aborting due to 2 previous errors + +For more information about this error, try `rustc --explain E0308`. diff --git a/tests/ui/rfcs/rfc-2005-default-binding-mode/no-double-error.rs b/tests/ui/rfcs/rfc-2005-default-binding-mode/no-double-error.rs new file mode 100644 index 000000000..46fdfd678 --- /dev/null +++ b/tests/ui/rfcs/rfc-2005-default-binding-mode/no-double-error.rs @@ -0,0 +1,11 @@ +// Without caching type lookups in FnCtxt.resolve_ty_and_def_ufcs +// the error below would be reported twice (once when checking +// for a non-ref pattern, once when processing the pattern). + +fn main() { + let foo = 22; + match foo { + u32::XXX => { } //~ ERROR no associated item named + _ => { } + } +} diff --git a/tests/ui/rfcs/rfc-2005-default-binding-mode/no-double-error.stderr b/tests/ui/rfcs/rfc-2005-default-binding-mode/no-double-error.stderr new file mode 100644 index 000000000..c672acee0 --- /dev/null +++ b/tests/ui/rfcs/rfc-2005-default-binding-mode/no-double-error.stderr @@ -0,0 +1,9 @@ +error[E0599]: no associated item named `XXX` found for type `u32` in the current scope + --> $DIR/no-double-error.rs:8:14 + | +LL | u32::XXX => { } + | ^^^ associated item not found in `u32` + +error: aborting due to previous error + +For more information about this error, try `rustc --explain E0599`. diff --git a/tests/ui/rfcs/rfc-2005-default-binding-mode/slice-ok.rs b/tests/ui/rfcs/rfc-2005-default-binding-mode/slice-ok.rs new file mode 100644 index 000000000..33229a205 --- /dev/null +++ b/tests/ui/rfcs/rfc-2005-default-binding-mode/slice-ok.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/tests/ui/rfcs/rfc-2005-default-binding-mode/slice.rs b/tests/ui/rfcs/rfc-2005-default-binding-mode/slice.rs index 33229a205..363a0e3e6 100644 --- a/tests/ui/rfcs/rfc-2005-default-binding-mode/slice.rs +++ b/tests/ui/rfcs/rfc-2005-default-binding-mode/slice.rs @@ -1,25 +1,7 @@ -// run-pass - -fn slice_pat() { +pub fn main() { 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(); + match sl { //~ ERROR non-exhaustive patterns + [first, remainder @ ..] => {}, + }; } diff --git a/tests/ui/rfcs/rfc-2005-default-binding-mode/slice.stderr b/tests/ui/rfcs/rfc-2005-default-binding-mode/slice.stderr new file mode 100644 index 000000000..5b51dc5ac --- /dev/null +++ b/tests/ui/rfcs/rfc-2005-default-binding-mode/slice.stderr @@ -0,0 +1,16 @@ +error[E0004]: non-exhaustive patterns: `&[]` not covered + --> $DIR/slice.rs:4:11 + | +LL | match sl { + | ^^ pattern `&[]` not covered + | + = note: the matched value is of type `&[u8]` +help: ensure that all possible cases are being handled by adding a match arm with a wildcard pattern or an explicit pattern as shown + | +LL ~ [first, remainder @ ..] => {}, +LL ~ &[] => todo!(), + | + +error: aborting due to previous error + +For more information about this error, try `rustc --explain E0004`. diff --git a/tests/ui/rfcs/rfc-2008-non-exhaustive/auxiliary/enums.rs b/tests/ui/rfcs/rfc-2008-non-exhaustive/auxiliary/enums.rs new file mode 100644 index 000000000..cb2b585ab --- /dev/null +++ b/tests/ui/rfcs/rfc-2008-non-exhaustive/auxiliary/enums.rs @@ -0,0 +1,44 @@ +#![crate_type = "rlib"] + +#[non_exhaustive] +pub enum NonExhaustiveEnum { + Unit, + Tuple(u32), + Struct { field: u32 }, +} + +#[non_exhaustive] +pub enum NestedNonExhaustive { + A(NonExhaustiveEnum), + B, + C, +} + +#[non_exhaustive] +pub enum EmptyNonExhaustiveEnum {} + +pub enum VariantNonExhaustive { + #[non_exhaustive] + Bar { + x: u32, + y: u64, + }, + Baz(u32, u16), +} + +#[non_exhaustive] +pub enum NonExhaustiveSingleVariant { + A(bool), +} + +#[repr(u8)] +pub enum FieldLessWithNonExhaustiveVariant { + A, + B, + #[non_exhaustive] + C, +} + +impl Default for FieldLessWithNonExhaustiveVariant { + fn default() -> Self { Self::A } +} diff --git a/tests/ui/rfcs/rfc-2008-non-exhaustive/auxiliary/monovariants.rs b/tests/ui/rfcs/rfc-2008-non-exhaustive/auxiliary/monovariants.rs new file mode 100644 index 000000000..5f86db86d --- /dev/null +++ b/tests/ui/rfcs/rfc-2008-non-exhaustive/auxiliary/monovariants.rs @@ -0,0 +1,8 @@ +#[non_exhaustive] +pub enum NonExhaustiveMonovariant { + Variant(u32), +} + +pub enum ExhaustiveMonovariant { + Variant(u32), +} diff --git a/tests/ui/rfcs/rfc-2008-non-exhaustive/auxiliary/structs.rs b/tests/ui/rfcs/rfc-2008-non-exhaustive/auxiliary/structs.rs new file mode 100644 index 000000000..78db6b170 --- /dev/null +++ b/tests/ui/rfcs/rfc-2008-non-exhaustive/auxiliary/structs.rs @@ -0,0 +1,41 @@ +#[derive(Default)] +#[non_exhaustive] +pub struct NormalStruct { + pub first_field: u16, + pub second_field: u16, +} + +#[non_exhaustive] +pub struct UnitStruct; + +#[non_exhaustive] +pub struct TupleStruct(pub u16, pub u16); + +#[derive(Debug)] +#[non_exhaustive] +pub struct FunctionalRecord { + pub first_field: u16, + pub second_field: u16, + pub third_field: bool, +} + +impl Default for FunctionalRecord { + fn default() -> FunctionalRecord { + FunctionalRecord { first_field: 640, second_field: 480, third_field: false } + } +} + +#[derive(Default)] +#[non_exhaustive] +pub struct NestedStruct { + pub foo: u16, + pub bar: NormalStruct, +} + +#[derive(Default)] +#[non_exhaustive] +pub struct MixedVisFields { + pub a: u16, + pub b: bool, + pub(crate) foo: bool, +} diff --git a/tests/ui/rfcs/rfc-2008-non-exhaustive/auxiliary/unstable.rs b/tests/ui/rfcs/rfc-2008-non-exhaustive/auxiliary/unstable.rs new file mode 100644 index 000000000..11df44461 --- /dev/null +++ b/tests/ui/rfcs/rfc-2008-non-exhaustive/auxiliary/unstable.rs @@ -0,0 +1,60 @@ +#![feature(staged_api)] +#![stable(feature = "stable_test_feature", since = "1.0.0")] + +#[stable(feature = "stable_test_feature", since = "1.0.0")] +#[non_exhaustive] +pub enum UnstableEnum { + #[stable(feature = "stable_test_feature", since = "1.0.0")] + Stable, + #[stable(feature = "stable_test_feature", since = "1.0.0")] + Stable2, + #[unstable(feature = "unstable_test_feature", issue = "none")] + Unstable, +} + +#[stable(feature = "stable_test_feature", since = "1.0.0")] +#[non_exhaustive] +pub enum OnlyUnstableEnum { + #[unstable(feature = "unstable_test_feature", issue = "none")] + Unstable, + #[unstable(feature = "unstable_test_feature", issue = "none")] + Unstable2, +} + +impl OnlyUnstableEnum { + #[stable(feature = "stable_test_feature", since = "1.0.0")] + pub fn new() -> Self { + Self::Unstable + } +} + +#[derive(Default)] +#[stable(feature = "stable_test_feature", since = "1.0.0")] +#[non_exhaustive] +pub struct UnstableStruct { + #[stable(feature = "stable_test_feature", since = "1.0.0")] + pub stable: bool, + #[stable(feature = "stable_test_feature", since = "1.0.0")] + pub stable2: usize, + #[unstable(feature = "unstable_test_feature", issue = "none")] + pub unstable: u8, +} + +#[stable(feature = "stable_test_feature", since = "1.0.0")] +#[non_exhaustive] +pub struct OnlyUnstableStruct { + #[unstable(feature = "unstable_test_feature", issue = "none")] + pub unstable: u8, + #[unstable(feature = "unstable_test_feature", issue = "none")] + pub unstable2: bool, +} + +impl OnlyUnstableStruct { + #[stable(feature = "stable_test_feature", since = "1.0.0")] + pub fn new() -> Self { + Self { + unstable: 0, + unstable2: false, + } + } +} diff --git a/tests/ui/rfcs/rfc-2008-non-exhaustive/auxiliary/variants.rs b/tests/ui/rfcs/rfc-2008-non-exhaustive/auxiliary/variants.rs new file mode 100644 index 000000000..02672d545 --- /dev/null +++ b/tests/ui/rfcs/rfc-2008-non-exhaustive/auxiliary/variants.rs @@ -0,0 +1,7 @@ +#![crate_type = "rlib"] + +pub enum NonExhaustiveVariants { + #[non_exhaustive] Unit, + #[non_exhaustive] Tuple(u32), + #[non_exhaustive] Struct { field: u32 } +} diff --git a/tests/ui/rfcs/rfc-2008-non-exhaustive/borrowck-exhaustive.rs b/tests/ui/rfcs/rfc-2008-non-exhaustive/borrowck-exhaustive.rs new file mode 100644 index 000000000..b9ff24c76 --- /dev/null +++ b/tests/ui/rfcs/rfc-2008-non-exhaustive/borrowck-exhaustive.rs @@ -0,0 +1,44 @@ +// Test that the borrow checker doesn't consider checking an exhaustive pattern +// as an access. + +// check-pass + +#![allow(dropping_references)] + +// aux-build:monovariants.rs +extern crate monovariants; + +use monovariants::ExhaustiveMonovariant; + +enum Local { + Variant(u32), +} + +#[non_exhaustive] +enum LocalNonExhaustive { + Variant(u32), +} + +fn main() { + let mut x = ExhaustiveMonovariant::Variant(1); + let y = &mut x; + match x { + ExhaustiveMonovariant::Variant(_) => {}, + _ => {}, + } + drop(y); + let mut x = Local::Variant(1); + let y = &mut x; + match x { + Local::Variant(_) => {}, + _ => {}, + } + drop(y); + let mut x = LocalNonExhaustive::Variant(1); + let y = &mut x; + match x { + LocalNonExhaustive::Variant(_) => {}, + _ => {}, + } + drop(y); +} diff --git a/tests/ui/rfcs/rfc-2008-non-exhaustive/borrowck-non-exhaustive.rs b/tests/ui/rfcs/rfc-2008-non-exhaustive/borrowck-non-exhaustive.rs new file mode 100644 index 000000000..2ad92b794 --- /dev/null +++ b/tests/ui/rfcs/rfc-2008-non-exhaustive/borrowck-non-exhaustive.rs @@ -0,0 +1,18 @@ +// Test that the borrow checker considers `#[non_exhaustive]` when checking +// whether a match contains a discriminant read. + +// aux-build:monovariants.rs +extern crate monovariants; + +use monovariants::NonExhaustiveMonovariant; + +fn main() { + let mut x = NonExhaustiveMonovariant::Variant(1); + let y = &mut x; + match x { + //~^ ERROR cannot use `x` because it was mutably borrowed + NonExhaustiveMonovariant::Variant(_) => {}, + _ => {}, + } + drop(y); +} diff --git a/tests/ui/rfcs/rfc-2008-non-exhaustive/borrowck-non-exhaustive.stderr b/tests/ui/rfcs/rfc-2008-non-exhaustive/borrowck-non-exhaustive.stderr new file mode 100644 index 000000000..ad84ebe3a --- /dev/null +++ b/tests/ui/rfcs/rfc-2008-non-exhaustive/borrowck-non-exhaustive.stderr @@ -0,0 +1,14 @@ +error[E0503]: cannot use `x` because it was mutably borrowed + --> $DIR/borrowck-non-exhaustive.rs:12:11 + | +LL | let y = &mut x; + | ------ `x` is borrowed here +LL | match x { + | ^ use of borrowed `x` +... +LL | drop(y); + | - borrow later used here + +error: aborting due to previous error + +For more information about this error, try `rustc --explain E0503`. diff --git a/tests/ui/rfcs/rfc-2008-non-exhaustive/enum-as-cast.rs b/tests/ui/rfcs/rfc-2008-non-exhaustive/enum-as-cast.rs new file mode 100644 index 000000000..5dce8180f --- /dev/null +++ b/tests/ui/rfcs/rfc-2008-non-exhaustive/enum-as-cast.rs @@ -0,0 +1,11 @@ +// aux-build:enums.rs + +extern crate enums; + +use enums::FieldLessWithNonExhaustiveVariant; + +fn main() { + let e = FieldLessWithNonExhaustiveVariant::default(); + let d = e as u8; //~ ERROR casting `FieldLessWithNonExhaustiveVariant` as `u8` is invalid [E0606] + assert_eq!(d, 0); +} diff --git a/tests/ui/rfcs/rfc-2008-non-exhaustive/enum-as-cast.stderr b/tests/ui/rfcs/rfc-2008-non-exhaustive/enum-as-cast.stderr new file mode 100644 index 000000000..a61dcf839 --- /dev/null +++ b/tests/ui/rfcs/rfc-2008-non-exhaustive/enum-as-cast.stderr @@ -0,0 +1,11 @@ +error[E0606]: casting `FieldLessWithNonExhaustiveVariant` as `u8` is invalid + --> $DIR/enum-as-cast.rs:9:13 + | +LL | let d = e as u8; + | ^^^^^^^ + | + = note: cannot cast an enum with a non-exhaustive variant when it's defined in another crate + +error: aborting due to previous error + +For more information about this error, try `rustc --explain E0606`. diff --git a/tests/ui/rfcs/rfc-2008-non-exhaustive/enum.rs b/tests/ui/rfcs/rfc-2008-non-exhaustive/enum.rs new file mode 100644 index 000000000..9d2855f5c --- /dev/null +++ b/tests/ui/rfcs/rfc-2008-non-exhaustive/enum.rs @@ -0,0 +1,69 @@ +// aux-build:enums.rs +extern crate enums; + +use enums::{EmptyNonExhaustiveEnum, NonExhaustiveEnum}; + +fn empty(x: EmptyNonExhaustiveEnum) { + match x {} //~ ERROR type `EmptyNonExhaustiveEnum` is non-empty + match x { + _ => {}, // ok + } +} + +fn main() { + let enum_unit = NonExhaustiveEnum::Unit; + + match enum_unit { + //~^ ERROR non-exhaustive patterns: `_` not covered [E0004] + NonExhaustiveEnum::Unit => "first", + NonExhaustiveEnum::Tuple(_) => "second", + NonExhaustiveEnum::Struct { .. } => "third" + }; + + match enum_unit {}; + //~^ ERROR non-exhaustive patterns: `_` not covered [E0004] + + // Everything below this is expected to compile successfully. + + let enum_unit = NonExhaustiveEnum::Unit; + + match enum_unit { + NonExhaustiveEnum::Unit => 1, + NonExhaustiveEnum::Tuple(_) => 2, + // This particular arm tests that an enum marked as non-exhaustive + // will not error if its variants are matched exhaustively. + NonExhaustiveEnum::Struct { field } => field, + _ => 0 // no error with wildcard + }; + + match enum_unit { + _ => "no error with only wildcard" + }; + + // #53549: Check that variant constructors can still be called normally. + match NonExhaustiveEnum::Unit { + NonExhaustiveEnum::Unit => {}, + _ => {} + }; + + match NonExhaustiveEnum::Tuple(2) { + NonExhaustiveEnum::Tuple(2) => {}, + _ => {} + }; + + match (NonExhaustiveEnum::Unit {}) { + NonExhaustiveEnum::Unit {} => {}, + _ => {} + }; + + match (NonExhaustiveEnum::Tuple { 0: 2 }) { + NonExhaustiveEnum::Tuple { 0: 2 } => {}, + _ => {} + }; + + match (NonExhaustiveEnum::Struct { field: 2 }) { + NonExhaustiveEnum::Struct { field: 2 } => {}, + _ => {} + }; + +} diff --git a/tests/ui/rfcs/rfc-2008-non-exhaustive/enum.stderr b/tests/ui/rfcs/rfc-2008-non-exhaustive/enum.stderr new file mode 100644 index 000000000..872cb9b8b --- /dev/null +++ b/tests/ui/rfcs/rfc-2008-non-exhaustive/enum.stderr @@ -0,0 +1,59 @@ +error[E0004]: non-exhaustive patterns: type `EmptyNonExhaustiveEnum` is non-empty + --> $DIR/enum.rs:7:11 + | +LL | match x {} + | ^ + | +note: `EmptyNonExhaustiveEnum` defined here + --> $DIR/auxiliary/enums.rs:18:1 + | +LL | pub enum EmptyNonExhaustiveEnum {} + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + = note: the matched value is of type `EmptyNonExhaustiveEnum`, which is marked as non-exhaustive +help: ensure that all possible cases are being handled by adding a match arm with a wildcard pattern as shown + | +LL ~ match x { +LL + _ => todo!(), +LL ~ } + | + +error[E0004]: non-exhaustive patterns: `_` not covered + --> $DIR/enum.rs:16:11 + | +LL | match enum_unit { + | ^^^^^^^^^ pattern `_` not covered + | +note: `NonExhaustiveEnum` defined here + --> $DIR/auxiliary/enums.rs:4:1 + | +LL | pub enum NonExhaustiveEnum { + | ^^^^^^^^^^^^^^^^^^^^^^^^^^ + = note: the matched value is of type `NonExhaustiveEnum`, which is marked as non-exhaustive +help: ensure that all possible cases are being handled by adding a match arm with a wildcard pattern or an explicit pattern as shown + | +LL ~ NonExhaustiveEnum::Struct { .. } => "third", +LL + _ => todo!() + | + +error[E0004]: non-exhaustive patterns: `_` not covered + --> $DIR/enum.rs:23:11 + | +LL | match enum_unit {}; + | ^^^^^^^^^ pattern `_` not covered + | +note: `NonExhaustiveEnum` defined here + --> $DIR/auxiliary/enums.rs:4:1 + | +LL | pub enum NonExhaustiveEnum { + | ^^^^^^^^^^^^^^^^^^^^^^^^^^ + = note: the matched value is of type `NonExhaustiveEnum`, which is marked as non-exhaustive +help: ensure that all possible cases are being handled by adding a match arm with a wildcard pattern or an explicit pattern as shown + | +LL ~ match enum_unit { +LL + _ => todo!(), +LL ~ }; + | + +error: aborting due to 3 previous errors + +For more information about this error, try `rustc --explain E0004`. diff --git a/tests/ui/rfcs/rfc-2008-non-exhaustive/enum_same_crate.rs b/tests/ui/rfcs/rfc-2008-non-exhaustive/enum_same_crate.rs new file mode 100644 index 000000000..54e42917f --- /dev/null +++ b/tests/ui/rfcs/rfc-2008-non-exhaustive/enum_same_crate.rs @@ -0,0 +1,18 @@ +// run-pass + +#[non_exhaustive] +pub enum NonExhaustiveEnum { + Unit, + Tuple(u32), + Struct { field: u32 } +} + +fn main() { + let enum_unit = NonExhaustiveEnum::Unit; + + match enum_unit { + NonExhaustiveEnum::Unit => "first", + NonExhaustiveEnum::Tuple(_) => "second", + NonExhaustiveEnum::Struct { .. } => "third", + }; +} diff --git a/tests/ui/rfcs/rfc-2008-non-exhaustive/enum_same_crate_empty_match.rs b/tests/ui/rfcs/rfc-2008-non-exhaustive/enum_same_crate_empty_match.rs new file mode 100644 index 000000000..69a283c31 --- /dev/null +++ b/tests/ui/rfcs/rfc-2008-non-exhaustive/enum_same_crate_empty_match.rs @@ -0,0 +1,37 @@ +#![deny(unreachable_patterns)] + +#[non_exhaustive] +pub enum NonExhaustiveEnum { + Unit, + //~^ not covered + Tuple(u32), + //~^ not covered + Struct { field: u32 } + //~^ not covered +} + +pub enum NormalEnum { + Unit, + //~^ not covered + Tuple(u32), + //~^ not covered + Struct { field: u32 } + //~^ not covered +} + +#[non_exhaustive] +pub enum EmptyNonExhaustiveEnum {} + +fn empty_non_exhaustive(x: EmptyNonExhaustiveEnum) { + match x {} + match x { + _ => {} //~ ERROR unreachable pattern + } +} + +fn main() { + match NonExhaustiveEnum::Unit {} + //~^ ERROR `NonExhaustiveEnum::Unit`, `NonExhaustiveEnum::Tuple(_)` and `NonExhaustiveEnum::Struct { .. }` not covered [E0004] + match NormalEnum::Unit {} + //~^ ERROR `NormalEnum::Unit`, `NormalEnum::Tuple(_)` and `NormalEnum::Struct { .. }` not covered [E0004] +} diff --git a/tests/ui/rfcs/rfc-2008-non-exhaustive/enum_same_crate_empty_match.stderr b/tests/ui/rfcs/rfc-2008-non-exhaustive/enum_same_crate_empty_match.stderr new file mode 100644 index 000000000..de1bf8be8 --- /dev/null +++ b/tests/ui/rfcs/rfc-2008-non-exhaustive/enum_same_crate_empty_match.stderr @@ -0,0 +1,69 @@ +error: unreachable pattern + --> $DIR/enum_same_crate_empty_match.rs:28:9 + | +LL | _ => {} + | ^ + | +note: the lint level is defined here + --> $DIR/enum_same_crate_empty_match.rs:1:9 + | +LL | #![deny(unreachable_patterns)] + | ^^^^^^^^^^^^^^^^^^^^ + +error[E0004]: non-exhaustive patterns: `NonExhaustiveEnum::Unit`, `NonExhaustiveEnum::Tuple(_)` and `NonExhaustiveEnum::Struct { .. }` not covered + --> $DIR/enum_same_crate_empty_match.rs:33:11 + | +LL | match NonExhaustiveEnum::Unit {} + | ^^^^^^^^^^^^^^^^^^^^^^^ patterns `NonExhaustiveEnum::Unit`, `NonExhaustiveEnum::Tuple(_)` and `NonExhaustiveEnum::Struct { .. }` not covered + | +note: `NonExhaustiveEnum` defined here + --> $DIR/enum_same_crate_empty_match.rs:5:5 + | +LL | pub enum NonExhaustiveEnum { + | ----------------- +LL | Unit, + | ^^^^ not covered +LL | +LL | Tuple(u32), + | ^^^^^ not covered +LL | +LL | Struct { field: u32 } + | ^^^^^^ not covered + = note: the matched value is of type `NonExhaustiveEnum` +help: ensure that all possible cases are being handled by adding a match arm with a wildcard pattern, a match arm with multiple or-patterns as shown, or multiple match arms + | +LL ~ match NonExhaustiveEnum::Unit { +LL + NonExhaustiveEnum::Unit | NonExhaustiveEnum::Tuple(_) | NonExhaustiveEnum::Struct { .. } => todo!(), +LL + } + | + +error[E0004]: non-exhaustive patterns: `NormalEnum::Unit`, `NormalEnum::Tuple(_)` and `NormalEnum::Struct { .. }` not covered + --> $DIR/enum_same_crate_empty_match.rs:35:11 + | +LL | match NormalEnum::Unit {} + | ^^^^^^^^^^^^^^^^ patterns `NormalEnum::Unit`, `NormalEnum::Tuple(_)` and `NormalEnum::Struct { .. }` not covered + | +note: `NormalEnum` defined here + --> $DIR/enum_same_crate_empty_match.rs:14:5 + | +LL | pub enum NormalEnum { + | ---------- +LL | Unit, + | ^^^^ not covered +LL | +LL | Tuple(u32), + | ^^^^^ not covered +LL | +LL | Struct { field: u32 } + | ^^^^^^ not covered + = note: the matched value is of type `NormalEnum` +help: ensure that all possible cases are being handled by adding a match arm with a wildcard pattern, a match arm with multiple or-patterns as shown, or multiple match arms + | +LL ~ match NormalEnum::Unit { +LL + NormalEnum::Unit | NormalEnum::Tuple(_) | NormalEnum::Struct { .. } => todo!(), +LL + } + | + +error: aborting due to 3 previous errors + +For more information about this error, try `rustc --explain E0004`. diff --git a/tests/ui/rfcs/rfc-2008-non-exhaustive/improper_ctypes/auxiliary/types.rs b/tests/ui/rfcs/rfc-2008-non-exhaustive/improper_ctypes/auxiliary/types.rs new file mode 100644 index 000000000..d6251fcb7 --- /dev/null +++ b/tests/ui/rfcs/rfc-2008-non-exhaustive/improper_ctypes/auxiliary/types.rs @@ -0,0 +1,29 @@ +#[non_exhaustive] +#[repr(C)] +pub enum NonExhaustiveEnum { + Unit, + Tuple(u32), + Struct { field: u32 } +} + +#[non_exhaustive] +#[repr(C)] +pub struct NormalStruct { + pub first_field: u16, + pub second_field: u16, +} + +#[non_exhaustive] +#[repr(C)] +pub struct UnitStruct; + +#[non_exhaustive] +#[repr(C)] +pub struct TupleStruct (pub u16, pub u16); + +#[repr(C)] +pub enum NonExhaustiveVariants { + #[non_exhaustive] Unit, + #[non_exhaustive] Tuple(u32), + #[non_exhaustive] Struct { field: u32 } +} diff --git a/tests/ui/rfcs/rfc-2008-non-exhaustive/improper_ctypes/extern_crate_improper.rs b/tests/ui/rfcs/rfc-2008-non-exhaustive/improper_ctypes/extern_crate_improper.rs new file mode 100644 index 000000000..15c0c695f --- /dev/null +++ b/tests/ui/rfcs/rfc-2008-non-exhaustive/improper_ctypes/extern_crate_improper.rs @@ -0,0 +1,24 @@ +// aux-build:types.rs +#![deny(improper_ctypes)] + +extern crate types; + +// This test checks that non-exhaustive types with `#[repr(C)]` from an extern crate are considered +// improper. + +use types::{NonExhaustiveEnum, NonExhaustiveVariants, NormalStruct, TupleStruct, UnitStruct}; + +extern "C" { + pub fn non_exhaustive_enum(_: NonExhaustiveEnum); + //~^ ERROR `extern` block uses type `NonExhaustiveEnum`, which is not FFI-safe + pub fn non_exhaustive_normal_struct(_: NormalStruct); + //~^ ERROR `extern` block uses type `NormalStruct`, which is not FFI-safe + pub fn non_exhaustive_unit_struct(_: UnitStruct); + //~^ ERROR `extern` block uses type `UnitStruct`, which is not FFI-safe + pub fn non_exhaustive_tuple_struct(_: TupleStruct); + //~^ ERROR `extern` block uses type `TupleStruct`, which is not FFI-safe + pub fn non_exhaustive_variant(_: NonExhaustiveVariants); + //~^ ERROR `extern` block uses type `NonExhaustiveVariants`, which is not FFI-safe +} + +fn main() {} diff --git a/tests/ui/rfcs/rfc-2008-non-exhaustive/improper_ctypes/extern_crate_improper.stderr b/tests/ui/rfcs/rfc-2008-non-exhaustive/improper_ctypes/extern_crate_improper.stderr new file mode 100644 index 000000000..43c8e1015 --- /dev/null +++ b/tests/ui/rfcs/rfc-2008-non-exhaustive/improper_ctypes/extern_crate_improper.stderr @@ -0,0 +1,47 @@ +error: `extern` block uses type `NonExhaustiveEnum`, which is not FFI-safe + --> $DIR/extern_crate_improper.rs:12:35 + | +LL | pub fn non_exhaustive_enum(_: NonExhaustiveEnum); + | ^^^^^^^^^^^^^^^^^ not FFI-safe + | + = note: this enum is non-exhaustive +note: the lint level is defined here + --> $DIR/extern_crate_improper.rs:2:9 + | +LL | #![deny(improper_ctypes)] + | ^^^^^^^^^^^^^^^ + +error: `extern` block uses type `NormalStruct`, which is not FFI-safe + --> $DIR/extern_crate_improper.rs:14:44 + | +LL | pub fn non_exhaustive_normal_struct(_: NormalStruct); + | ^^^^^^^^^^^^ not FFI-safe + | + = note: this struct is non-exhaustive + +error: `extern` block uses type `UnitStruct`, which is not FFI-safe + --> $DIR/extern_crate_improper.rs:16:42 + | +LL | pub fn non_exhaustive_unit_struct(_: UnitStruct); + | ^^^^^^^^^^ not FFI-safe + | + = note: this struct is non-exhaustive + +error: `extern` block uses type `TupleStruct`, which is not FFI-safe + --> $DIR/extern_crate_improper.rs:18:43 + | +LL | pub fn non_exhaustive_tuple_struct(_: TupleStruct); + | ^^^^^^^^^^^ not FFI-safe + | + = note: this struct is non-exhaustive + +error: `extern` block uses type `NonExhaustiveVariants`, which is not FFI-safe + --> $DIR/extern_crate_improper.rs:20:38 + | +LL | pub fn non_exhaustive_variant(_: NonExhaustiveVariants); + | ^^^^^^^^^^^^^^^^^^^^^ not FFI-safe + | + = note: this enum has non-exhaustive variants + +error: aborting due to 5 previous errors + diff --git a/tests/ui/rfcs/rfc-2008-non-exhaustive/improper_ctypes/same_crate_proper.rs b/tests/ui/rfcs/rfc-2008-non-exhaustive/improper_ctypes/same_crate_proper.rs new file mode 100644 index 000000000..fe4ae345d --- /dev/null +++ b/tests/ui/rfcs/rfc-2008-non-exhaustive/improper_ctypes/same_crate_proper.rs @@ -0,0 +1,48 @@ +// check-pass +#![deny(improper_ctypes)] + +// This test checks that non-exhaustive types with `#[repr(C)]` are considered proper within +// the defining crate. + +#[non_exhaustive] +#[repr(C)] +pub enum NonExhaustiveEnum { + Unit, + Tuple(u32), + Struct { field: u32 }, +} + +#[non_exhaustive] +#[repr(C)] +pub struct NormalStruct { + pub first_field: u16, + pub second_field: u16, +} + +#[non_exhaustive] +#[repr(C)] +pub struct UnitStruct; + +#[non_exhaustive] +#[repr(C)] +pub struct TupleStruct(pub u16, pub u16); + +#[repr(C)] +pub enum NonExhaustiveVariants { + #[non_exhaustive] + Unit, + #[non_exhaustive] + Tuple(u32), + #[non_exhaustive] + Struct { field: u32 }, +} + +extern "C" { + // Unit structs aren't tested here because they will trigger `improper_ctypes` anyway. + pub fn non_exhaustive_enum(_: NonExhaustiveEnum); + pub fn non_exhaustive_normal_struct(_: NormalStruct); + pub fn non_exhaustive_tuple_struct(_: TupleStruct); + pub fn non_exhaustive_variant(_: NonExhaustiveVariants); +} + +fn main() {} diff --git a/tests/ui/rfcs/rfc-2008-non-exhaustive/invalid-attribute.rs b/tests/ui/rfcs/rfc-2008-non-exhaustive/invalid-attribute.rs new file mode 100644 index 000000000..143f9a300 --- /dev/null +++ b/tests/ui/rfcs/rfc-2008-non-exhaustive/invalid-attribute.rs @@ -0,0 +1,16 @@ +#[non_exhaustive(anything)] +//~^ ERROR malformed `non_exhaustive` attribute +struct Foo; + +#[non_exhaustive] +//~^ ERROR attribute should be applied to a struct or enum [E0701] +trait Bar { } + +#[non_exhaustive] +//~^ ERROR attribute should be applied to a struct or enum [E0701] +union Baz { + f1: u16, + f2: u16 +} + +fn main() { } diff --git a/tests/ui/rfcs/rfc-2008-non-exhaustive/invalid-attribute.stderr b/tests/ui/rfcs/rfc-2008-non-exhaustive/invalid-attribute.stderr new file mode 100644 index 000000000..136cd763b --- /dev/null +++ b/tests/ui/rfcs/rfc-2008-non-exhaustive/invalid-attribute.stderr @@ -0,0 +1,30 @@ +error: malformed `non_exhaustive` attribute input + --> $DIR/invalid-attribute.rs:1:1 + | +LL | #[non_exhaustive(anything)] + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: must be of the form: `#[non_exhaustive]` + +error[E0701]: attribute should be applied to a struct or enum + --> $DIR/invalid-attribute.rs:5:1 + | +LL | #[non_exhaustive] + | ^^^^^^^^^^^^^^^^^ +LL | +LL | trait Bar { } + | ------------- not a struct or enum + +error[E0701]: attribute should be applied to a struct or enum + --> $DIR/invalid-attribute.rs:9:1 + | +LL | #[non_exhaustive] + | ^^^^^^^^^^^^^^^^^ +LL | +LL | / union Baz { +LL | | f1: u16, +LL | | f2: u16 +LL | | } + | |_- not a struct or enum + +error: aborting due to 3 previous errors + +For more information about this error, try `rustc --explain E0701`. diff --git a/tests/ui/rfcs/rfc-2008-non-exhaustive/omitted-patterns.rs b/tests/ui/rfcs/rfc-2008-non-exhaustive/omitted-patterns.rs new file mode 100644 index 000000000..3482af747 --- /dev/null +++ b/tests/ui/rfcs/rfc-2008-non-exhaustive/omitted-patterns.rs @@ -0,0 +1,211 @@ +// Test that the `non_exhaustive_omitted_patterns` lint is triggered correctly. + +#![feature(non_exhaustive_omitted_patterns_lint, unstable_test_feature)] + +// aux-build:enums.rs +extern crate enums; +// aux-build:unstable.rs +extern crate unstable; +// aux-build:structs.rs +extern crate structs; + +use enums::{ + EmptyNonExhaustiveEnum, NestedNonExhaustive, NonExhaustiveEnum, NonExhaustiveSingleVariant, + VariantNonExhaustive, +}; +use unstable::{UnstableEnum, OnlyUnstableEnum, UnstableStruct, OnlyUnstableStruct}; +use structs::{FunctionalRecord, MixedVisFields, NestedStruct, NormalStruct}; + +#[non_exhaustive] +#[derive(Default)] +pub struct Foo { + a: u8, + b: usize, + c: String, +} + +#[non_exhaustive] +pub enum Bar { + A, + B, + C, +} + +fn main() { + let enumeration = Bar::A; + + // Ok: this is a crate local non_exhaustive enum + match enumeration { + Bar::A => {} + Bar::B => {} + #[deny(non_exhaustive_omitted_patterns)] + _ => {} + } + + let non_enum = NonExhaustiveEnum::Unit; + + // Ok: without the attribute + match non_enum { + NonExhaustiveEnum::Unit => {} + NonExhaustiveEnum::Tuple(_) => {} + _ => {} + } + + match non_enum { + NonExhaustiveEnum::Unit => {} + NonExhaustiveEnum::Tuple(_) => {} + #[deny(non_exhaustive_omitted_patterns)] + _ => {} + } + //~^^ some variants are not matched explicitly + + match non_enum { + NonExhaustiveEnum::Unit | NonExhaustiveEnum::Struct { .. } => {} + #[deny(non_exhaustive_omitted_patterns)] + _ => {} + } + //~^^ some variants are not matched explicitly + + let x = 5; + match non_enum { + NonExhaustiveEnum::Unit if x > 10 => {} + NonExhaustiveEnum::Tuple(_) => {} + NonExhaustiveEnum::Struct { .. } => {} + #[deny(non_exhaustive_omitted_patterns)] + _ => {} + } + //~^^ some variants are not matched explicitly + + // Ok: all covered and not `unreachable-patterns` + #[deny(unreachable_patterns)] + match non_enum { + NonExhaustiveEnum::Unit => {} + NonExhaustiveEnum::Tuple(_) => {} + NonExhaustiveEnum::Struct { .. } => {} + #[deny(non_exhaustive_omitted_patterns)] + _ => {} + } + + #[deny(non_exhaustive_omitted_patterns)] + match NestedNonExhaustive::B { + NestedNonExhaustive::A(NonExhaustiveEnum::Unit) => {} + NestedNonExhaustive::A(_) => {} + NestedNonExhaustive::B => {} + _ => {} + } + //~^^ some variants are not matched explicitly + //~^^^^^ some variants are not matched explicitly + + #[warn(non_exhaustive_omitted_patterns)] + match VariantNonExhaustive::Baz(1, 2) { + VariantNonExhaustive::Baz(_, _) => {} + VariantNonExhaustive::Bar { x, .. } => {} + } + //~^^ some fields are not explicitly listed + + #[warn(non_exhaustive_omitted_patterns)] + let FunctionalRecord { first_field, second_field, .. } = FunctionalRecord::default(); + //~^ some fields are not explicitly listed + + // Ok: this is local + #[warn(non_exhaustive_omitted_patterns)] + let Foo { a, b, .. } = Foo::default(); + + #[warn(non_exhaustive_omitted_patterns)] + let NestedStruct { bar: NormalStruct { first_field, .. }, .. } = NestedStruct::default(); + //~^ some fields are not explicitly listed + //~^^ some fields are not explicitly listed + + // Ok: this tests https://github.com/rust-lang/rust/issues/89382 + #[warn(non_exhaustive_omitted_patterns)] + let MixedVisFields { a, b, .. } = MixedVisFields::default(); + + // Ok: because this only has 1 variant + #[deny(non_exhaustive_omitted_patterns)] + match NonExhaustiveSingleVariant::A(true) { + NonExhaustiveSingleVariant::A(true) => {} + _ => {} + } + + #[deny(non_exhaustive_omitted_patterns)] + match NonExhaustiveSingleVariant::A(true) { + _ => {} + } + //~^^ some variants are not matched explicitly + + // Ok: we don't lint on `if let` expressions + #[deny(non_exhaustive_omitted_patterns)] + if let NonExhaustiveEnum::Tuple(_) = non_enum {} + + match UnstableEnum::Stable { + UnstableEnum::Stable => {} + UnstableEnum::Stable2 => {} + #[deny(non_exhaustive_omitted_patterns)] + _ => {} + } + //~^^ some variants are not matched explicitly + + // Ok: the feature is on and all variants are matched + #[deny(non_exhaustive_omitted_patterns)] + match UnstableEnum::Stable { + UnstableEnum::Stable => {} + UnstableEnum::Stable2 => {} + UnstableEnum::Unstable => {} + _ => {} + } + + // Ok: the feature is on and both variants are matched + #[deny(non_exhaustive_omitted_patterns)] + match OnlyUnstableEnum::Unstable { + OnlyUnstableEnum::Unstable => {} + OnlyUnstableEnum::Unstable2 => {} + _ => {} + } + + #[deny(non_exhaustive_omitted_patterns)] + match OnlyUnstableEnum::Unstable { + OnlyUnstableEnum::Unstable => {} + _ => {} + } + //~^^ some variants are not matched explicitly + + #[warn(non_exhaustive_omitted_patterns)] + let OnlyUnstableStruct { unstable, .. } = OnlyUnstableStruct::new(); + //~^ some fields are not explicitly listed + + // OK: both unstable fields are matched with feature on + #[warn(non_exhaustive_omitted_patterns)] + let OnlyUnstableStruct { unstable, unstable2, .. } = OnlyUnstableStruct::new(); + + #[warn(non_exhaustive_omitted_patterns)] + let UnstableStruct { stable, stable2, .. } = UnstableStruct::default(); + //~^ some fields are not explicitly listed + + // OK: both unstable and stable fields are matched with feature on + #[warn(non_exhaustive_omitted_patterns)] + let UnstableStruct { stable, stable2, unstable, .. } = UnstableStruct::default(); + + // Ok: local bindings are allowed + #[deny(non_exhaustive_omitted_patterns)] + let local = NonExhaustiveEnum::Unit; + + // Ok: missing patterns will be blocked by the pattern being refutable + #[deny(non_exhaustive_omitted_patterns)] + let local_refutable @ NonExhaustiveEnum::Unit = NonExhaustiveEnum::Unit; + //~^ refutable pattern in local binding + + // Check that matching on a reference results in a correctly spanned diagnostic + #[deny(non_exhaustive_omitted_patterns)] + match &non_enum { + NonExhaustiveEnum::Unit => {} + NonExhaustiveEnum::Tuple(_) => {} + _ => {} + } + //~^^ some variants are not matched explicitly +} + +#[deny(non_exhaustive_omitted_patterns)] +// Ok: Pattern in a param is always wildcard +pub fn takes_non_exhaustive(_: NonExhaustiveEnum) { + let _closure = |_: NonExhaustiveEnum| {}; +} diff --git a/tests/ui/rfcs/rfc-2008-non-exhaustive/omitted-patterns.stderr b/tests/ui/rfcs/rfc-2008-non-exhaustive/omitted-patterns.stderr new file mode 100644 index 000000000..923394474 --- /dev/null +++ b/tests/ui/rfcs/rfc-2008-non-exhaustive/omitted-patterns.stderr @@ -0,0 +1,217 @@ +warning: some fields are not explicitly listed + --> $DIR/omitted-patterns.rs:102:9 + | +LL | VariantNonExhaustive::Bar { x, .. } => {} + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ field `y` not listed + | + = help: ensure that all fields are mentioned explicitly by adding the suggested fields + = note: the pattern is of type `VariantNonExhaustive` and the `non_exhaustive_omitted_patterns` attribute was found +note: the lint level is defined here + --> $DIR/omitted-patterns.rs:99:12 + | +LL | #[warn(non_exhaustive_omitted_patterns)] + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + +warning: some fields are not explicitly listed + --> $DIR/omitted-patterns.rs:107:9 + | +LL | let FunctionalRecord { first_field, second_field, .. } = FunctionalRecord::default(); + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ field `third_field` not listed + | + = help: ensure that all fields are mentioned explicitly by adding the suggested fields + = note: the pattern is of type `FunctionalRecord` and the `non_exhaustive_omitted_patterns` attribute was found +note: the lint level is defined here + --> $DIR/omitted-patterns.rs:106:12 + | +LL | #[warn(non_exhaustive_omitted_patterns)] + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + +warning: some fields are not explicitly listed + --> $DIR/omitted-patterns.rs:115:29 + | +LL | let NestedStruct { bar: NormalStruct { first_field, .. }, .. } = NestedStruct::default(); + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ field `second_field` not listed + | + = help: ensure that all fields are mentioned explicitly by adding the suggested fields + = note: the pattern is of type `NormalStruct` and the `non_exhaustive_omitted_patterns` attribute was found +note: the lint level is defined here + --> $DIR/omitted-patterns.rs:114:12 + | +LL | #[warn(non_exhaustive_omitted_patterns)] + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + +warning: some fields are not explicitly listed + --> $DIR/omitted-patterns.rs:115:9 + | +LL | let NestedStruct { bar: NormalStruct { first_field, .. }, .. } = NestedStruct::default(); + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ field `foo` not listed + | + = help: ensure that all fields are mentioned explicitly by adding the suggested fields + = note: the pattern is of type `NestedStruct` and the `non_exhaustive_omitted_patterns` attribute was found + +warning: some fields are not explicitly listed + --> $DIR/omitted-patterns.rs:173:9 + | +LL | let OnlyUnstableStruct { unstable, .. } = OnlyUnstableStruct::new(); + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ field `unstable2` not listed + | + = help: ensure that all fields are mentioned explicitly by adding the suggested fields + = note: the pattern is of type `OnlyUnstableStruct` and the `non_exhaustive_omitted_patterns` attribute was found +note: the lint level is defined here + --> $DIR/omitted-patterns.rs:172:12 + | +LL | #[warn(non_exhaustive_omitted_patterns)] + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + +warning: some fields are not explicitly listed + --> $DIR/omitted-patterns.rs:181:9 + | +LL | let UnstableStruct { stable, stable2, .. } = UnstableStruct::default(); + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ field `unstable` not listed + | + = help: ensure that all fields are mentioned explicitly by adding the suggested fields + = note: the pattern is of type `UnstableStruct` and the `non_exhaustive_omitted_patterns` attribute was found +note: the lint level is defined here + --> $DIR/omitted-patterns.rs:180:12 + | +LL | #[warn(non_exhaustive_omitted_patterns)] + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + +error: some variants are not matched explicitly + --> $DIR/omitted-patterns.rs:58:9 + | +LL | _ => {} + | ^ pattern `NonExhaustiveEnum::Struct { .. }` not covered + | + = help: ensure that all variants are matched explicitly by adding the suggested match arms + = note: the matched value is of type `NonExhaustiveEnum` and the `non_exhaustive_omitted_patterns` attribute was found +note: the lint level is defined here + --> $DIR/omitted-patterns.rs:57:16 + | +LL | #[deny(non_exhaustive_omitted_patterns)] + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + +error: some variants are not matched explicitly + --> $DIR/omitted-patterns.rs:65:9 + | +LL | _ => {} + | ^ pattern `NonExhaustiveEnum::Tuple(_)` not covered + | + = help: ensure that all variants are matched explicitly by adding the suggested match arms + = note: the matched value is of type `NonExhaustiveEnum` and the `non_exhaustive_omitted_patterns` attribute was found +note: the lint level is defined here + --> $DIR/omitted-patterns.rs:64:16 + | +LL | #[deny(non_exhaustive_omitted_patterns)] + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + +error: some variants are not matched explicitly + --> $DIR/omitted-patterns.rs:75:9 + | +LL | _ => {} + | ^ pattern `NonExhaustiveEnum::Unit` not covered + | + = help: ensure that all variants are matched explicitly by adding the suggested match arms + = note: the matched value is of type `NonExhaustiveEnum` and the `non_exhaustive_omitted_patterns` attribute was found +note: the lint level is defined here + --> $DIR/omitted-patterns.rs:74:16 + | +LL | #[deny(non_exhaustive_omitted_patterns)] + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + +error: some variants are not matched explicitly + --> $DIR/omitted-patterns.rs:92:32 + | +LL | NestedNonExhaustive::A(_) => {} + | ^ patterns `NonExhaustiveEnum::Tuple(_)` and `NonExhaustiveEnum::Struct { .. }` not covered + | + = help: ensure that all variants are matched explicitly by adding the suggested match arms + = note: the matched value is of type `NonExhaustiveEnum` and the `non_exhaustive_omitted_patterns` attribute was found +note: the lint level is defined here + --> $DIR/omitted-patterns.rs:89:12 + | +LL | #[deny(non_exhaustive_omitted_patterns)] + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + +error: some variants are not matched explicitly + --> $DIR/omitted-patterns.rs:94:9 + | +LL | _ => {} + | ^ pattern `NestedNonExhaustive::C` not covered + | + = help: ensure that all variants are matched explicitly by adding the suggested match arms + = note: the matched value is of type `NestedNonExhaustive` and the `non_exhaustive_omitted_patterns` attribute was found + +error: some variants are not matched explicitly + --> $DIR/omitted-patterns.rs:132:9 + | +LL | _ => {} + | ^ pattern `NonExhaustiveSingleVariant::A(_)` not covered + | + = help: ensure that all variants are matched explicitly by adding the suggested match arms + = note: the matched value is of type `NonExhaustiveSingleVariant` and the `non_exhaustive_omitted_patterns` attribute was found +note: the lint level is defined here + --> $DIR/omitted-patterns.rs:130:12 + | +LL | #[deny(non_exhaustive_omitted_patterns)] + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + +error: some variants are not matched explicitly + --> $DIR/omitted-patterns.rs:144:9 + | +LL | _ => {} + | ^ pattern `UnstableEnum::Unstable` not covered + | + = help: ensure that all variants are matched explicitly by adding the suggested match arms + = note: the matched value is of type `UnstableEnum` and the `non_exhaustive_omitted_patterns` attribute was found +note: the lint level is defined here + --> $DIR/omitted-patterns.rs:143:16 + | +LL | #[deny(non_exhaustive_omitted_patterns)] + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + +error: some variants are not matched explicitly + --> $DIR/omitted-patterns.rs:168:9 + | +LL | _ => {} + | ^ pattern `OnlyUnstableEnum::Unstable2` not covered + | + = help: ensure that all variants are matched explicitly by adding the suggested match arms + = note: the matched value is of type `OnlyUnstableEnum` and the `non_exhaustive_omitted_patterns` attribute was found +note: the lint level is defined here + --> $DIR/omitted-patterns.rs:165:12 + | +LL | #[deny(non_exhaustive_omitted_patterns)] + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + +error[E0005]: refutable pattern in local binding + --> $DIR/omitted-patterns.rs:194:9 + | +LL | let local_refutable @ NonExhaustiveEnum::Unit = NonExhaustiveEnum::Unit; + | ^^^^^^^^^^^^^^^ pattern `_` not covered + | + = note: `let` bindings require an "irrefutable pattern", like a `struct` or an `enum` with only one variant + = note: for more information, visit https://doc.rust-lang.org/book/ch18-02-refutability.html + = note: the matched value is of type `NonExhaustiveEnum` +help: you might want to use `let else` to handle the variant that isn't matched + | +LL | let local_refutable @ NonExhaustiveEnum::Unit = NonExhaustiveEnum::Unit else { todo!() }; + | ++++++++++++++++ + +error: some variants are not matched explicitly + --> $DIR/omitted-patterns.rs:202:9 + | +LL | _ => {} + | ^ pattern `NonExhaustiveEnum::Struct { .. }` not covered + | + = help: ensure that all variants are matched explicitly by adding the suggested match arms + = note: the matched value is of type `NonExhaustiveEnum` and the `non_exhaustive_omitted_patterns` attribute was found +note: the lint level is defined here + --> $DIR/omitted-patterns.rs:198:12 + | +LL | #[deny(non_exhaustive_omitted_patterns)] + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + +error: aborting due to 10 previous errors; 6 warnings emitted + +For more information about this error, try `rustc --explain E0005`. diff --git a/tests/ui/rfcs/rfc-2008-non-exhaustive/stable-omitted-patterns.rs b/tests/ui/rfcs/rfc-2008-non-exhaustive/stable-omitted-patterns.rs new file mode 100644 index 000000000..82ee68687 --- /dev/null +++ b/tests/ui/rfcs/rfc-2008-non-exhaustive/stable-omitted-patterns.rs @@ -0,0 +1,45 @@ +// Test that the `non_exhaustive_omitted_patterns` lint is triggered correctly with variants +// marked stable and unstable. + +#![feature(non_exhaustive_omitted_patterns_lint)] + +// aux-build:unstable.rs +extern crate unstable; + +use unstable::{UnstableEnum, OnlyUnstableEnum, UnstableStruct, OnlyUnstableStruct}; + +fn main() { + // OK: this matches all the stable variants + match UnstableEnum::Stable { + UnstableEnum::Stable => {} + UnstableEnum::Stable2 => {} + #[deny(non_exhaustive_omitted_patterns)] + _ => {} + } + + match UnstableEnum::Stable { + UnstableEnum::Stable => {} + #[deny(non_exhaustive_omitted_patterns)] + _ => {} + } + //~^^ some variants are not matched explicitly + + // Ok: although this is a bit odd, we don't have anything to report + // since there is no stable variants and the feature is off + #[deny(non_exhaustive_omitted_patterns)] + match OnlyUnstableEnum::new() { + _ => {} + } + + // Ok: Same as the above enum (no fields can be matched on) + #[warn(non_exhaustive_omitted_patterns)] + let OnlyUnstableStruct { .. } = OnlyUnstableStruct::new(); + + #[warn(non_exhaustive_omitted_patterns)] + let UnstableStruct { stable, .. } = UnstableStruct::default(); + //~^ some fields are not explicitly listed + + // OK: stable field is matched + #[warn(non_exhaustive_omitted_patterns)] + let UnstableStruct { stable, stable2, .. } = UnstableStruct::default(); +} diff --git a/tests/ui/rfcs/rfc-2008-non-exhaustive/stable-omitted-patterns.stderr b/tests/ui/rfcs/rfc-2008-non-exhaustive/stable-omitted-patterns.stderr new file mode 100644 index 000000000..f38368590 --- /dev/null +++ b/tests/ui/rfcs/rfc-2008-non-exhaustive/stable-omitted-patterns.stderr @@ -0,0 +1,30 @@ +warning: some fields are not explicitly listed + --> $DIR/stable-omitted-patterns.rs:39:9 + | +LL | let UnstableStruct { stable, .. } = UnstableStruct::default(); + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ field `stable2` not listed + | + = help: ensure that all fields are mentioned explicitly by adding the suggested fields + = note: the pattern is of type `UnstableStruct` and the `non_exhaustive_omitted_patterns` attribute was found +note: the lint level is defined here + --> $DIR/stable-omitted-patterns.rs:38:12 + | +LL | #[warn(non_exhaustive_omitted_patterns)] + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + +error: some variants are not matched explicitly + --> $DIR/stable-omitted-patterns.rs:23:9 + | +LL | _ => {} + | ^ pattern `UnstableEnum::Stable2` not covered + | + = help: ensure that all variants are matched explicitly by adding the suggested match arms + = note: the matched value is of type `UnstableEnum` and the `non_exhaustive_omitted_patterns` attribute was found +note: the lint level is defined here + --> $DIR/stable-omitted-patterns.rs:22:16 + | +LL | #[deny(non_exhaustive_omitted_patterns)] + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + +error: aborting due to previous error; 1 warning emitted + diff --git a/tests/ui/rfcs/rfc-2008-non-exhaustive/struct.rs b/tests/ui/rfcs/rfc-2008-non-exhaustive/struct.rs new file mode 100644 index 000000000..07e093c15 --- /dev/null +++ b/tests/ui/rfcs/rfc-2008-non-exhaustive/struct.rs @@ -0,0 +1,49 @@ +// aux-build:structs.rs +extern crate structs; + +use structs::{NormalStruct, UnitStruct, TupleStruct, FunctionalRecord}; + +fn main() { + let fr = FunctionalRecord { + //~^ ERROR cannot create non-exhaustive struct + first_field: 1920, + second_field: 1080, + ..FunctionalRecord::default() + }; + + let ns = NormalStruct { first_field: 640, second_field: 480 }; + //~^ ERROR cannot create non-exhaustive struct + + let NormalStruct { first_field, second_field } = ns; + //~^ ERROR `..` required with struct marked as non-exhaustive + + let ts = TupleStruct(640, 480); + //~^ ERROR cannot initialize a tuple struct which contains private fields [E0423] + + let ts_explicit = structs::TupleStruct(640, 480); + //~^ ERROR tuple struct constructor `TupleStruct` is private [E0603] + + let TupleStruct { 0: first_field, 1: second_field } = ts; + //~^ ERROR `..` required with struct marked as non-exhaustive + + let us = UnitStruct; + //~^ ERROR expected value, found struct `UnitStruct` [E0423] + + let us_explicit = structs::UnitStruct; + //~^ ERROR unit struct `UnitStruct` is private [E0603] + + let UnitStruct { } = us; + //~^ ERROR `..` required with struct marked as non-exhaustive +} + +// Everything below this is expected to compile successfully. + +// We only test matching here as we cannot create non-exhaustive +// structs from another crate. ie. they'll never pass in run-pass tests. +fn match_structs(ns: NormalStruct, ts: TupleStruct, us: UnitStruct) { + let NormalStruct { first_field, second_field, .. } = ns; + + let TupleStruct { 0: first, 1: second, .. } = ts; + + let UnitStruct { .. } = us; +} diff --git a/tests/ui/rfcs/rfc-2008-non-exhaustive/struct.stderr b/tests/ui/rfcs/rfc-2008-non-exhaustive/struct.stderr new file mode 100644 index 000000000..39b1ef1e0 --- /dev/null +++ b/tests/ui/rfcs/rfc-2008-non-exhaustive/struct.stderr @@ -0,0 +1,95 @@ +error[E0423]: expected value, found struct `UnitStruct` + --> $DIR/struct.rs:29:14 + | +LL | let us = UnitStruct; + | ^^^^^^^^^^ constructor is not visible here due to private fields + +error[E0603]: tuple struct constructor `TupleStruct` is private + --> $DIR/struct.rs:23:32 + | +LL | let ts_explicit = structs::TupleStruct(640, 480); + | ^^^^^^^^^^^ private tuple struct constructor + | +note: the tuple struct constructor `TupleStruct` is defined here + --> $DIR/auxiliary/structs.rs:12:1 + | +LL | #[non_exhaustive] + | ----------------- cannot be constructed because it is `#[non_exhaustive]` +LL | pub struct TupleStruct(pub u16, pub u16); + | ^^^^^^^^^^^^^^^^^^^^^^ + +error[E0603]: unit struct `UnitStruct` is private + --> $DIR/struct.rs:32:32 + | +LL | let us_explicit = structs::UnitStruct; + | ^^^^^^^^^^ private unit struct + | +note: the unit struct `UnitStruct` is defined here + --> $DIR/auxiliary/structs.rs:9:1 + | +LL | #[non_exhaustive] + | ----------------- cannot be constructed because it is `#[non_exhaustive]` +LL | pub struct UnitStruct; + | ^^^^^^^^^^^^^^^^^^^^^ + +error[E0639]: cannot create non-exhaustive struct using struct expression + --> $DIR/struct.rs:7:14 + | +LL | let fr = FunctionalRecord { + | ______________^ +LL | | +LL | | first_field: 1920, +LL | | second_field: 1080, +LL | | ..FunctionalRecord::default() +LL | | }; + | |_____^ + +error[E0639]: cannot create non-exhaustive struct using struct expression + --> $DIR/struct.rs:14:14 + | +LL | let ns = NormalStruct { first_field: 640, second_field: 480 }; + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + +error[E0638]: `..` required with struct marked as non-exhaustive + --> $DIR/struct.rs:17:9 + | +LL | let NormalStruct { first_field, second_field } = ns; + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + | +help: add `..` at the end of the field list to ignore all other fields + | +LL | let NormalStruct { first_field, second_field , .. } = ns; + | ~~~~~~ + +error[E0423]: cannot initialize a tuple struct which contains private fields + --> $DIR/struct.rs:20:14 + | +LL | let ts = TupleStruct(640, 480); + | ^^^^^^^^^^^ + +error[E0638]: `..` required with struct marked as non-exhaustive + --> $DIR/struct.rs:26:9 + | +LL | let TupleStruct { 0: first_field, 1: second_field } = ts; + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + | +help: add `..` at the end of the field list to ignore all other fields + | +LL | let TupleStruct { 0: first_field, 1: second_field , .. } = ts; + | ~~~~~~ + +error[E0638]: `..` required with struct marked as non-exhaustive + --> $DIR/struct.rs:35:9 + | +LL | let UnitStruct { } = us; + | ^^^^^^^^^^^^^^ + | +help: add `..` at the end of the field list to ignore all other fields + | +LL | let UnitStruct { .. } = us; + | ~~~~ + +error: aborting due to 9 previous errors + +Some errors have detailed explanations: E0423, E0603, E0638, E0639. +For more information about an error, try `rustc --explain E0423`. diff --git a/tests/ui/rfcs/rfc-2008-non-exhaustive/structs_same_crate.rs b/tests/ui/rfcs/rfc-2008-non-exhaustive/structs_same_crate.rs new file mode 100644 index 000000000..5f76b0cb2 --- /dev/null +++ b/tests/ui/rfcs/rfc-2008-non-exhaustive/structs_same_crate.rs @@ -0,0 +1,32 @@ +// run-pass + +#![allow(unused_variables)] + +#[non_exhaustive] +pub struct NormalStruct { + pub first_field: u16, + pub second_field: u16, +} + +#[non_exhaustive] +pub struct UnitStruct; + +#[non_exhaustive] +pub struct TupleStruct (pub u16, pub u16); + +fn main() { + let ns = NormalStruct { first_field: 640, second_field: 480 }; + + let NormalStruct { first_field, second_field } = ns; + + let ts = TupleStruct { 0: 340, 1: 480 }; + let ts_constructor = TupleStruct(340, 480); + + let TupleStruct { 0: first, 1: second } = ts; + let TupleStruct(first, second) = ts_constructor; + + let us = UnitStruct {}; + let us_constructor = UnitStruct; + + let UnitStruct { } = us; +} diff --git a/tests/ui/rfcs/rfc-2008-non-exhaustive/uninhabited/auxiliary/uninhabited.rs b/tests/ui/rfcs/rfc-2008-non-exhaustive/uninhabited/auxiliary/uninhabited.rs new file mode 100644 index 000000000..a2735d4cb --- /dev/null +++ b/tests/ui/rfcs/rfc-2008-non-exhaustive/uninhabited/auxiliary/uninhabited.rs @@ -0,0 +1,32 @@ +#![crate_type = "rlib"] +#![feature(never_type)] + +#[non_exhaustive] +pub enum UninhabitedEnum { +} + +#[non_exhaustive] +pub struct UninhabitedStruct { + _priv: !, +} + +#[non_exhaustive] +pub struct UninhabitedTupleStruct(!); + +pub enum UninhabitedVariants { + #[non_exhaustive] Tuple(!), + #[non_exhaustive] Struct { x: ! } +} + +pub enum PartiallyInhabitedVariants { + Tuple(u8), + #[non_exhaustive] Struct { x: ! } +} + +pub struct IndirectUninhabitedEnum(UninhabitedEnum); + +pub struct IndirectUninhabitedStruct(UninhabitedStruct); + +pub struct IndirectUninhabitedTupleStruct(UninhabitedTupleStruct); + +pub struct IndirectUninhabitedVariants(UninhabitedVariants); diff --git a/tests/ui/rfcs/rfc-2008-non-exhaustive/uninhabited/coercions.rs b/tests/ui/rfcs/rfc-2008-non-exhaustive/uninhabited/coercions.rs new file mode 100644 index 000000000..80b9dc4c1 --- /dev/null +++ b/tests/ui/rfcs/rfc-2008-non-exhaustive/uninhabited/coercions.rs @@ -0,0 +1,38 @@ +// aux-build:uninhabited.rs +#![feature(never_type)] + +extern crate uninhabited; + +use uninhabited::{ + UninhabitedEnum, + UninhabitedStruct, + UninhabitedTupleStruct, + UninhabitedVariants, +}; + +// This test checks that uninhabited non-exhaustive types cannot coerce to any type, as the never +// type can. + +struct A; + +fn can_coerce_never_type_to_anything(x: !) -> A { + x +} + +fn cannot_coerce_empty_enum_to_anything(x: UninhabitedEnum) -> A { + x //~ ERROR mismatched types +} + +fn cannot_coerce_empty_tuple_struct_to_anything(x: UninhabitedTupleStruct) -> A { + x //~ ERROR mismatched types +} + +fn cannot_coerce_empty_struct_to_anything(x: UninhabitedStruct) -> A { + x //~ ERROR mismatched types +} + +fn cannot_coerce_enum_with_empty_variants_to_anything(x: UninhabitedVariants) -> A { + x //~ ERROR mismatched types +} + +fn main() {} diff --git a/tests/ui/rfcs/rfc-2008-non-exhaustive/uninhabited/coercions.stderr b/tests/ui/rfcs/rfc-2008-non-exhaustive/uninhabited/coercions.stderr new file mode 100644 index 000000000..c209caab5 --- /dev/null +++ b/tests/ui/rfcs/rfc-2008-non-exhaustive/uninhabited/coercions.stderr @@ -0,0 +1,35 @@ +error[E0308]: mismatched types + --> $DIR/coercions.rs:23:5 + | +LL | fn cannot_coerce_empty_enum_to_anything(x: UninhabitedEnum) -> A { + | - expected `A` because of return type +LL | x + | ^ expected `A`, found `UninhabitedEnum` + +error[E0308]: mismatched types + --> $DIR/coercions.rs:27:5 + | +LL | fn cannot_coerce_empty_tuple_struct_to_anything(x: UninhabitedTupleStruct) -> A { + | - expected `A` because of return type +LL | x + | ^ expected `A`, found `UninhabitedTupleStruct` + +error[E0308]: mismatched types + --> $DIR/coercions.rs:31:5 + | +LL | fn cannot_coerce_empty_struct_to_anything(x: UninhabitedStruct) -> A { + | - expected `A` because of return type +LL | x + | ^ expected `A`, found `UninhabitedStruct` + +error[E0308]: mismatched types + --> $DIR/coercions.rs:35:5 + | +LL | fn cannot_coerce_enum_with_empty_variants_to_anything(x: UninhabitedVariants) -> A { + | - expected `A` because of return type +LL | x + | ^ expected `A`, found `UninhabitedVariants` + +error: aborting due to 4 previous errors + +For more information about this error, try `rustc --explain E0308`. diff --git a/tests/ui/rfcs/rfc-2008-non-exhaustive/uninhabited/coercions_same_crate.rs b/tests/ui/rfcs/rfc-2008-non-exhaustive/uninhabited/coercions_same_crate.rs new file mode 100644 index 000000000..6b911dd98 --- /dev/null +++ b/tests/ui/rfcs/rfc-2008-non-exhaustive/uninhabited/coercions_same_crate.rs @@ -0,0 +1,45 @@ +#![feature(never_type)] + +#[non_exhaustive] +pub enum UninhabitedEnum { +} + +#[non_exhaustive] +pub struct UninhabitedTupleStruct(!); + +#[non_exhaustive] +pub struct UninhabitedStruct { + _priv: !, +} + +pub enum UninhabitedVariants { + #[non_exhaustive] Tuple(!), + #[non_exhaustive] Struct { x: ! } +} + +struct A; + +// This test checks that uninhabited non-exhaustive types defined in the same crate cannot coerce +// to any type, as the never type can. + +fn can_coerce_never_type_to_anything(x: !) -> A { + x +} + +fn cannot_coerce_empty_enum_to_anything(x: UninhabitedEnum) -> A { + x //~ ERROR mismatched types +} + +fn cannot_coerce_empty_tuple_struct_to_anything(x: UninhabitedTupleStruct) -> A { + x //~ ERROR mismatched types +} + +fn cannot_coerce_empty_struct_to_anything(x: UninhabitedStruct) -> A { + x //~ ERROR mismatched types +} + +fn cannot_coerce_enum_with_empty_variants_to_anything(x: UninhabitedVariants) -> A { + x //~ ERROR mismatched types +} + +fn main() {} diff --git a/tests/ui/rfcs/rfc-2008-non-exhaustive/uninhabited/coercions_same_crate.stderr b/tests/ui/rfcs/rfc-2008-non-exhaustive/uninhabited/coercions_same_crate.stderr new file mode 100644 index 000000000..289433edf --- /dev/null +++ b/tests/ui/rfcs/rfc-2008-non-exhaustive/uninhabited/coercions_same_crate.stderr @@ -0,0 +1,35 @@ +error[E0308]: mismatched types + --> $DIR/coercions_same_crate.rs:30:5 + | +LL | fn cannot_coerce_empty_enum_to_anything(x: UninhabitedEnum) -> A { + | - expected `A` because of return type +LL | x + | ^ expected `A`, found `UninhabitedEnum` + +error[E0308]: mismatched types + --> $DIR/coercions_same_crate.rs:34:5 + | +LL | fn cannot_coerce_empty_tuple_struct_to_anything(x: UninhabitedTupleStruct) -> A { + | - expected `A` because of return type +LL | x + | ^ expected `A`, found `UninhabitedTupleStruct` + +error[E0308]: mismatched types + --> $DIR/coercions_same_crate.rs:38:5 + | +LL | fn cannot_coerce_empty_struct_to_anything(x: UninhabitedStruct) -> A { + | - expected `A` because of return type +LL | x + | ^ expected `A`, found `UninhabitedStruct` + +error[E0308]: mismatched types + --> $DIR/coercions_same_crate.rs:42:5 + | +LL | fn cannot_coerce_enum_with_empty_variants_to_anything(x: UninhabitedVariants) -> A { + | - expected `A` because of return type +LL | x + | ^ expected `A`, found `UninhabitedVariants` + +error: aborting due to 4 previous errors + +For more information about this error, try `rustc --explain E0308`. diff --git a/tests/ui/rfcs/rfc-2008-non-exhaustive/uninhabited/indirect_match.rs b/tests/ui/rfcs/rfc-2008-non-exhaustive/uninhabited/indirect_match.rs new file mode 100644 index 000000000..98a7fdbc5 --- /dev/null +++ b/tests/ui/rfcs/rfc-2008-non-exhaustive/uninhabited/indirect_match.rs @@ -0,0 +1,36 @@ +// aux-build:uninhabited.rs +#![feature(never_type)] + +extern crate uninhabited; + +use uninhabited::{ + IndirectUninhabitedEnum, + IndirectUninhabitedStruct, + IndirectUninhabitedTupleStruct, + IndirectUninhabitedVariants, +}; + +struct A; + +// This test checks that an empty match on a non-exhaustive uninhabited type through a level of +// indirection from an extern crate will not compile. + +fn cannot_empty_match_on_empty_enum_to_anything(x: IndirectUninhabitedEnum) -> A { + match x {} //~ ERROR non-exhaustive patterns +} + +fn cannot_empty_match_on_empty_struct_to_anything(x: IndirectUninhabitedStruct) -> A { + match x {} //~ ERROR non-exhaustive patterns +} + +fn cannot_empty_match_on_empty_tuple_struct_to_anything(x: IndirectUninhabitedTupleStruct) -> A { + match x {} //~ ERROR non-exhaustive patterns +} + +fn cannot_empty_match_on_enum_with_empty_variants_struct_to_anything( + x: IndirectUninhabitedVariants, +) -> A { + match x {} //~ ERROR non-exhaustive patterns +} + +fn main() {} diff --git a/tests/ui/rfcs/rfc-2008-non-exhaustive/uninhabited/indirect_match.stderr b/tests/ui/rfcs/rfc-2008-non-exhaustive/uninhabited/indirect_match.stderr new file mode 100644 index 000000000..66e93291c --- /dev/null +++ b/tests/ui/rfcs/rfc-2008-non-exhaustive/uninhabited/indirect_match.stderr @@ -0,0 +1,79 @@ +error[E0004]: non-exhaustive patterns: type `IndirectUninhabitedEnum` is non-empty + --> $DIR/indirect_match.rs:19:11 + | +LL | match x {} + | ^ + | +note: `IndirectUninhabitedEnum` defined here + --> $DIR/auxiliary/uninhabited.rs:26:1 + | +LL | pub struct IndirectUninhabitedEnum(UninhabitedEnum); + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + = note: the matched value is of type `IndirectUninhabitedEnum` +help: ensure that all possible cases are being handled by adding a match arm with a wildcard pattern as shown + | +LL ~ match x { +LL + _ => todo!(), +LL ~ } + | + +error[E0004]: non-exhaustive patterns: type `IndirectUninhabitedStruct` is non-empty + --> $DIR/indirect_match.rs:23:11 + | +LL | match x {} + | ^ + | +note: `IndirectUninhabitedStruct` defined here + --> $DIR/auxiliary/uninhabited.rs:28:1 + | +LL | pub struct IndirectUninhabitedStruct(UninhabitedStruct); + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + = note: the matched value is of type `IndirectUninhabitedStruct` +help: ensure that all possible cases are being handled by adding a match arm with a wildcard pattern as shown + | +LL ~ match x { +LL + _ => todo!(), +LL ~ } + | + +error[E0004]: non-exhaustive patterns: type `IndirectUninhabitedTupleStruct` is non-empty + --> $DIR/indirect_match.rs:27:11 + | +LL | match x {} + | ^ + | +note: `IndirectUninhabitedTupleStruct` defined here + --> $DIR/auxiliary/uninhabited.rs:30:1 + | +LL | pub struct IndirectUninhabitedTupleStruct(UninhabitedTupleStruct); + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + = note: the matched value is of type `IndirectUninhabitedTupleStruct` +help: ensure that all possible cases are being handled by adding a match arm with a wildcard pattern as shown + | +LL ~ match x { +LL + _ => todo!(), +LL ~ } + | + +error[E0004]: non-exhaustive patterns: type `IndirectUninhabitedVariants` is non-empty + --> $DIR/indirect_match.rs:33:11 + | +LL | match x {} + | ^ + | +note: `IndirectUninhabitedVariants` defined here + --> $DIR/auxiliary/uninhabited.rs:32:1 + | +LL | pub struct IndirectUninhabitedVariants(UninhabitedVariants); + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + = note: the matched value is of type `IndirectUninhabitedVariants` +help: ensure that all possible cases are being handled by adding a match arm with a wildcard pattern as shown + | +LL ~ match x { +LL + _ => todo!(), +LL ~ } + | + +error: aborting due to 4 previous errors + +For more information about this error, try `rustc --explain E0004`. diff --git a/tests/ui/rfcs/rfc-2008-non-exhaustive/uninhabited/indirect_match_same_crate.rs b/tests/ui/rfcs/rfc-2008-non-exhaustive/uninhabited/indirect_match_same_crate.rs new file mode 100644 index 000000000..8f090fe88 --- /dev/null +++ b/tests/ui/rfcs/rfc-2008-non-exhaustive/uninhabited/indirect_match_same_crate.rs @@ -0,0 +1,51 @@ +#![feature(never_type)] + +#[non_exhaustive] +pub enum UninhabitedEnum { +} + +#[non_exhaustive] +pub struct UninhabitedStruct { + _priv: !, +} + +#[non_exhaustive] +pub struct UninhabitedTupleStruct(!); + +pub enum UninhabitedVariants { + #[non_exhaustive] Tuple(!), + #[non_exhaustive] Struct { x: ! } +} + +pub struct IndirectUninhabitedEnum(UninhabitedEnum); + +pub struct IndirectUninhabitedStruct(UninhabitedStruct); + +pub struct IndirectUninhabitedTupleStruct(UninhabitedTupleStruct); + +pub struct IndirectUninhabitedVariants(UninhabitedVariants); + +struct A; + +// This test checks that an empty match on a non-exhaustive uninhabited type through a level of +// indirection from the defining crate will not compile without `#![feature(exhaustive_patterns)]`. + +fn cannot_empty_match_on_empty_enum_to_anything(x: IndirectUninhabitedEnum) -> A { + match x {} //~ ERROR non-exhaustive patterns +} + +fn cannot_empty_match_on_empty_struct_to_anything(x: IndirectUninhabitedStruct) -> A { + match x {} //~ ERROR non-exhaustive patterns +} + +fn cannot_empty_match_on_empty_tuple_struct_to_anything(x: IndirectUninhabitedTupleStruct) -> A { + match x {} //~ ERROR non-exhaustive patterns +} + +fn cannot_empty_match_on_enum_with_empty_variants_struct_to_anything( + x: IndirectUninhabitedVariants, +) -> A { + match x {} //~ ERROR non-exhaustive patterns +} + +fn main() {} diff --git a/tests/ui/rfcs/rfc-2008-non-exhaustive/uninhabited/indirect_match_same_crate.stderr b/tests/ui/rfcs/rfc-2008-non-exhaustive/uninhabited/indirect_match_same_crate.stderr new file mode 100644 index 000000000..c12190541 --- /dev/null +++ b/tests/ui/rfcs/rfc-2008-non-exhaustive/uninhabited/indirect_match_same_crate.stderr @@ -0,0 +1,79 @@ +error[E0004]: non-exhaustive patterns: type `IndirectUninhabitedEnum` is non-empty + --> $DIR/indirect_match_same_crate.rs:34:11 + | +LL | match x {} + | ^ + | +note: `IndirectUninhabitedEnum` defined here + --> $DIR/indirect_match_same_crate.rs:20:12 + | +LL | pub struct IndirectUninhabitedEnum(UninhabitedEnum); + | ^^^^^^^^^^^^^^^^^^^^^^^ + = note: the matched value is of type `IndirectUninhabitedEnum` +help: ensure that all possible cases are being handled by adding a match arm with a wildcard pattern as shown + | +LL ~ match x { +LL + _ => todo!(), +LL ~ } + | + +error[E0004]: non-exhaustive patterns: type `IndirectUninhabitedStruct` is non-empty + --> $DIR/indirect_match_same_crate.rs:38:11 + | +LL | match x {} + | ^ + | +note: `IndirectUninhabitedStruct` defined here + --> $DIR/indirect_match_same_crate.rs:22:12 + | +LL | pub struct IndirectUninhabitedStruct(UninhabitedStruct); + | ^^^^^^^^^^^^^^^^^^^^^^^^^ + = note: the matched value is of type `IndirectUninhabitedStruct` +help: ensure that all possible cases are being handled by adding a match arm with a wildcard pattern as shown + | +LL ~ match x { +LL + _ => todo!(), +LL ~ } + | + +error[E0004]: non-exhaustive patterns: type `IndirectUninhabitedTupleStruct` is non-empty + --> $DIR/indirect_match_same_crate.rs:42:11 + | +LL | match x {} + | ^ + | +note: `IndirectUninhabitedTupleStruct` defined here + --> $DIR/indirect_match_same_crate.rs:24:12 + | +LL | pub struct IndirectUninhabitedTupleStruct(UninhabitedTupleStruct); + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + = note: the matched value is of type `IndirectUninhabitedTupleStruct` +help: ensure that all possible cases are being handled by adding a match arm with a wildcard pattern as shown + | +LL ~ match x { +LL + _ => todo!(), +LL ~ } + | + +error[E0004]: non-exhaustive patterns: type `IndirectUninhabitedVariants` is non-empty + --> $DIR/indirect_match_same_crate.rs:48:11 + | +LL | match x {} + | ^ + | +note: `IndirectUninhabitedVariants` defined here + --> $DIR/indirect_match_same_crate.rs:26:12 + | +LL | pub struct IndirectUninhabitedVariants(UninhabitedVariants); + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^ + = note: the matched value is of type `IndirectUninhabitedVariants` +help: ensure that all possible cases are being handled by adding a match arm with a wildcard pattern as shown + | +LL ~ match x { +LL + _ => todo!(), +LL ~ } + | + +error: aborting due to 4 previous errors + +For more information about this error, try `rustc --explain E0004`. diff --git a/tests/ui/rfcs/rfc-2008-non-exhaustive/uninhabited/indirect_match_with_exhaustive_patterns.rs b/tests/ui/rfcs/rfc-2008-non-exhaustive/uninhabited/indirect_match_with_exhaustive_patterns.rs new file mode 100644 index 000000000..be86519ec --- /dev/null +++ b/tests/ui/rfcs/rfc-2008-non-exhaustive/uninhabited/indirect_match_with_exhaustive_patterns.rs @@ -0,0 +1,40 @@ +// aux-build:uninhabited.rs +#![deny(unreachable_patterns)] +#![feature(exhaustive_patterns)] +#![feature(never_type)] + +extern crate uninhabited; + +use uninhabited::{ + IndirectUninhabitedEnum, + IndirectUninhabitedStruct, + IndirectUninhabitedTupleStruct, + IndirectUninhabitedVariants, +}; + +struct A; + +// This test checks that an empty match on a non-exhaustive uninhabited type through a level of +// indirection from an extern crate will not compile. In particular, this enables the +// `exhaustive_patterns` feature as this can change the branch used in the compiler to determine +// this. + +fn cannot_empty_match_on_empty_enum_to_anything(x: IndirectUninhabitedEnum) -> A { + match x {} //~ ERROR non-exhaustive patterns +} + +fn cannot_empty_match_on_empty_struct_to_anything(x: IndirectUninhabitedStruct) -> A { + match x {} //~ ERROR non-exhaustive patterns +} + +fn cannot_empty_match_on_empty_tuple_struct_to_anything(x: IndirectUninhabitedTupleStruct) -> A { + match x {} //~ ERROR non-exhaustive patterns +} + +fn cannot_empty_match_on_enum_with_empty_variants_struct_to_anything( + x: IndirectUninhabitedVariants, +) -> A { + match x {} //~ ERROR non-exhaustive patterns +} + +fn main() {} diff --git a/tests/ui/rfcs/rfc-2008-non-exhaustive/uninhabited/indirect_match_with_exhaustive_patterns.stderr b/tests/ui/rfcs/rfc-2008-non-exhaustive/uninhabited/indirect_match_with_exhaustive_patterns.stderr new file mode 100644 index 000000000..ef97c1fa1 --- /dev/null +++ b/tests/ui/rfcs/rfc-2008-non-exhaustive/uninhabited/indirect_match_with_exhaustive_patterns.stderr @@ -0,0 +1,79 @@ +error[E0004]: non-exhaustive patterns: type `IndirectUninhabitedEnum` is non-empty + --> $DIR/indirect_match_with_exhaustive_patterns.rs:23:11 + | +LL | match x {} + | ^ + | +note: `IndirectUninhabitedEnum` defined here + --> $DIR/auxiliary/uninhabited.rs:26:1 + | +LL | pub struct IndirectUninhabitedEnum(UninhabitedEnum); + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + = note: the matched value is of type `IndirectUninhabitedEnum` +help: ensure that all possible cases are being handled by adding a match arm with a wildcard pattern as shown + | +LL ~ match x { +LL + _ => todo!(), +LL ~ } + | + +error[E0004]: non-exhaustive patterns: type `IndirectUninhabitedStruct` is non-empty + --> $DIR/indirect_match_with_exhaustive_patterns.rs:27:11 + | +LL | match x {} + | ^ + | +note: `IndirectUninhabitedStruct` defined here + --> $DIR/auxiliary/uninhabited.rs:28:1 + | +LL | pub struct IndirectUninhabitedStruct(UninhabitedStruct); + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + = note: the matched value is of type `IndirectUninhabitedStruct` +help: ensure that all possible cases are being handled by adding a match arm with a wildcard pattern as shown + | +LL ~ match x { +LL + _ => todo!(), +LL ~ } + | + +error[E0004]: non-exhaustive patterns: type `IndirectUninhabitedTupleStruct` is non-empty + --> $DIR/indirect_match_with_exhaustive_patterns.rs:31:11 + | +LL | match x {} + | ^ + | +note: `IndirectUninhabitedTupleStruct` defined here + --> $DIR/auxiliary/uninhabited.rs:30:1 + | +LL | pub struct IndirectUninhabitedTupleStruct(UninhabitedTupleStruct); + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + = note: the matched value is of type `IndirectUninhabitedTupleStruct` +help: ensure that all possible cases are being handled by adding a match arm with a wildcard pattern as shown + | +LL ~ match x { +LL + _ => todo!(), +LL ~ } + | + +error[E0004]: non-exhaustive patterns: type `IndirectUninhabitedVariants` is non-empty + --> $DIR/indirect_match_with_exhaustive_patterns.rs:37:11 + | +LL | match x {} + | ^ + | +note: `IndirectUninhabitedVariants` defined here + --> $DIR/auxiliary/uninhabited.rs:32:1 + | +LL | pub struct IndirectUninhabitedVariants(UninhabitedVariants); + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + = note: the matched value is of type `IndirectUninhabitedVariants` +help: ensure that all possible cases are being handled by adding a match arm with a wildcard pattern as shown + | +LL ~ match x { +LL + _ => todo!(), +LL ~ } + | + +error: aborting due to 4 previous errors + +For more information about this error, try `rustc --explain E0004`. diff --git a/tests/ui/rfcs/rfc-2008-non-exhaustive/uninhabited/indirect_match_with_exhaustive_patterns_same_crate.rs b/tests/ui/rfcs/rfc-2008-non-exhaustive/uninhabited/indirect_match_with_exhaustive_patterns_same_crate.rs new file mode 100644 index 000000000..60289aa78 --- /dev/null +++ b/tests/ui/rfcs/rfc-2008-non-exhaustive/uninhabited/indirect_match_with_exhaustive_patterns_same_crate.rs @@ -0,0 +1,57 @@ +// check-pass + +#![deny(unreachable_patterns)] +#![feature(exhaustive_patterns)] +#![feature(never_type)] + +#[non_exhaustive] +pub enum UninhabitedEnum { +} + +#[non_exhaustive] +pub struct UninhabitedStruct { + _priv: !, +} + +#[non_exhaustive] +pub struct UninhabitedTupleStruct(!); + +pub enum UninhabitedVariants { + #[non_exhaustive] Tuple(!), + #[non_exhaustive] Struct { x: ! } +} + +pub struct IndirectUninhabitedEnum(UninhabitedEnum); + +pub struct IndirectUninhabitedStruct(UninhabitedStruct); + +pub struct IndirectUninhabitedTupleStruct(UninhabitedTupleStruct); + +pub struct IndirectUninhabitedVariants(UninhabitedVariants); + +struct A; + +// This test checks that an empty match on a non-exhaustive uninhabited type from the defining crate +// will compile. In particular, this enables the `exhaustive_patterns` feature as this can +// change the branch used in the compiler to determine this. +// Codegen is skipped because tests with long names can cause issues on Windows CI, see #60648. + +fn cannot_empty_match_on_empty_enum_to_anything(x: IndirectUninhabitedEnum) -> A { + match x {} +} + +fn cannot_empty_match_on_empty_struct_to_anything(x: IndirectUninhabitedStruct) -> A { + match x {} +} + +fn cannot_empty_match_on_empty_tuple_struct_to_anything(x: IndirectUninhabitedTupleStruct) -> A { + match x {} +} + +fn cannot_empty_match_on_enum_with_empty_variants_struct_to_anything( + x: IndirectUninhabitedVariants, +) -> A { + match x {} +} + +fn main() {} diff --git a/tests/ui/rfcs/rfc-2008-non-exhaustive/uninhabited/issue-65157-repeated-match-arm.rs b/tests/ui/rfcs/rfc-2008-non-exhaustive/uninhabited/issue-65157-repeated-match-arm.rs new file mode 100644 index 000000000..230ac7529 --- /dev/null +++ b/tests/ui/rfcs/rfc-2008-non-exhaustive/uninhabited/issue-65157-repeated-match-arm.rs @@ -0,0 +1,21 @@ +// aux-build:uninhabited.rs +#![deny(unreachable_patterns)] +#![feature(never_type)] + +extern crate uninhabited; + +use uninhabited::PartiallyInhabitedVariants; + +// This test checks a redundant/useless pattern of a non-exhaustive enum/variant is still +// warned against. + +pub fn foo(x: PartiallyInhabitedVariants) { + match x { + PartiallyInhabitedVariants::Struct { .. } => {}, + PartiallyInhabitedVariants::Struct { .. } => {}, + //~^ ERROR unreachable pattern + _ => {}, + } +} + +fn main() { } diff --git a/tests/ui/rfcs/rfc-2008-non-exhaustive/uninhabited/issue-65157-repeated-match-arm.stderr b/tests/ui/rfcs/rfc-2008-non-exhaustive/uninhabited/issue-65157-repeated-match-arm.stderr new file mode 100644 index 000000000..f39e6ee29 --- /dev/null +++ b/tests/ui/rfcs/rfc-2008-non-exhaustive/uninhabited/issue-65157-repeated-match-arm.stderr @@ -0,0 +1,14 @@ +error: unreachable pattern + --> $DIR/issue-65157-repeated-match-arm.rs:15:9 + | +LL | PartiallyInhabitedVariants::Struct { .. } => {}, + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + | +note: the lint level is defined here + --> $DIR/issue-65157-repeated-match-arm.rs:2:9 + | +LL | #![deny(unreachable_patterns)] + | ^^^^^^^^^^^^^^^^^^^^ + +error: aborting due to previous error + diff --git a/tests/ui/rfcs/rfc-2008-non-exhaustive/uninhabited/match.rs b/tests/ui/rfcs/rfc-2008-non-exhaustive/uninhabited/match.rs new file mode 100644 index 000000000..e54098d4d --- /dev/null +++ b/tests/ui/rfcs/rfc-2008-non-exhaustive/uninhabited/match.rs @@ -0,0 +1,34 @@ +// aux-build:uninhabited.rs +#![feature(never_type)] + +extern crate uninhabited; + +use uninhabited::{ + UninhabitedEnum, + UninhabitedStruct, + UninhabitedTupleStruct, + UninhabitedVariants, +}; + +struct A; + +// This test checks that an empty match on a non-exhaustive uninhabited type from an extern crate +// will not compile. + +fn cannot_empty_match_on_empty_enum_to_anything(x: UninhabitedEnum) -> A { + match x {} //~ ERROR non-exhaustive patterns +} + +fn cannot_empty_match_on_empty_struct_to_anything(x: UninhabitedStruct) -> A { + match x {} //~ ERROR non-exhaustive patterns +} + +fn cannot_empty_match_on_empty_tuple_struct_to_anything(x: UninhabitedTupleStruct) -> A { + match x {} //~ ERROR non-exhaustive patterns +} + +fn cannot_empty_match_on_enum_with_empty_variants_struct_to_anything(x: UninhabitedVariants) -> A { + match x {} //~ ERROR non-exhaustive patterns +} + +fn main() {} diff --git a/tests/ui/rfcs/rfc-2008-non-exhaustive/uninhabited/match.stderr b/tests/ui/rfcs/rfc-2008-non-exhaustive/uninhabited/match.stderr new file mode 100644 index 000000000..a9c54af04 --- /dev/null +++ b/tests/ui/rfcs/rfc-2008-non-exhaustive/uninhabited/match.stderr @@ -0,0 +1,83 @@ +error[E0004]: non-exhaustive patterns: type `UninhabitedEnum` is non-empty + --> $DIR/match.rs:19:11 + | +LL | match x {} + | ^ + | +note: `UninhabitedEnum` defined here + --> $DIR/auxiliary/uninhabited.rs:5:1 + | +LL | pub enum UninhabitedEnum { + | ^^^^^^^^^^^^^^^^^^^^^^^^ + = note: the matched value is of type `UninhabitedEnum`, which is marked as non-exhaustive +help: ensure that all possible cases are being handled by adding a match arm with a wildcard pattern as shown + | +LL ~ match x { +LL + _ => todo!(), +LL ~ } + | + +error[E0004]: non-exhaustive patterns: type `UninhabitedStruct` is non-empty + --> $DIR/match.rs:23:11 + | +LL | match x {} + | ^ + | +note: `UninhabitedStruct` defined here + --> $DIR/auxiliary/uninhabited.rs:9:1 + | +LL | pub struct UninhabitedStruct { + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + = note: the matched value is of type `UninhabitedStruct` +help: ensure that all possible cases are being handled by adding a match arm with a wildcard pattern as shown + | +LL ~ match x { +LL + _ => todo!(), +LL ~ } + | + +error[E0004]: non-exhaustive patterns: type `UninhabitedTupleStruct` is non-empty + --> $DIR/match.rs:27:11 + | +LL | match x {} + | ^ + | +note: `UninhabitedTupleStruct` defined here + --> $DIR/auxiliary/uninhabited.rs:14:1 + | +LL | pub struct UninhabitedTupleStruct(!); + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + = note: the matched value is of type `UninhabitedTupleStruct` +help: ensure that all possible cases are being handled by adding a match arm with a wildcard pattern as shown + | +LL ~ match x { +LL + _ => todo!(), +LL ~ } + | + +error[E0004]: non-exhaustive patterns: `UninhabitedVariants::Tuple(_)` and `UninhabitedVariants::Struct { .. }` not covered + --> $DIR/match.rs:31:11 + | +LL | match x {} + | ^ patterns `UninhabitedVariants::Tuple(_)` and `UninhabitedVariants::Struct { .. }` not covered + | +note: `UninhabitedVariants` defined here + --> $DIR/auxiliary/uninhabited.rs:17:23 + | +LL | pub enum UninhabitedVariants { + | ---------------------------- +LL | #[non_exhaustive] Tuple(!), + | ^^^^^ not covered +LL | #[non_exhaustive] Struct { x: ! } + | ^^^^^^ not covered + = note: the matched value is of type `UninhabitedVariants` +help: ensure that all possible cases are being handled by adding a match arm with a wildcard pattern, a match arm with multiple or-patterns as shown, or multiple match arms + | +LL ~ match x { +LL + UninhabitedVariants::Tuple(_) | UninhabitedVariants::Struct { .. } => todo!(), +LL ~ } + | + +error: aborting due to 4 previous errors + +For more information about this error, try `rustc --explain E0004`. diff --git a/tests/ui/rfcs/rfc-2008-non-exhaustive/uninhabited/match_same_crate.rs b/tests/ui/rfcs/rfc-2008-non-exhaustive/uninhabited/match_same_crate.rs new file mode 100644 index 000000000..ebbdfba15 --- /dev/null +++ b/tests/ui/rfcs/rfc-2008-non-exhaustive/uninhabited/match_same_crate.rs @@ -0,0 +1,41 @@ +#![feature(never_type)] + +#[non_exhaustive] +pub enum UninhabitedEnum { +} + +#[non_exhaustive] +pub struct UninhabitedStruct { + _priv: !, +} + +#[non_exhaustive] +pub struct UninhabitedTupleStruct(!); + +pub enum UninhabitedVariants { + #[non_exhaustive] Tuple(!), + #[non_exhaustive] Struct { x: ! } +} + +struct A; + +// This test checks that an empty match on a non-exhaustive uninhabited type from the defining crate +// will compile. + +fn cannot_empty_match_on_empty_enum_to_anything(x: UninhabitedEnum) -> A { + match x {} +} + +fn cannot_empty_match_on_empty_struct_to_anything(x: UninhabitedStruct) -> A { + match x {} //~ ERROR non-exhaustive patterns +} + +fn cannot_empty_match_on_empty_tuple_struct_to_anything(x: UninhabitedTupleStruct) -> A { + match x {} //~ ERROR non-exhaustive patterns +} + +fn cannot_empty_match_on_enum_with_empty_variants_struct_to_anything(x: UninhabitedVariants) -> A { + match x {} //~ ERROR non-exhaustive patterns +} + +fn main() {} diff --git a/tests/ui/rfcs/rfc-2008-non-exhaustive/uninhabited/match_same_crate.stderr b/tests/ui/rfcs/rfc-2008-non-exhaustive/uninhabited/match_same_crate.stderr new file mode 100644 index 000000000..ec2a2f6f0 --- /dev/null +++ b/tests/ui/rfcs/rfc-2008-non-exhaustive/uninhabited/match_same_crate.stderr @@ -0,0 +1,64 @@ +error[E0004]: non-exhaustive patterns: type `UninhabitedStruct` is non-empty + --> $DIR/match_same_crate.rs:30:11 + | +LL | match x {} + | ^ + | +note: `UninhabitedStruct` defined here + --> $DIR/match_same_crate.rs:8:12 + | +LL | pub struct UninhabitedStruct { + | ^^^^^^^^^^^^^^^^^ + = note: the matched value is of type `UninhabitedStruct` +help: ensure that all possible cases are being handled by adding a match arm with a wildcard pattern as shown + | +LL ~ match x { +LL + _ => todo!(), +LL ~ } + | + +error[E0004]: non-exhaustive patterns: type `UninhabitedTupleStruct` is non-empty + --> $DIR/match_same_crate.rs:34:11 + | +LL | match x {} + | ^ + | +note: `UninhabitedTupleStruct` defined here + --> $DIR/match_same_crate.rs:13:12 + | +LL | pub struct UninhabitedTupleStruct(!); + | ^^^^^^^^^^^^^^^^^^^^^^ + = note: the matched value is of type `UninhabitedTupleStruct` +help: ensure that all possible cases are being handled by adding a match arm with a wildcard pattern as shown + | +LL ~ match x { +LL + _ => todo!(), +LL ~ } + | + +error[E0004]: non-exhaustive patterns: `UninhabitedVariants::Tuple(_)` and `UninhabitedVariants::Struct { .. }` not covered + --> $DIR/match_same_crate.rs:38:11 + | +LL | match x {} + | ^ patterns `UninhabitedVariants::Tuple(_)` and `UninhabitedVariants::Struct { .. }` not covered + | +note: `UninhabitedVariants` defined here + --> $DIR/match_same_crate.rs:16:23 + | +LL | pub enum UninhabitedVariants { + | ------------------- +LL | #[non_exhaustive] Tuple(!), + | ^^^^^ not covered +LL | #[non_exhaustive] Struct { x: ! } + | ^^^^^^ not covered + = note: the matched value is of type `UninhabitedVariants` +help: ensure that all possible cases are being handled by adding a match arm with a wildcard pattern, a match arm with multiple or-patterns as shown, or multiple match arms + | +LL ~ match x { +LL + UninhabitedVariants::Tuple(_) | UninhabitedVariants::Struct { .. } => todo!(), +LL ~ } + | + +error: aborting due to 3 previous errors + +For more information about this error, try `rustc --explain E0004`. diff --git a/tests/ui/rfcs/rfc-2008-non-exhaustive/uninhabited/match_with_exhaustive_patterns.rs b/tests/ui/rfcs/rfc-2008-non-exhaustive/uninhabited/match_with_exhaustive_patterns.rs new file mode 100644 index 000000000..900dfff65 --- /dev/null +++ b/tests/ui/rfcs/rfc-2008-non-exhaustive/uninhabited/match_with_exhaustive_patterns.rs @@ -0,0 +1,37 @@ +// aux-build:uninhabited.rs +#![deny(unreachable_patterns)] +#![feature(exhaustive_patterns)] +#![feature(never_type)] + +extern crate uninhabited; + +use uninhabited::{ + UninhabitedEnum, + UninhabitedStruct, + UninhabitedTupleStruct, + UninhabitedVariants, +}; + +struct A; + +// This test checks that an empty match on a non-exhaustive uninhabited type from an extern crate +// will not compile. In particular, this enables the `exhaustive_patterns` feature as this can +// change the branch used in the compiler to determine this. + +fn cannot_empty_match_on_empty_enum_to_anything(x: UninhabitedEnum) -> A { + match x {} //~ ERROR non-exhaustive patterns +} + +fn cannot_empty_match_on_empty_struct_to_anything(x: UninhabitedStruct) -> A { + match x {} //~ ERROR non-exhaustive patterns +} + +fn cannot_empty_match_on_empty_tuple_struct_to_anything(x: UninhabitedTupleStruct) -> A { + match x {} //~ ERROR non-exhaustive patterns +} + +fn cannot_empty_match_on_enum_with_empty_variants_struct_to_anything(x: UninhabitedVariants) -> A { + match x {} //~ ERROR non-exhaustive patterns +} + +fn main() {} diff --git a/tests/ui/rfcs/rfc-2008-non-exhaustive/uninhabited/match_with_exhaustive_patterns.stderr b/tests/ui/rfcs/rfc-2008-non-exhaustive/uninhabited/match_with_exhaustive_patterns.stderr new file mode 100644 index 000000000..b6b777ec5 --- /dev/null +++ b/tests/ui/rfcs/rfc-2008-non-exhaustive/uninhabited/match_with_exhaustive_patterns.stderr @@ -0,0 +1,83 @@ +error[E0004]: non-exhaustive patterns: type `UninhabitedEnum` is non-empty + --> $DIR/match_with_exhaustive_patterns.rs:22:11 + | +LL | match x {} + | ^ + | +note: `UninhabitedEnum` defined here + --> $DIR/auxiliary/uninhabited.rs:5:1 + | +LL | pub enum UninhabitedEnum { + | ^^^^^^^^^^^^^^^^^^^^^^^^ + = note: the matched value is of type `UninhabitedEnum`, which is marked as non-exhaustive +help: ensure that all possible cases are being handled by adding a match arm with a wildcard pattern as shown + | +LL ~ match x { +LL + _ => todo!(), +LL ~ } + | + +error[E0004]: non-exhaustive patterns: type `UninhabitedStruct` is non-empty + --> $DIR/match_with_exhaustive_patterns.rs:26:11 + | +LL | match x {} + | ^ + | +note: `UninhabitedStruct` defined here + --> $DIR/auxiliary/uninhabited.rs:9:1 + | +LL | pub struct UninhabitedStruct { + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + = note: the matched value is of type `UninhabitedStruct` +help: ensure that all possible cases are being handled by adding a match arm with a wildcard pattern as shown + | +LL ~ match x { +LL + _ => todo!(), +LL ~ } + | + +error[E0004]: non-exhaustive patterns: type `UninhabitedTupleStruct` is non-empty + --> $DIR/match_with_exhaustive_patterns.rs:30:11 + | +LL | match x {} + | ^ + | +note: `UninhabitedTupleStruct` defined here + --> $DIR/auxiliary/uninhabited.rs:14:1 + | +LL | pub struct UninhabitedTupleStruct(!); + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + = note: the matched value is of type `UninhabitedTupleStruct` +help: ensure that all possible cases are being handled by adding a match arm with a wildcard pattern as shown + | +LL ~ match x { +LL + _ => todo!(), +LL ~ } + | + +error[E0004]: non-exhaustive patterns: `UninhabitedVariants::Tuple(_)` and `UninhabitedVariants::Struct { .. }` not covered + --> $DIR/match_with_exhaustive_patterns.rs:34:11 + | +LL | match x {} + | ^ patterns `UninhabitedVariants::Tuple(_)` and `UninhabitedVariants::Struct { .. }` not covered + | +note: `UninhabitedVariants` defined here + --> $DIR/auxiliary/uninhabited.rs:17:23 + | +LL | pub enum UninhabitedVariants { + | ---------------------------- +LL | #[non_exhaustive] Tuple(!), + | ^^^^^ not covered +LL | #[non_exhaustive] Struct { x: ! } + | ^^^^^^ not covered + = note: the matched value is of type `UninhabitedVariants` +help: ensure that all possible cases are being handled by adding a match arm with a wildcard pattern, a match arm with multiple or-patterns as shown, or multiple match arms + | +LL ~ match x { +LL + UninhabitedVariants::Tuple(_) | UninhabitedVariants::Struct { .. } => todo!(), +LL ~ } + | + +error: aborting due to 4 previous errors + +For more information about this error, try `rustc --explain E0004`. diff --git a/tests/ui/rfcs/rfc-2008-non-exhaustive/uninhabited/match_with_exhaustive_patterns_same_crate.rs b/tests/ui/rfcs/rfc-2008-non-exhaustive/uninhabited/match_with_exhaustive_patterns_same_crate.rs new file mode 100644 index 000000000..de5530485 --- /dev/null +++ b/tests/ui/rfcs/rfc-2008-non-exhaustive/uninhabited/match_with_exhaustive_patterns_same_crate.rs @@ -0,0 +1,47 @@ +// check-pass + +#![deny(unreachable_patterns)] +#![feature(exhaustive_patterns)] +#![feature(never_type)] + +#[non_exhaustive] +pub enum UninhabitedEnum { +} + +#[non_exhaustive] +pub struct UninhabitedStruct { + _priv: !, +} + +#[non_exhaustive] +pub struct UninhabitedTupleStruct(!); + +pub enum UninhabitedVariants { + #[non_exhaustive] Tuple(!), + #[non_exhaustive] Struct { x: ! } +} + +struct A; + +// This test checks that an empty match on a non-exhaustive uninhabited type from the defining crate +// will compile. In particular, this enables the `exhaustive_patterns` feature as this can +// change the branch used in the compiler to determine this. +// Codegen is skipped because tests with long names can cause issues on Windows CI, see #60648. + +fn cannot_empty_match_on_empty_enum_to_anything(x: UninhabitedEnum) -> A { + match x {} +} + +fn cannot_empty_match_on_empty_struct_to_anything(x: UninhabitedStruct) -> A { + match x {} +} + +fn cannot_empty_match_on_empty_tuple_struct_to_anything(x: UninhabitedTupleStruct) -> A { + match x {} +} + +fn cannot_empty_match_on_enum_with_empty_variants_struct_to_anything(x: UninhabitedVariants) -> A { + match x {} +} + +fn main() {} diff --git a/tests/ui/rfcs/rfc-2008-non-exhaustive/uninhabited/patterns.rs b/tests/ui/rfcs/rfc-2008-non-exhaustive/uninhabited/patterns.rs new file mode 100644 index 000000000..221b5cf6b --- /dev/null +++ b/tests/ui/rfcs/rfc-2008-non-exhaustive/uninhabited/patterns.rs @@ -0,0 +1,59 @@ +// aux-build:uninhabited.rs +// build-pass (FIXME(62277): could be check-pass?) +#![deny(unreachable_patterns)] +#![feature(exhaustive_patterns)] + +extern crate uninhabited; + +use uninhabited::{ + PartiallyInhabitedVariants, + UninhabitedEnum, + UninhabitedStruct, + UninhabitedTupleStruct, + UninhabitedVariants, +}; + +fn uninhabited_enum() -> Option<UninhabitedEnum> { + None +} + +fn uninhabited_variant() -> Option<UninhabitedVariants> { + None +} + +fn partially_inhabited_variant() -> PartiallyInhabitedVariants { + PartiallyInhabitedVariants::Tuple(3) +} + +fn uninhabited_struct() -> Option<UninhabitedStruct> { + None +} + +fn uninhabited_tuple_struct() -> Option<UninhabitedTupleStruct> { + None +} + +// This test checks that non-exhaustive types that would normally be considered uninhabited within +// the defining crate are not considered uninhabited from extern crates. + +fn main() { + match uninhabited_enum() { + Some(_x) => (), // This line would normally error. + None => (), + } + + match uninhabited_variant() { + Some(_x) => (), // This line would normally error. + None => (), + } + + // This line would normally error. + while let PartiallyInhabitedVariants::Struct { x, .. } = partially_inhabited_variant() { + } + + while let Some(_x) = uninhabited_struct() { // This line would normally error. + } + + while let Some(_x) = uninhabited_tuple_struct() { // This line would normally error. + } +} diff --git a/tests/ui/rfcs/rfc-2008-non-exhaustive/uninhabited/patterns_same_crate.rs b/tests/ui/rfcs/rfc-2008-non-exhaustive/uninhabited/patterns_same_crate.rs new file mode 100644 index 000000000..ffc496a97 --- /dev/null +++ b/tests/ui/rfcs/rfc-2008-non-exhaustive/uninhabited/patterns_same_crate.rs @@ -0,0 +1,70 @@ +#![deny(unreachable_patterns)] +#![feature(exhaustive_patterns)] +#![feature(never_type)] + +#[non_exhaustive] +pub enum UninhabitedEnum { +} + +#[non_exhaustive] +pub struct UninhabitedTupleStruct(!); + +#[non_exhaustive] +pub struct UninhabitedStruct { + _priv: !, +} + +pub enum UninhabitedVariants { + #[non_exhaustive] Tuple(!), + #[non_exhaustive] Struct { x: ! } +} + +pub enum PartiallyInhabitedVariants { + Tuple(u8), + #[non_exhaustive] Struct { x: ! } +} + +fn uninhabited_enum() -> Option<UninhabitedEnum> { + None +} + +fn uninhabited_variant() -> Option<UninhabitedVariants> { + None +} + +fn partially_inhabited_variant() -> PartiallyInhabitedVariants { + PartiallyInhabitedVariants::Tuple(3) +} + +fn uninhabited_struct() -> Option<UninhabitedStruct> { + None +} + +fn uninhabited_tuple_struct() -> Option<UninhabitedTupleStruct> { + None +} + +// This test checks that non-exhaustive types that would normally be considered uninhabited within +// the defining crate are still considered uninhabited. + +fn main() { + match uninhabited_enum() { + Some(_x) => (), //~ ERROR unreachable pattern + None => (), + } + + match uninhabited_variant() { + Some(_x) => (), //~ ERROR unreachable pattern + None => (), + } + + while let PartiallyInhabitedVariants::Struct { x } = partially_inhabited_variant() { + //~^ ERROR unreachable pattern + } + + while let Some(_x) = uninhabited_struct() { //~ ERROR unreachable pattern + } + + while let Some(_x) = uninhabited_tuple_struct() { //~ ERROR unreachable pattern + } +} diff --git a/tests/ui/rfcs/rfc-2008-non-exhaustive/uninhabited/patterns_same_crate.stderr b/tests/ui/rfcs/rfc-2008-non-exhaustive/uninhabited/patterns_same_crate.stderr new file mode 100644 index 000000000..8bfd6e91f --- /dev/null +++ b/tests/ui/rfcs/rfc-2008-non-exhaustive/uninhabited/patterns_same_crate.stderr @@ -0,0 +1,38 @@ +error: unreachable pattern + --> $DIR/patterns_same_crate.rs:52:9 + | +LL | Some(_x) => (), + | ^^^^^^^^ + | +note: the lint level is defined here + --> $DIR/patterns_same_crate.rs:1:9 + | +LL | #![deny(unreachable_patterns)] + | ^^^^^^^^^^^^^^^^^^^^ + +error: unreachable pattern + --> $DIR/patterns_same_crate.rs:57:9 + | +LL | Some(_x) => (), + | ^^^^^^^^ + +error: unreachable pattern + --> $DIR/patterns_same_crate.rs:61:15 + | +LL | while let PartiallyInhabitedVariants::Struct { x } = partially_inhabited_variant() { + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + +error: unreachable pattern + --> $DIR/patterns_same_crate.rs:65:15 + | +LL | while let Some(_x) = uninhabited_struct() { + | ^^^^^^^^ + +error: unreachable pattern + --> $DIR/patterns_same_crate.rs:68:15 + | +LL | while let Some(_x) = uninhabited_tuple_struct() { + | ^^^^^^^^ + +error: aborting due to 5 previous errors + diff --git a/tests/ui/rfcs/rfc-2008-non-exhaustive/variant.rs b/tests/ui/rfcs/rfc-2008-non-exhaustive/variant.rs new file mode 100644 index 000000000..bc346aea5 --- /dev/null +++ b/tests/ui/rfcs/rfc-2008-non-exhaustive/variant.rs @@ -0,0 +1,33 @@ +// aux-build:variants.rs + +extern crate variants; + +use variants::NonExhaustiveVariants; + +fn main() { + let variant_struct = NonExhaustiveVariants::Struct { field: 640 }; + //~^ ERROR cannot create non-exhaustive variant + + let variant_tuple = NonExhaustiveVariants::Tuple(640); + //~^ ERROR tuple variant `Tuple` is private [E0603] + + let variant_unit = NonExhaustiveVariants::Unit; + //~^ ERROR unit variant `Unit` is private [E0603] + + match variant_struct { + NonExhaustiveVariants::Unit => "", + //~^ ERROR unit variant `Unit` is private [E0603] + NonExhaustiveVariants::Tuple(fe_tpl) => "", + //~^ ERROR tuple variant `Tuple` is private [E0603] + NonExhaustiveVariants::Struct { field } => "" + //~^ ERROR `..` required with variant marked as non-exhaustive + }; + + if let NonExhaustiveVariants::Tuple(fe_tpl) = variant_struct { + //~^ ERROR tuple variant `Tuple` is private [E0603] + } + + if let NonExhaustiveVariants::Struct { field } = variant_struct { + //~^ ERROR `..` required with variant marked as non-exhaustive + } +} diff --git a/tests/ui/rfcs/rfc-2008-non-exhaustive/variant.stderr b/tests/ui/rfcs/rfc-2008-non-exhaustive/variant.stderr new file mode 100644 index 000000000..4083f57a9 --- /dev/null +++ b/tests/ui/rfcs/rfc-2008-non-exhaustive/variant.stderr @@ -0,0 +1,102 @@ +error[E0603]: tuple variant `Tuple` is private + --> $DIR/variant.rs:11:48 + | +LL | let variant_tuple = NonExhaustiveVariants::Tuple(640); + | ^^^^^ private tuple variant + | +note: the tuple variant `Tuple` is defined here + --> $DIR/auxiliary/variants.rs:5:23 + | +LL | #[non_exhaustive] Tuple(u32), + | ----------------- ^^^^^ + | | + | cannot be constructed because it is `#[non_exhaustive]` + +error[E0603]: unit variant `Unit` is private + --> $DIR/variant.rs:14:47 + | +LL | let variant_unit = NonExhaustiveVariants::Unit; + | ^^^^ private unit variant + | +note: the unit variant `Unit` is defined here + --> $DIR/auxiliary/variants.rs:4:23 + | +LL | #[non_exhaustive] Unit, + | ----------------- ^^^^ + | | + | cannot be constructed because it is `#[non_exhaustive]` + +error[E0603]: unit variant `Unit` is private + --> $DIR/variant.rs:18:32 + | +LL | NonExhaustiveVariants::Unit => "", + | ^^^^ private unit variant + | +note: the unit variant `Unit` is defined here + --> $DIR/auxiliary/variants.rs:4:23 + | +LL | #[non_exhaustive] Unit, + | ----------------- ^^^^ + | | + | cannot be constructed because it is `#[non_exhaustive]` + +error[E0603]: tuple variant `Tuple` is private + --> $DIR/variant.rs:20:32 + | +LL | NonExhaustiveVariants::Tuple(fe_tpl) => "", + | ^^^^^ private tuple variant + | +note: the tuple variant `Tuple` is defined here + --> $DIR/auxiliary/variants.rs:5:23 + | +LL | #[non_exhaustive] Tuple(u32), + | ----------------- ^^^^^ + | | + | cannot be constructed because it is `#[non_exhaustive]` + +error[E0603]: tuple variant `Tuple` is private + --> $DIR/variant.rs:26:35 + | +LL | if let NonExhaustiveVariants::Tuple(fe_tpl) = variant_struct { + | ^^^^^ private tuple variant + | +note: the tuple variant `Tuple` is defined here + --> $DIR/auxiliary/variants.rs:5:23 + | +LL | #[non_exhaustive] Tuple(u32), + | ----------------- ^^^^^ + | | + | cannot be constructed because it is `#[non_exhaustive]` + +error[E0639]: cannot create non-exhaustive variant using struct expression + --> $DIR/variant.rs:8:26 + | +LL | let variant_struct = NonExhaustiveVariants::Struct { field: 640 }; + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + +error[E0638]: `..` required with variant marked as non-exhaustive + --> $DIR/variant.rs:22:9 + | +LL | NonExhaustiveVariants::Struct { field } => "" + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + | +help: add `..` at the end of the field list to ignore all other fields + | +LL | NonExhaustiveVariants::Struct { field , .. } => "" + | ~~~~~~ + +error[E0638]: `..` required with variant marked as non-exhaustive + --> $DIR/variant.rs:30:12 + | +LL | if let NonExhaustiveVariants::Struct { field } = variant_struct { + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + | +help: add `..` at the end of the field list to ignore all other fields + | +LL | if let NonExhaustiveVariants::Struct { field , .. } = variant_struct { + | ~~~~~~ + +error: aborting due to 8 previous errors + +Some errors have detailed explanations: E0603, E0638, E0639. +For more information about an error, try `rustc --explain E0603`. diff --git a/tests/ui/rfcs/rfc-2008-non-exhaustive/variants_fictive_visibility.rs b/tests/ui/rfcs/rfc-2008-non-exhaustive/variants_fictive_visibility.rs new file mode 100644 index 000000000..dacaf489a --- /dev/null +++ b/tests/ui/rfcs/rfc-2008-non-exhaustive/variants_fictive_visibility.rs @@ -0,0 +1,12 @@ +// build-pass (FIXME(62277): could be check-pass?) +// aux-build:variants.rs + +extern crate variants; + +const S: u8 = 0; + +// OK, `Struct` in value namespace is crate-private, so it's filtered away +// and there's no conflict with the previously defined `const S`. +use variants::NonExhaustiveVariants::Struct as S; + +fn main() {} diff --git a/tests/ui/rfcs/rfc-2008-non-exhaustive/variants_same_crate.rs b/tests/ui/rfcs/rfc-2008-non-exhaustive/variants_same_crate.rs new file mode 100644 index 000000000..5f2816ec6 --- /dev/null +++ b/tests/ui/rfcs/rfc-2008-non-exhaustive/variants_same_crate.rs @@ -0,0 +1,18 @@ +// run-pass + +pub enum NonExhaustiveVariants { + #[non_exhaustive] Unit, + #[non_exhaustive] Tuple(u32), + #[non_exhaustive] Struct { field: u32 } +} + +fn main() { + let variant_tuple = NonExhaustiveVariants::Tuple(340); + let _variant_struct = NonExhaustiveVariants::Struct { field: 340 }; + + match variant_tuple { + NonExhaustiveVariants::Unit => "", + NonExhaustiveVariants::Tuple(_fe_tpl) => "", + NonExhaustiveVariants::Struct { field: _ } => "" + }; +} diff --git a/tests/ui/rfcs/rfc-2027-object-safe-for-dispatch/downcast-unsafe-trait-objects.rs b/tests/ui/rfcs/rfc-2027-object-safe-for-dispatch/downcast-unsafe-trait-objects.rs new file mode 100644 index 000000000..fa04f4b12 --- /dev/null +++ b/tests/ui/rfcs/rfc-2027-object-safe-for-dispatch/downcast-unsafe-trait-objects.rs @@ -0,0 +1,23 @@ +// Check that we if we get ahold of an object unsafe trait +// object with auto traits and lifetimes, we can downcast it +// +// check-pass + +#![feature(object_safe_for_dispatch)] + +trait Trait: Sized {} + +fn downcast_auto(t: &(dyn Trait + Send)) -> &dyn Trait { + t +} + +fn downcast_lifetime<'a, 'b, 't>(t: &'a (dyn Trait + 't)) + -> &'b (dyn Trait + 't) +where + 'a: 'b, + 't: 'a + 'b, +{ + t +} + +fn main() {} diff --git a/tests/ui/rfcs/rfc-2027-object-safe-for-dispatch/manual-self-impl-for-unsafe-obj.rs b/tests/ui/rfcs/rfc-2027-object-safe-for-dispatch/manual-self-impl-for-unsafe-obj.rs new file mode 100644 index 000000000..721890db4 --- /dev/null +++ b/tests/ui/rfcs/rfc-2027-object-safe-for-dispatch/manual-self-impl-for-unsafe-obj.rs @@ -0,0 +1,66 @@ +// Check that we can manually implement an object-unsafe trait for its trait object. + +// run-pass + +#![feature(object_safe_for_dispatch)] + +trait Bad { + fn stat() -> char { + 'A' + } + fn virt(&self) -> char { + 'B' + } + fn indirect(&self) -> char { + Self::stat() + } +} + +trait Good { + fn good_virt(&self) -> char { + panic!() + } + fn good_indirect(&self) -> char { + panic!() + } +} + +impl<'a> Bad for dyn Bad + 'a { + fn stat() -> char { + 'C' + } + fn virt(&self) -> char { + 'D' + } +} + +struct Struct {} + +impl Bad for Struct {} + +impl Good for Struct {} + +fn main() { + let s = Struct {}; + + let mut res = String::new(); + + // Directly call static. + res.push(Struct::stat()); // "A" + res.push(<dyn Bad>::stat()); // "AC" + + let good: &dyn Good = &s; + + // These look similar enough... + let bad = unsafe { std::mem::transmute::<&dyn Good, &dyn Bad>(good) }; + + // Call virtual. + res.push(s.virt()); // "ACB" + res.push(bad.virt()); // "ACBD" + + // Indirectly call static. + res.push(s.indirect()); // "ACBDA" + res.push(bad.indirect()); // "ACBDAC" + + assert_eq!(&res, "ACBDAC"); +} diff --git a/tests/ui/rfcs/rfc-2027-object-safe-for-dispatch/static-dispatch-unsafe-object.rs b/tests/ui/rfcs/rfc-2027-object-safe-for-dispatch/static-dispatch-unsafe-object.rs new file mode 100644 index 000000000..df97d2c13 --- /dev/null +++ b/tests/ui/rfcs/rfc-2027-object-safe-for-dispatch/static-dispatch-unsafe-object.rs @@ -0,0 +1,37 @@ +// Check that we can statically dispatch methods for object +// unsafe trait objects, directly and indirectly +// +// check-pass + +#![feature(object_safe_for_dispatch)] + +trait Statics { + fn plain() {} + fn generic<T>() {} +} + +trait Trait: Sized {} + +impl<'a> Statics for dyn Trait + 'a {} + +fn static_poly<T: Statics + ?Sized>() { + T::plain(); + T::generic::<usize>(); +} + +fn inferred_poly<T: Statics + ?Sized>(t: &T) { + static_poly::<T>(); + T::plain(); + T::generic::<usize>(); +} + +fn call(t: &dyn Trait) { + static_poly::<dyn Trait>(); + inferred_poly(t); +} + +fn main() { + static_poly::<dyn Trait>(); + <dyn Trait>::plain(); + <dyn Trait>::generic::<usize>() +} diff --git a/tests/ui/rfcs/rfc-2091-track-caller/call-chain.rs b/tests/ui/rfcs/rfc-2091-track-caller/call-chain.rs new file mode 100644 index 000000000..a8814ce28 --- /dev/null +++ b/tests/ui/rfcs/rfc-2091-track-caller/call-chain.rs @@ -0,0 +1,30 @@ +// run-pass +// revisions: default mir-opt +//[default] compile-flags: -Zinline-mir=false +//[mir-opt] compile-flags: -Zmir-opt-level=4 + +use std::panic::Location; + +struct Foo; + +impl Foo { + #[inline(always)] + #[track_caller] + fn check_loc(&self, line: u32, col: u32) -> &Self { + let loc = Location::caller(); + assert_eq!(loc.file(), file!(), "file mismatch"); + assert_eq!(loc.line(), line, "line mismatch"); + assert_eq!(loc.column(), col, "column mismatch"); + self + } +} + +fn main() { + // Tests that when `Location::caller` is used in a method chain, + // it points to the start of the correct call (the first character after the dot) + // instead of to the very first expression in the chain + let foo = Foo; + foo. + check_loc(line!(), 9).check_loc(line!(), 31) + .check_loc(line!(), 10); +} diff --git a/tests/ui/rfcs/rfc-2091-track-caller/caller-location-fnptr-rt-ctfe-equiv.rs b/tests/ui/rfcs/rfc-2091-track-caller/caller-location-fnptr-rt-ctfe-equiv.rs new file mode 100644 index 000000000..a3bed707e --- /dev/null +++ b/tests/ui/rfcs/rfc-2091-track-caller/caller-location-fnptr-rt-ctfe-equiv.rs @@ -0,0 +1,32 @@ +// Ensure that a `#[track_caller]` function, returning `caller_location()`, +// which coerced (to a function pointer) and called, inside a `const fn`, +// in turn called, results in the same output irrespective of whether +// we're in a const or runtime context. + +// run-pass +// compile-flags: -Z unleash-the-miri-inside-of-you + +#![feature(core_intrinsics, const_caller_location)] + +type L = &'static std::panic::Location<'static>; + +#[track_caller] +const fn attributed() -> L { + std::intrinsics::caller_location() +} + +const fn calling_attributed() -> L { + // We need `-Z unleash-the-miri-inside-of-you` for this as we don't have `const fn` pointers. + let ptr: fn() -> L = attributed; + ptr() +} + +fn main() { + const CONSTANT: L = calling_attributed(); + let runtime = calling_attributed(); + + assert_eq!( + (runtime.file(), runtime.line(), runtime.column()), + (CONSTANT.file(), CONSTANT.line(), CONSTANT.column()), + ); +} diff --git a/tests/ui/rfcs/rfc-2091-track-caller/caller-location-fnptr-rt-ctfe-equiv.stderr b/tests/ui/rfcs/rfc-2091-track-caller/caller-location-fnptr-rt-ctfe-equiv.stderr new file mode 100644 index 000000000..cf8ca5771 --- /dev/null +++ b/tests/ui/rfcs/rfc-2091-track-caller/caller-location-fnptr-rt-ctfe-equiv.stderr @@ -0,0 +1,10 @@ +warning: skipping const checks + | +help: skipping check that does not even have a feature gate + --> $DIR/caller-location-fnptr-rt-ctfe-equiv.rs:21:5 + | +LL | ptr() + | ^^^^^ + +warning: 1 warning emitted + diff --git a/tests/ui/rfcs/rfc-2091-track-caller/caller-location-intrinsic.rs b/tests/ui/rfcs/rfc-2091-track-caller/caller-location-intrinsic.rs new file mode 100644 index 000000000..e5754d355 --- /dev/null +++ b/tests/ui/rfcs/rfc-2091-track-caller/caller-location-intrinsic.rs @@ -0,0 +1,27 @@ +// run-pass +// revisions: default mir-opt +//[mir-opt] compile-flags: -Zmir-opt-level=4 + +#[inline(never)] +#[track_caller] +fn codegen_caller_loc() -> &'static core::panic::Location<'static> { + core::panic::Location::caller() +} + +macro_rules! caller_location_from_macro { + () => (codegen_caller_loc()); +} + +fn main() { + let loc = codegen_caller_loc(); + assert_eq!(loc.file(), file!()); + assert_eq!(loc.line(), 16); + assert_eq!(loc.column(), 15); + + // `Location::caller()` in a macro should behave similarly to `file!` and `line!`, + // i.e. point to where the macro was invoked, instead of the macro itself. + let loc2 = caller_location_from_macro!(); + assert_eq!(loc2.file(), file!()); + assert_eq!(loc2.line(), 23); + assert_eq!(loc2.column(), 16); +} diff --git a/tests/ui/rfcs/rfc-2091-track-caller/const-caller-location.rs b/tests/ui/rfcs/rfc-2091-track-caller/const-caller-location.rs new file mode 100644 index 000000000..6e15cf3fe --- /dev/null +++ b/tests/ui/rfcs/rfc-2091-track-caller/const-caller-location.rs @@ -0,0 +1,43 @@ +// run-pass +// revisions: default mir-opt +//[mir-opt] compile-flags: -Zmir-opt-level=4 + +#![feature(const_caller_location)] + +use std::panic::Location; + +const LOCATION: &Location = Location::caller(); + +const TRACKED: &Location = tracked(); +#[track_caller] +const fn tracked() -> &'static Location <'static> { + Location::caller() +} + +const NESTED: &Location = nested_location(); +const fn nested_location() -> &'static Location<'static> { + Location::caller() +} + +const CONTAINED: &Location = contained(); +const fn contained() -> &'static Location<'static> { + tracked() +} + +fn main() { + assert_eq!(LOCATION.file(), file!()); + assert_eq!(LOCATION.line(), 9); + assert_eq!(LOCATION.column(), 29); + + assert_eq!(TRACKED.file(), file!()); + assert_eq!(TRACKED.line(), 11); + assert_eq!(TRACKED.column(), 28); + + assert_eq!(NESTED.file(), file!()); + assert_eq!(NESTED.line(), 19); + assert_eq!(NESTED.column(), 5); + + assert_eq!(CONTAINED.file(), file!()); + assert_eq!(CONTAINED.line(), 24); + assert_eq!(CONTAINED.column(), 5); +} diff --git a/tests/ui/rfcs/rfc-2091-track-caller/diverging-caller-location.rs b/tests/ui/rfcs/rfc-2091-track-caller/diverging-caller-location.rs new file mode 100644 index 000000000..668111955 --- /dev/null +++ b/tests/ui/rfcs/rfc-2091-track-caller/diverging-caller-location.rs @@ -0,0 +1,17 @@ +// run-fail + +//! This test ensures that `#[track_caller]` can be applied directly to diverging functions, as +//! the tracking issue says: https://github.com/rust-lang/rust/issues/47809#issue-292138490. +//! Because the annotated function must diverge and a panic keeps that faster than an infinite loop, +//! we don't inspect the location returned -- it would be difficult to distinguish between the +//! explicit panic and a failed assertion. That it compiles and runs is enough for this one. + +#[track_caller] +fn doesnt_return() -> ! { + let _location = core::panic::Location::caller(); + panic!("huzzah"); +} + +fn main() { + doesnt_return(); +} diff --git a/tests/ui/rfcs/rfc-2091-track-caller/error-odd-syntax.rs b/tests/ui/rfcs/rfc-2091-track-caller/error-odd-syntax.rs new file mode 100644 index 000000000..6f4290e2a --- /dev/null +++ b/tests/ui/rfcs/rfc-2091-track-caller/error-odd-syntax.rs @@ -0,0 +1,5 @@ +#[track_caller(1)] +fn f() {} +//~^^ ERROR malformed `track_caller` attribute input + +fn main() {} diff --git a/tests/ui/rfcs/rfc-2091-track-caller/error-odd-syntax.stderr b/tests/ui/rfcs/rfc-2091-track-caller/error-odd-syntax.stderr new file mode 100644 index 000000000..e7ddf8df4 --- /dev/null +++ b/tests/ui/rfcs/rfc-2091-track-caller/error-odd-syntax.stderr @@ -0,0 +1,8 @@ +error: malformed `track_caller` attribute input + --> $DIR/error-odd-syntax.rs:1:1 + | +LL | #[track_caller(1)] + | ^^^^^^^^^^^^^^^^^^ help: must be of the form: `#[track_caller]` + +error: aborting due to previous error + diff --git a/tests/ui/rfcs/rfc-2091-track-caller/error-with-invalid-abi.rs b/tests/ui/rfcs/rfc-2091-track-caller/error-with-invalid-abi.rs new file mode 100644 index 000000000..074e1ceb7 --- /dev/null +++ b/tests/ui/rfcs/rfc-2091-track-caller/error-with-invalid-abi.rs @@ -0,0 +1,11 @@ +#[track_caller] +extern "C" fn f() {} +//~^^ ERROR `#[track_caller]` requires Rust ABI + +extern "C" { + #[track_caller] + fn g(); + //~^^ ERROR `#[track_caller]` requires Rust ABI +} + +fn main() {} diff --git a/tests/ui/rfcs/rfc-2091-track-caller/error-with-invalid-abi.stderr b/tests/ui/rfcs/rfc-2091-track-caller/error-with-invalid-abi.stderr new file mode 100644 index 000000000..bcc0c8170 --- /dev/null +++ b/tests/ui/rfcs/rfc-2091-track-caller/error-with-invalid-abi.stderr @@ -0,0 +1,15 @@ +error[E0737]: `#[track_caller]` requires Rust ABI + --> $DIR/error-with-invalid-abi.rs:1:1 + | +LL | #[track_caller] + | ^^^^^^^^^^^^^^^ + +error[E0737]: `#[track_caller]` requires Rust ABI + --> $DIR/error-with-invalid-abi.rs:6:5 + | +LL | #[track_caller] + | ^^^^^^^^^^^^^^^ + +error: aborting due to 2 previous errors + +For more information about this error, try `rustc --explain E0737`. diff --git a/tests/ui/rfcs/rfc-2091-track-caller/error-with-main.rs b/tests/ui/rfcs/rfc-2091-track-caller/error-with-main.rs new file mode 100644 index 000000000..b2ea31bb5 --- /dev/null +++ b/tests/ui/rfcs/rfc-2091-track-caller/error-with-main.rs @@ -0,0 +1,4 @@ +#[track_caller] //~ ERROR `main` function is not allowed to be +fn main() { + panic!("{}: oh no", std::panic::Location::caller()); +} diff --git a/tests/ui/rfcs/rfc-2091-track-caller/error-with-main.stderr b/tests/ui/rfcs/rfc-2091-track-caller/error-with-main.stderr new file mode 100644 index 000000000..6d6562dae --- /dev/null +++ b/tests/ui/rfcs/rfc-2091-track-caller/error-with-main.stderr @@ -0,0 +1,10 @@ +error: `main` function is not allowed to be `#[track_caller]` + --> $DIR/error-with-main.rs:1:1 + | +LL | #[track_caller] + | ^^^^^^^^^^^^^^^ help: remove this annotation +LL | fn main() { + | --------- `main` function is not allowed to be `#[track_caller]` + +error: aborting due to previous error + diff --git a/tests/ui/rfcs/rfc-2091-track-caller/error-with-naked.rs b/tests/ui/rfcs/rfc-2091-track-caller/error-with-naked.rs new file mode 100644 index 000000000..43e33cbb1 --- /dev/null +++ b/tests/ui/rfcs/rfc-2091-track-caller/error-with-naked.rs @@ -0,0 +1,24 @@ +// needs-asm-support +#![feature(naked_functions)] + +use std::arch::asm; + +#[track_caller] //~ ERROR cannot use `#[track_caller]` with `#[naked]` +//~^ ERROR `#[track_caller]` requires Rust ABI +#[naked] +extern "C" fn f() { + asm!("", options(noreturn)); +} + +struct S; + +impl S { + #[track_caller] //~ ERROR cannot use `#[track_caller]` with `#[naked]` + //~^ ERROR `#[track_caller]` requires Rust ABI + #[naked] + extern "C" fn g() { + asm!("", options(noreturn)); + } +} + +fn main() {} diff --git a/tests/ui/rfcs/rfc-2091-track-caller/error-with-naked.stderr b/tests/ui/rfcs/rfc-2091-track-caller/error-with-naked.stderr new file mode 100644 index 000000000..3f7d0df42 --- /dev/null +++ b/tests/ui/rfcs/rfc-2091-track-caller/error-with-naked.stderr @@ -0,0 +1,28 @@ +error[E0736]: cannot use `#[track_caller]` with `#[naked]` + --> $DIR/error-with-naked.rs:6:1 + | +LL | #[track_caller] + | ^^^^^^^^^^^^^^^ + +error[E0736]: cannot use `#[track_caller]` with `#[naked]` + --> $DIR/error-with-naked.rs:16:5 + | +LL | #[track_caller] + | ^^^^^^^^^^^^^^^ + +error[E0737]: `#[track_caller]` requires Rust ABI + --> $DIR/error-with-naked.rs:6:1 + | +LL | #[track_caller] + | ^^^^^^^^^^^^^^^ + +error[E0737]: `#[track_caller]` requires Rust ABI + --> $DIR/error-with-naked.rs:16:5 + | +LL | #[track_caller] + | ^^^^^^^^^^^^^^^ + +error: aborting due to 4 previous errors + +Some errors have detailed explanations: E0736, E0737. +For more information about an error, try `rustc --explain E0736`. diff --git a/tests/ui/rfcs/rfc-2091-track-caller/error-with-start.rs b/tests/ui/rfcs/rfc-2091-track-caller/error-with-start.rs new file mode 100644 index 000000000..0cab47170 --- /dev/null +++ b/tests/ui/rfcs/rfc-2091-track-caller/error-with-start.rs @@ -0,0 +1,7 @@ +#![feature(start)] + +#[start] +#[track_caller] //~ ERROR `start` is not allowed to be `#[track_caller]` +fn start(_argc: isize, _argv: *const *const u8) -> isize { + panic!("{}: oh no", std::panic::Location::caller()); +} diff --git a/tests/ui/rfcs/rfc-2091-track-caller/error-with-start.stderr b/tests/ui/rfcs/rfc-2091-track-caller/error-with-start.stderr new file mode 100644 index 000000000..454c98ff9 --- /dev/null +++ b/tests/ui/rfcs/rfc-2091-track-caller/error-with-start.stderr @@ -0,0 +1,10 @@ +error: `start` is not allowed to be `#[track_caller]` + --> $DIR/error-with-start.rs:4:1 + | +LL | #[track_caller] + | ^^^^^^^^^^^^^^^ +LL | fn start(_argc: isize, _argv: *const *const u8) -> isize { + | -------------------------------------------------------- `start` is not allowed to be `#[track_caller]` + +error: aborting due to previous error + diff --git a/tests/ui/rfcs/rfc-2091-track-caller/intrinsic-wrapper.rs b/tests/ui/rfcs/rfc-2091-track-caller/intrinsic-wrapper.rs new file mode 100644 index 000000000..23d2a4b0a --- /dev/null +++ b/tests/ui/rfcs/rfc-2091-track-caller/intrinsic-wrapper.rs @@ -0,0 +1,22 @@ +// run-pass +// revisions: default mir-opt +//[default] compile-flags: -Zinline-mir=no +//[mir-opt] compile-flags: -Zmir-opt-level=4 + +macro_rules! caller_location_from_macro { + () => (core::panic::Location::caller()); +} + +fn main() { + let loc = core::panic::Location::caller(); + assert_eq!(loc.file(), file!()); + assert_eq!(loc.line(), 11); + assert_eq!(loc.column(), 15); + + // `Location::caller()` in a macro should behave similarly to `file!` and `line!`, + // i.e. point to where the macro was invoked, instead of the macro itself. + let loc2 = caller_location_from_macro!(); + assert_eq!(loc2.file(), file!()); + assert_eq!(loc2.line(), 18); + assert_eq!(loc2.column(), 16); +} diff --git a/tests/ui/rfcs/rfc-2091-track-caller/macro-declaration.rs b/tests/ui/rfcs/rfc-2091-track-caller/macro-declaration.rs new file mode 100644 index 000000000..6ca09fac8 --- /dev/null +++ b/tests/ui/rfcs/rfc-2091-track-caller/macro-declaration.rs @@ -0,0 +1,10 @@ +// check-pass + +// See https://github.com/rust-lang/rust/issues/95151 +#[track_caller] +macro_rules! _foo { + () => {}; +} + +fn main() { +} diff --git a/tests/ui/rfcs/rfc-2091-track-caller/mir-inlined-macro.rs b/tests/ui/rfcs/rfc-2091-track-caller/mir-inlined-macro.rs new file mode 100644 index 000000000..a2e8eb27e --- /dev/null +++ b/tests/ui/rfcs/rfc-2091-track-caller/mir-inlined-macro.rs @@ -0,0 +1,23 @@ +// run-pass +// revisions: default mir-opt +//[default] compile-flags: -Zinline-mir=no +//[mir-opt] compile-flags: -Zmir-opt-level=4 + +use std::panic::Location; + +macro_rules! f { + () => { + Location::caller() + }; +} + +#[inline(always)] +fn g() -> &'static Location<'static> { + f!() +} + +fn main() { + let loc = g(); + assert_eq!(loc.line(), 16); + assert_eq!(loc.column(), 5); +} diff --git a/tests/ui/rfcs/rfc-2091-track-caller/only-for-fns.rs b/tests/ui/rfcs/rfc-2091-track-caller/only-for-fns.rs new file mode 100644 index 000000000..2d2b01b6f --- /dev/null +++ b/tests/ui/rfcs/rfc-2091-track-caller/only-for-fns.rs @@ -0,0 +1,5 @@ +#[track_caller] +struct S; +//~^^ ERROR attribute should be applied to a function definition + +fn main() {} diff --git a/tests/ui/rfcs/rfc-2091-track-caller/only-for-fns.stderr b/tests/ui/rfcs/rfc-2091-track-caller/only-for-fns.stderr new file mode 100644 index 000000000..b36597bde --- /dev/null +++ b/tests/ui/rfcs/rfc-2091-track-caller/only-for-fns.stderr @@ -0,0 +1,11 @@ +error[E0739]: attribute should be applied to a function definition + --> $DIR/only-for-fns.rs:1:1 + | +LL | #[track_caller] + | ^^^^^^^^^^^^^^^ +LL | struct S; + | --------- not a function definition + +error: aborting due to previous error + +For more information about this error, try `rustc --explain E0739`. diff --git a/tests/ui/rfcs/rfc-2091-track-caller/pass.rs b/tests/ui/rfcs/rfc-2091-track-caller/pass.rs new file mode 100644 index 000000000..1b13ea3e9 --- /dev/null +++ b/tests/ui/rfcs/rfc-2091-track-caller/pass.rs @@ -0,0 +1,10 @@ +// run-pass +// revisions: default mir-opt +//[mir-opt] compile-flags: -Zmir-opt-level=4 + +#[track_caller] +fn f() {} + +fn main() { + f(); +} diff --git a/tests/ui/rfcs/rfc-2091-track-caller/std-panic-locations.rs b/tests/ui/rfcs/rfc-2091-track-caller/std-panic-locations.rs new file mode 100644 index 000000000..f11456250 --- /dev/null +++ b/tests/ui/rfcs/rfc-2091-track-caller/std-panic-locations.rs @@ -0,0 +1,64 @@ +// run-pass +// needs-unwind +// revisions: default mir-opt +//[mir-opt] compile-flags: -Zmir-opt-level=4 + +#![allow(unconditional_panic)] + +//! Test that panic locations for `#[track_caller]` functions in std have the correct +//! location reported. + +use std::cell::RefCell; +use std::collections::{BTreeMap, HashMap, VecDeque}; +use std::ops::{Index, IndexMut}; +use std::panic::{AssertUnwindSafe, UnwindSafe}; + +fn main() { + // inspect the `PanicInfo` we receive to ensure the right file is the source + std::panic::set_hook(Box::new(|info| { + let actual = info.location().unwrap(); + if actual.file() != file!() { + eprintln!("expected a location in the test file, found {:?}", actual); + panic!(); + } + })); + + fn assert_panicked(f: impl FnOnce() + UnwindSafe) { + std::panic::catch_unwind(f).unwrap_err(); + } + + let nope: Option<()> = None; + assert_panicked(|| nope.unwrap()); + assert_panicked(|| nope.expect("")); + + let oops: Result<(), ()> = Err(()); + assert_panicked(|| oops.unwrap()); + assert_panicked(|| oops.expect("")); + + let fine: Result<(), ()> = Ok(()); + assert_panicked(|| fine.unwrap_err()); + assert_panicked(|| fine.expect_err("")); + + let mut small = [0]; // the implementation backing str, vec, etc + assert_panicked(move || { small.index(1); }); + assert_panicked(move || { small[1]; }); + assert_panicked(move || { small.index_mut(1); }); + assert_panicked(move || { small[1] += 1; }); + + let sorted: BTreeMap<bool, bool> = Default::default(); + assert_panicked(|| { sorted.index(&false); }); + assert_panicked(|| { sorted[&false]; }); + + let unsorted: HashMap<bool, bool> = Default::default(); + assert_panicked(|| { unsorted.index(&false); }); + assert_panicked(|| { unsorted[&false]; }); + + let weirdo: VecDeque<()> = Default::default(); + assert_panicked(|| { weirdo.index(1); }); + assert_panicked(|| { weirdo[1]; }); + + let refcell: RefCell<()> = Default::default(); + let _conflicting = refcell.borrow_mut(); + assert_panicked(AssertUnwindSafe(|| { refcell.borrow(); })); + assert_panicked(AssertUnwindSafe(|| { refcell.borrow_mut(); })); +} diff --git a/tests/ui/rfcs/rfc-2091-track-caller/track-caller-attribute.rs b/tests/ui/rfcs/rfc-2091-track-caller/track-caller-attribute.rs new file mode 100644 index 000000000..9d28eb9de --- /dev/null +++ b/tests/ui/rfcs/rfc-2091-track-caller/track-caller-attribute.rs @@ -0,0 +1,40 @@ +// run-pass +// revisions: default mir-opt +//[mir-opt] compile-flags: -Zmir-opt-level=4 + +use std::panic::Location; + +#[track_caller] +fn tracked() -> &'static Location<'static> { + Location::caller() +} + +fn nested_intrinsic() -> &'static Location<'static> { + Location::caller() +} + +fn nested_tracked() -> &'static Location<'static> { + tracked() +} + +fn main() { + let location = Location::caller(); + assert_eq!(location.file(), file!()); + assert_eq!(location.line(), 21); + assert_eq!(location.column(), 20); + + let tracked = tracked(); + assert_eq!(tracked.file(), file!()); + assert_eq!(tracked.line(), 26); + assert_eq!(tracked.column(), 19); + + let nested = nested_intrinsic(); + assert_eq!(nested.file(), file!()); + assert_eq!(nested.line(), 13); + assert_eq!(nested.column(), 5); + + let contained = nested_tracked(); + assert_eq!(contained.file(), file!()); + assert_eq!(contained.line(), 17); + assert_eq!(contained.column(), 5); +} diff --git a/tests/ui/rfcs/rfc-2091-track-caller/track-caller-ffi.rs b/tests/ui/rfcs/rfc-2091-track-caller/track-caller-ffi.rs new file mode 100644 index 000000000..5115f687c --- /dev/null +++ b/tests/ui/rfcs/rfc-2091-track-caller/track-caller-ffi.rs @@ -0,0 +1,48 @@ +// run-pass + +use std::panic::Location; + +extern "Rust" { + #[track_caller] + fn rust_track_caller_ffi_test_tracked() -> &'static Location<'static>; + fn rust_track_caller_ffi_test_untracked() -> &'static Location<'static>; +} + +fn rust_track_caller_ffi_test_nested_tracked() -> &'static Location<'static> { + unsafe { rust_track_caller_ffi_test_tracked() } +} + +mod provides { + use std::panic::Location; + #[track_caller] // UB if we did not have this! + #[no_mangle] + fn rust_track_caller_ffi_test_tracked() -> &'static Location<'static> { + Location::caller() + } + #[no_mangle] + fn rust_track_caller_ffi_test_untracked() -> &'static Location<'static> { + Location::caller() + } +} + +fn main() { + let location = Location::caller(); + assert_eq!(location.file(), file!()); + assert_eq!(location.line(), 29); + assert_eq!(location.column(), 20); + + let tracked = unsafe { rust_track_caller_ffi_test_tracked() }; + assert_eq!(tracked.file(), file!()); + assert_eq!(tracked.line(), 34); + assert_eq!(tracked.column(), 28); + + let untracked = unsafe { rust_track_caller_ffi_test_untracked() }; + assert_eq!(untracked.file(), file!()); + assert_eq!(untracked.line(), 24); + assert_eq!(untracked.column(), 9); + + let contained = rust_track_caller_ffi_test_nested_tracked(); + assert_eq!(contained.file(), file!()); + assert_eq!(contained.line(), 12); + assert_eq!(contained.column(), 14); +} diff --git a/tests/ui/rfcs/rfc-2091-track-caller/tracked-closure.rs b/tests/ui/rfcs/rfc-2091-track-caller/tracked-closure.rs new file mode 100644 index 000000000..670c423a7 --- /dev/null +++ b/tests/ui/rfcs/rfc-2091-track-caller/tracked-closure.rs @@ -0,0 +1,154 @@ +// run-pass + +#![feature(stmt_expr_attributes)] +#![feature(closure_track_caller)] +#![feature(generator_trait)] +#![feature(generators)] + +use std::ops::{Generator, GeneratorState}; +use std::pin::Pin; +use std::panic::Location; + +type Loc = &'static Location<'static>; + +#[track_caller] +fn mono_invoke_fn<F: Fn(&'static str, bool) -> (&'static str, bool, Loc)>( + val: &F +) -> (&'static str, bool, Loc) { + val("from_mono", false) +} + +#[track_caller] +fn mono_invoke_fn_once<F: FnOnce(&'static str, bool) -> (&'static str, bool, Loc)>( + val: F +) -> (&'static str, bool, Loc) { + val("from_mono", false) +} + +#[track_caller] +fn dyn_invoke_fn_mut( + val: &mut dyn FnMut(&'static str, bool) -> (&'static str, bool, Loc) +) -> (&'static str, bool, Loc) { + val("from_dyn", false) +} + +#[track_caller] +fn dyn_invoke_fn_once( + val: Box<dyn FnOnce(&'static str, bool) -> (&'static str, bool, Loc)> +) -> (&'static str, bool, Loc) { + val("from_dyn", false) +} + + +fn test_closure() { + let mut track_closure = #[track_caller] |first: &'static str, second: bool| { + (first, second, Location::caller()) + }; + let (first_arg, first_bool, first_loc) = track_closure("first_arg", true); + let first_line = line!() - 1; + assert_eq!(first_arg, "first_arg"); + assert_eq!(first_bool, true); + assert_eq!(first_loc.file(), file!()); + assert_eq!(first_loc.line(), first_line); + assert_eq!(first_loc.column(), 46); + + let (dyn_arg, dyn_bool, dyn_loc) = dyn_invoke_fn_mut(&mut track_closure); + assert_eq!(dyn_arg, "from_dyn"); + assert_eq!(dyn_bool, false); + // `FnMut::call_mut` does not have `#[track_caller]`, + // so this will not match + assert_ne!(dyn_loc.file(), file!()); + + let (dyn_arg, dyn_bool, dyn_loc) = dyn_invoke_fn_once(Box::new(track_closure)); + assert_eq!(dyn_arg, "from_dyn"); + assert_eq!(dyn_bool, false); + // `FnOnce::call_once` does not have `#[track_caller]` + // so this will not match + assert_ne!(dyn_loc.file(), file!()); + + + let (mono_arg, mono_bool, mono_loc) = mono_invoke_fn(&track_closure); + let mono_line = line!() - 1; + assert_eq!(mono_arg, "from_mono"); + assert_eq!(mono_bool, false); + assert_eq!(mono_loc.file(), file!()); + assert_eq!(mono_loc.line(), mono_line); + assert_eq!(mono_loc.column(), 43); + + let (mono_arg, mono_bool, mono_loc) = mono_invoke_fn_once(track_closure); + let mono_line = line!() - 1; + assert_eq!(mono_arg, "from_mono"); + assert_eq!(mono_bool, false); + assert_eq!(mono_loc.file(), file!()); + assert_eq!(mono_loc.line(), mono_line); + assert_eq!(mono_loc.column(), 43); + + let non_tracked_caller = || Location::caller(); + let non_tracked_line = line!() - 1; // This is the line of the closure, not its caller + let non_tracked_loc = non_tracked_caller(); + assert_eq!(non_tracked_loc.file(), file!()); + assert_eq!(non_tracked_loc.line(), non_tracked_line); + assert_eq!(non_tracked_loc.column(), 33); +} + + +#[track_caller] +fn mono_generator<F: Generator<String, Yield = (&'static str, String, Loc), Return = ()>>( + val: Pin<&mut F> +) -> (&'static str, String, Loc) { + match val.resume("Mono".to_string()) { + GeneratorState::Yielded(val) => val, + _ => unreachable!() + } +} + +#[track_caller] +fn dyn_generator( + val: Pin<&mut dyn Generator<String, Yield = (&'static str, String, Loc), Return = ()>> +) -> (&'static str, String, Loc) { + match val.resume("Dyn".to_string()) { + GeneratorState::Yielded(val) => val, + _ => unreachable!() + } +} + +fn test_generator() { + let generator = #[track_caller] |arg: String| { + yield ("first", arg.clone(), Location::caller()); + yield ("second", arg.clone(), Location::caller()); + }; + + let mut pinned = Box::pin(generator); + let (dyn_ret, dyn_arg, dyn_loc) = dyn_generator(pinned.as_mut()); + assert_eq!(dyn_ret, "first"); + assert_eq!(dyn_arg, "Dyn".to_string()); + // The `Generator` trait does not have `#[track_caller]` on `resume`, so + // this will not match. + assert_ne!(dyn_loc.file(), file!()); + + + let (mono_ret, mono_arg, mono_loc) = mono_generator(pinned.as_mut()); + let mono_line = line!() - 1; + assert_eq!(mono_ret, "second"); + // The generator ignores the argument to the second `resume` call + assert_eq!(mono_arg, "Dyn".to_string()); + assert_eq!(mono_loc.file(), file!()); + assert_eq!(mono_loc.line(), mono_line); + assert_eq!(mono_loc.column(), 42); + + let non_tracked_generator = || { yield Location::caller(); }; + let non_tracked_line = line!() - 1; // This is the line of the generator, not its caller + let non_tracked_loc = match Box::pin(non_tracked_generator).as_mut().resume(()) { + GeneratorState::Yielded(val) => val, + _ => unreachable!() + }; + assert_eq!(non_tracked_loc.file(), file!()); + assert_eq!(non_tracked_loc.line(), non_tracked_line); + assert_eq!(non_tracked_loc.column(), 44); + +} + +fn main() { + test_closure(); + test_generator(); +} diff --git a/tests/ui/rfcs/rfc-2091-track-caller/tracked-fn-ptr-with-arg.rs b/tests/ui/rfcs/rfc-2091-track-caller/tracked-fn-ptr-with-arg.rs new file mode 100644 index 000000000..658812578 --- /dev/null +++ b/tests/ui/rfcs/rfc-2091-track-caller/tracked-fn-ptr-with-arg.rs @@ -0,0 +1,62 @@ +// run-pass +// revisions: default mir-opt +//[mir-opt] compile-flags: -Zmir-opt-level=4 + +fn pass_to_ptr_call<T>(f: fn(T), x: T) { + f(x); +} + +#[track_caller] +fn tracked_unit(_: ()) { + let expected_line = line!() - 1; + let location = std::panic::Location::caller(); + assert_eq!(location.file(), file!()); + assert_eq!(location.line(), expected_line, "call shims report location as fn definition"); +} + +trait Trait { + fn trait_tracked_unit(_: ()); +} + +impl Trait for () { + #[track_caller] + fn trait_tracked_unit(_: ()) { + let expected_line = line!() - 1; + let location = std::panic::Location::caller(); + assert_eq!(location.file(), file!()); + assert_eq!(location.line(), expected_line, "call shims report location as fn definition"); + } +} + +trait TrackedTrait { + #[track_caller] + fn trait_tracked_unit_default(_: ()) { + let expected_line = line!() - 1; + let location = std::panic::Location::caller(); + assert_eq!(location.file(), file!()); + assert_eq!(location.line(), expected_line, "call shims report location as fn definition"); + } +} + +impl TrackedTrait for () {} + +trait BlanketTrackedTrait { + #[track_caller] + fn tracked_blanket(_: ()); +} + +impl BlanketTrackedTrait for () { + fn tracked_blanket(_: ()) { + let expected_line = line!() - 1; + let location = std::panic::Location::caller(); + assert_eq!(location.file(), file!()); + assert_eq!(location.line(), expected_line, "call shims report location as fn definition"); + } +} + +fn main() { + pass_to_ptr_call(tracked_unit, ()); + pass_to_ptr_call(<() as Trait>::trait_tracked_unit, ()); + pass_to_ptr_call(<() as TrackedTrait>::trait_tracked_unit_default, ()); + pass_to_ptr_call(<() as BlanketTrackedTrait>::tracked_blanket, ()); +} diff --git a/tests/ui/rfcs/rfc-2091-track-caller/tracked-fn-ptr.rs b/tests/ui/rfcs/rfc-2091-track-caller/tracked-fn-ptr.rs new file mode 100644 index 000000000..8bb4dd288 --- /dev/null +++ b/tests/ui/rfcs/rfc-2091-track-caller/tracked-fn-ptr.rs @@ -0,0 +1,62 @@ +// run-pass +// revisions: default mir-opt +//[mir-opt] compile-flags: -Zmir-opt-level=4 + +fn ptr_call(f: fn()) { + f(); +} + +#[track_caller] +fn tracked() { + let expected_line = line!() - 1; + let location = std::panic::Location::caller(); + assert_eq!(location.file(), file!()); + assert_eq!(location.line(), expected_line, "call shims report location as fn definition"); +} + +trait Trait { + fn trait_tracked(); +} + +impl Trait for () { + #[track_caller] + fn trait_tracked() { + let expected_line = line!() - 1; + let location = std::panic::Location::caller(); + assert_eq!(location.file(), file!()); + assert_eq!(location.line(), expected_line, "call shims report location as fn definition"); + } +} + +trait TrackedTrait { + #[track_caller] + fn trait_tracked_default() { + let expected_line = line!() - 1; + let location = std::panic::Location::caller(); + assert_eq!(location.file(), file!()); + assert_eq!(location.line(), expected_line, "call shims report location as fn definition"); + } +} + +impl TrackedTrait for () {} + +trait TraitBlanketTracked { + #[track_caller] + fn tracked_blanket(); +} + +impl TraitBlanketTracked for () { + fn tracked_blanket() { + let expected_line = line!() - 1; + let location = std::panic::Location::caller(); + assert_eq!(location.file(), file!()); + assert_eq!(location.line(), expected_line, "call shims report location as fn definition"); + } +} + +fn main() { + ptr_call(tracked); + ptr_call(<() as Trait>::trait_tracked); + ptr_call(<() as TrackedTrait>::trait_tracked_default); + ptr_call(<() as TraitBlanketTracked>::tracked_blanket); +} diff --git a/tests/ui/rfcs/rfc-2091-track-caller/tracked-trait-impls.rs b/tests/ui/rfcs/rfc-2091-track-caller/tracked-trait-impls.rs new file mode 100644 index 000000000..4db4c29e5 --- /dev/null +++ b/tests/ui/rfcs/rfc-2091-track-caller/tracked-trait-impls.rs @@ -0,0 +1,77 @@ +// run-pass + +macro_rules! assert_expansion_site_is_tracked { + () => {{ + let location = std::panic::Location::caller(); + assert_eq!(location.file(), file!()); + assert_ne!(location.line(), line!(), "line should be outside this fn"); + }} +} + +trait Tracked { + fn local_tracked(&self); + + #[track_caller] + fn blanket_tracked(&self); + + #[track_caller] + fn default_tracked(&self) { + assert_expansion_site_is_tracked!(); + } +} + +impl Tracked for () { + #[track_caller] + fn local_tracked(&self) { + assert_expansion_site_is_tracked!(); + } + + fn blanket_tracked(&self) { + assert_expansion_site_is_tracked!(); + } +} + +impl Tracked for bool { + #[track_caller] + fn local_tracked(&self) { + assert_expansion_site_is_tracked!(); + } + + fn blanket_tracked(&self) { + assert_expansion_site_is_tracked!(); + } + + fn default_tracked(&self) { + assert_expansion_site_is_tracked!(); + } +} + +impl Tracked for u8 { + #[track_caller] + fn local_tracked(&self) { + assert_expansion_site_is_tracked!(); + } + + fn blanket_tracked(&self) { + assert_expansion_site_is_tracked!(); + } + + #[track_caller] + fn default_tracked(&self) { + assert_expansion_site_is_tracked!(); + } +} + +fn main() { + ().local_tracked(); + ().default_tracked(); + ().blanket_tracked(); + + true.local_tracked(); + true.default_tracked(); + true.blanket_tracked(); + + 0u8.local_tracked(); + 0u8.default_tracked(); + 0u8.blanket_tracked(); +} diff --git a/tests/ui/rfcs/rfc-2091-track-caller/tracked-trait-obj.rs b/tests/ui/rfcs/rfc-2091-track-caller/tracked-trait-obj.rs new file mode 100644 index 000000000..06883a857 --- /dev/null +++ b/tests/ui/rfcs/rfc-2091-track-caller/tracked-trait-obj.rs @@ -0,0 +1,61 @@ +// run-pass + +trait Tracked { + #[track_caller] + fn track_caller_trait_method(&self, line: u32, col: u32) { + let location = std::panic::Location::caller(); + assert_eq!(location.file(), file!()); + // The trait method definition is annotated with `#[track_caller]`, + // so caller location information will work through a method + // call on a trait object + assert_eq!(location.line(), line, "Bad line"); + assert_eq!(location.column(), col, "Bad col"); + } + + fn track_caller_not_on_trait_method(&self); + + #[track_caller] + fn track_caller_through_self(self: Box<Self>, line: u32, col: u32); +} + +impl Tracked for () { + // We have `#[track_caller]` on the implementation of the method, + // but not on the definition of the method in the trait. Therefore, + // caller location information will *not* work through a method call + // on a trait object. Instead, we will get the location of this method + #[track_caller] + fn track_caller_not_on_trait_method(&self) { + let location = std::panic::Location::caller(); + assert_eq!(location.file(), file!()); + assert_eq!(location.line(), line!() - 3); + assert_eq!(location.column(), 5); + } + + // We don't have a `#[track_caller]` attribute, but + // `#[track_caller]` is present on the trait definition, + // so we'll still get location information + fn track_caller_through_self(self: Box<Self>, line: u32, col: u32) { + let location = std::panic::Location::caller(); + assert_eq!(location.file(), file!()); + // The trait method definition is annotated with `#[track_caller]`, + // so caller location information will work through a method + // call on a trait object + assert_eq!(location.line(), line, "Bad line"); + assert_eq!(location.column(), col, "Bad col"); + } +} + +fn main() { + let tracked: &dyn Tracked = &(); + // The column is the start of 'track_caller_trait_method' + tracked.track_caller_trait_method(line!(), 13); + + const TRACKED: &dyn Tracked = &(); + // The column is the start of 'track_caller_trait_method' + TRACKED.track_caller_trait_method(line!(), 13); + TRACKED.track_caller_not_on_trait_method(); + + // The column is the start of `track_caller_through_self` + let boxed: Box<dyn Tracked> = Box::new(()); + boxed.track_caller_through_self(line!(), 11); +} diff --git a/tests/ui/rfcs/rfc-2093-infer-outlives/cross-crate.rs b/tests/ui/rfcs/rfc-2093-infer-outlives/cross-crate.rs new file mode 100644 index 000000000..a9bfeabf1 --- /dev/null +++ b/tests/ui/rfcs/rfc-2093-infer-outlives/cross-crate.rs @@ -0,0 +1,8 @@ +#![feature(rustc_attrs)] + +#[rustc_outlives] +struct Foo<'a, T> { //~ ERROR rustc_outlives + bar: std::slice::IterMut<'a, T> +} + +fn main() {} diff --git a/tests/ui/rfcs/rfc-2093-infer-outlives/cross-crate.stderr b/tests/ui/rfcs/rfc-2093-infer-outlives/cross-crate.stderr new file mode 100644 index 000000000..76300cce5 --- /dev/null +++ b/tests/ui/rfcs/rfc-2093-infer-outlives/cross-crate.stderr @@ -0,0 +1,10 @@ +error: rustc_outlives + --> $DIR/cross-crate.rs:4:1 + | +LL | struct Foo<'a, T> { + | ^^^^^^^^^^^^^^^^^ + | + = note: T: 'a + +error: aborting due to previous error + diff --git a/tests/ui/rfcs/rfc-2093-infer-outlives/dont-infer-static.rs b/tests/ui/rfcs/rfc-2093-infer-outlives/dont-infer-static.rs new file mode 100644 index 000000000..d3940b13b --- /dev/null +++ b/tests/ui/rfcs/rfc-2093-infer-outlives/dont-infer-static.rs @@ -0,0 +1,12 @@ +/* + * We don't infer `T: 'static` outlives relationships. + */ + +struct Foo<U> { + bar: Bar<U> //~ ERROR the parameter type `U` may not live long enough [E0310] +} +struct Bar<T: 'static> { + x: T, +} + +fn main() {} diff --git a/tests/ui/rfcs/rfc-2093-infer-outlives/dont-infer-static.stderr b/tests/ui/rfcs/rfc-2093-infer-outlives/dont-infer-static.stderr new file mode 100644 index 000000000..0c388f5fe --- /dev/null +++ b/tests/ui/rfcs/rfc-2093-infer-outlives/dont-infer-static.stderr @@ -0,0 +1,19 @@ +error[E0310]: the parameter type `U` may not live long enough + --> $DIR/dont-infer-static.rs:6:10 + | +LL | bar: Bar<U> + | ^^^^^^ ...so that the type `U` will meet its required lifetime bounds... + | +note: ...that is required by this bound + --> $DIR/dont-infer-static.rs:8:15 + | +LL | struct Bar<T: 'static> { + | ^^^^^^^ +help: consider adding an explicit lifetime bound... + | +LL | struct Foo<U: 'static> { + | +++++++++ + +error: aborting due to previous error + +For more information about this error, try `rustc --explain E0310`. diff --git a/tests/ui/rfcs/rfc-2093-infer-outlives/enum.rs b/tests/ui/rfcs/rfc-2093-infer-outlives/enum.rs new file mode 100644 index 000000000..71d2d3222 --- /dev/null +++ b/tests/ui/rfcs/rfc-2093-infer-outlives/enum.rs @@ -0,0 +1,27 @@ +#![feature(rustc_attrs)] + +// Needs an explicit where clause stating outlives condition. (RFC 2093) + +// Type T needs to outlive lifetime 'a. +#[rustc_outlives] +enum Foo<'a, T> { //~ ERROR rustc_outlives + One(Bar<'a, T>) +} + +// Type U needs to outlive lifetime 'b +#[rustc_outlives] +struct Bar<'b, U> { //~ ERROR rustc_outlives + field2: &'b U +} + +// Type K needs to outlive lifetime 'c. +#[rustc_outlives] +enum Ying<'c, K> { //~ ERROR rustc_outlives + One(&'c Yang<K>) +} + +struct Yang<V> { + field2: V +} + +fn main() {} diff --git a/tests/ui/rfcs/rfc-2093-infer-outlives/enum.stderr b/tests/ui/rfcs/rfc-2093-infer-outlives/enum.stderr new file mode 100644 index 000000000..b6ce2450e --- /dev/null +++ b/tests/ui/rfcs/rfc-2093-infer-outlives/enum.stderr @@ -0,0 +1,26 @@ +error: rustc_outlives + --> $DIR/enum.rs:7:1 + | +LL | enum Foo<'a, T> { + | ^^^^^^^^^^^^^^^ + | + = note: T: 'a + +error: rustc_outlives + --> $DIR/enum.rs:13:1 + | +LL | struct Bar<'b, U> { + | ^^^^^^^^^^^^^^^^^ + | + = note: U: 'b + +error: rustc_outlives + --> $DIR/enum.rs:19:1 + | +LL | enum Ying<'c, K> { + | ^^^^^^^^^^^^^^^^ + | + = note: K: 'c + +error: aborting due to 3 previous errors + diff --git a/tests/ui/rfcs/rfc-2093-infer-outlives/explicit-dyn.rs b/tests/ui/rfcs/rfc-2093-infer-outlives/explicit-dyn.rs new file mode 100644 index 000000000..419fb0a0e --- /dev/null +++ b/tests/ui/rfcs/rfc-2093-infer-outlives/explicit-dyn.rs @@ -0,0 +1,12 @@ +#![feature(rustc_attrs)] + +trait Trait<'x, T> where T: 'x { +} + +#[rustc_outlives] +struct Foo<'a, A> //~ ERROR rustc_outlives +{ + foo: Box<dyn Trait<'a, A>> +} + +fn main() {} diff --git a/tests/ui/rfcs/rfc-2093-infer-outlives/explicit-dyn.stderr b/tests/ui/rfcs/rfc-2093-infer-outlives/explicit-dyn.stderr new file mode 100644 index 000000000..595a5c280 --- /dev/null +++ b/tests/ui/rfcs/rfc-2093-infer-outlives/explicit-dyn.stderr @@ -0,0 +1,10 @@ +error: rustc_outlives + --> $DIR/explicit-dyn.rs:7:1 + | +LL | struct Foo<'a, A> + | ^^^^^^^^^^^^^^^^^ + | + = note: A: 'a + +error: aborting due to previous error + diff --git a/tests/ui/rfcs/rfc-2093-infer-outlives/explicit-enum.rs b/tests/ui/rfcs/rfc-2093-infer-outlives/explicit-enum.rs new file mode 100644 index 000000000..c330c27fe --- /dev/null +++ b/tests/ui/rfcs/rfc-2093-infer-outlives/explicit-enum.rs @@ -0,0 +1,13 @@ +#![feature(rustc_attrs)] + +#[rustc_outlives] +enum Foo<'a, U> { //~ ERROR rustc_outlives + One(Bar<'a, U>) +} + +struct Bar<'x, T> where T: 'x { + x: &'x (), + y: T, +} + +fn main() {} diff --git a/tests/ui/rfcs/rfc-2093-infer-outlives/explicit-enum.stderr b/tests/ui/rfcs/rfc-2093-infer-outlives/explicit-enum.stderr new file mode 100644 index 000000000..3059f95ae --- /dev/null +++ b/tests/ui/rfcs/rfc-2093-infer-outlives/explicit-enum.stderr @@ -0,0 +1,10 @@ +error: rustc_outlives + --> $DIR/explicit-enum.rs:4:1 + | +LL | enum Foo<'a, U> { + | ^^^^^^^^^^^^^^^ + | + = note: U: 'a + +error: aborting due to previous error + diff --git a/tests/ui/rfcs/rfc-2093-infer-outlives/explicit-projection.rs b/tests/ui/rfcs/rfc-2093-infer-outlives/explicit-projection.rs new file mode 100644 index 000000000..00b895288 --- /dev/null +++ b/tests/ui/rfcs/rfc-2093-infer-outlives/explicit-projection.rs @@ -0,0 +1,13 @@ +#![feature(rustc_attrs)] + +trait Trait<'x, T> where T: 'x { + type Type; +} + +#[rustc_outlives] +struct Foo<'a, A, B> where A: Trait<'a, B> //~ ERROR rustc_outlives +{ + foo: <A as Trait<'a, B>>::Type +} + +fn main() {} diff --git a/tests/ui/rfcs/rfc-2093-infer-outlives/explicit-projection.stderr b/tests/ui/rfcs/rfc-2093-infer-outlives/explicit-projection.stderr new file mode 100644 index 000000000..589e95899 --- /dev/null +++ b/tests/ui/rfcs/rfc-2093-infer-outlives/explicit-projection.stderr @@ -0,0 +1,10 @@ +error: rustc_outlives + --> $DIR/explicit-projection.rs:8:1 + | +LL | struct Foo<'a, A, B> where A: Trait<'a, B> + | ^^^^^^^^^^^^^^^^^^^^ + | + = note: B: 'a + +error: aborting due to previous error + diff --git a/tests/ui/rfcs/rfc-2093-infer-outlives/explicit-struct.rs b/tests/ui/rfcs/rfc-2093-infer-outlives/explicit-struct.rs new file mode 100644 index 000000000..3d5e610b9 --- /dev/null +++ b/tests/ui/rfcs/rfc-2093-infer-outlives/explicit-struct.rs @@ -0,0 +1,13 @@ +#![feature(rustc_attrs)] + +#[rustc_outlives] +struct Foo<'b, U> { //~ ERROR rustc_outlives + bar: Bar<'b, U> +} + +struct Bar<'a, T> where T: 'a { + x: &'a (), + y: T, +} + +fn main() {} diff --git a/tests/ui/rfcs/rfc-2093-infer-outlives/explicit-struct.stderr b/tests/ui/rfcs/rfc-2093-infer-outlives/explicit-struct.stderr new file mode 100644 index 000000000..9912e36b2 --- /dev/null +++ b/tests/ui/rfcs/rfc-2093-infer-outlives/explicit-struct.stderr @@ -0,0 +1,10 @@ +error: rustc_outlives + --> $DIR/explicit-struct.rs:4:1 + | +LL | struct Foo<'b, U> { + | ^^^^^^^^^^^^^^^^^ + | + = note: U: 'b + +error: aborting due to previous error + diff --git a/tests/ui/rfcs/rfc-2093-infer-outlives/explicit-union.rs b/tests/ui/rfcs/rfc-2093-infer-outlives/explicit-union.rs new file mode 100644 index 000000000..871208b5b --- /dev/null +++ b/tests/ui/rfcs/rfc-2093-infer-outlives/explicit-union.rs @@ -0,0 +1,14 @@ +#![feature(rustc_attrs)] + +#[rustc_outlives] +union Foo<'b, U: Copy> { //~ ERROR rustc_outlives + bar: Bar<'b, U> +} + +#[derive(Clone, Copy)] +union Bar<'a, T: Copy> where T: 'a { + x: &'a (), + y: T, +} + +fn main() {} diff --git a/tests/ui/rfcs/rfc-2093-infer-outlives/explicit-union.stderr b/tests/ui/rfcs/rfc-2093-infer-outlives/explicit-union.stderr new file mode 100644 index 000000000..16b64bdc2 --- /dev/null +++ b/tests/ui/rfcs/rfc-2093-infer-outlives/explicit-union.stderr @@ -0,0 +1,10 @@ +error: rustc_outlives + --> $DIR/explicit-union.rs:4:1 + | +LL | union Foo<'b, U: Copy> { + | ^^^^^^^^^^^^^^^^^^^^^^ + | + = note: U: 'b + +error: aborting due to previous error + diff --git a/tests/ui/rfcs/rfc-2093-infer-outlives/issue-54467.rs b/tests/ui/rfcs/rfc-2093-infer-outlives/issue-54467.rs new file mode 100644 index 000000000..c712f15e3 --- /dev/null +++ b/tests/ui/rfcs/rfc-2093-infer-outlives/issue-54467.rs @@ -0,0 +1,17 @@ +// Regression test for #54467: +// +// Here, the trait object has an "inferred outlives" requirement that +// `<Self as MyIterator<'a>>::Item: 'a`; but since we don't know what +// `Self` is, we were (incorrectly) messing things up, leading to +// strange errors. This test ensures that we do not give compilation +// errors. +// +// check-pass + +trait MyIterator<'a>: Iterator where Self::Item: 'a { } + +struct MyStruct<'a, A> { + item: Box<dyn MyIterator<'a, Item = A>> +} + +fn main() { } diff --git a/tests/ui/rfcs/rfc-2093-infer-outlives/nested-enum.rs b/tests/ui/rfcs/rfc-2093-infer-outlives/nested-enum.rs new file mode 100644 index 000000000..0cd706e7a --- /dev/null +++ b/tests/ui/rfcs/rfc-2093-infer-outlives/nested-enum.rs @@ -0,0 +1,13 @@ +#![feature(rustc_attrs)] + +#[rustc_outlives] +enum Foo<'a, T> { //~ ERROR rustc_outlives + + One(Bar<'a, T>) +} + +struct Bar<'b, U> { + field2: &'b U +} + +fn main() {} diff --git a/tests/ui/rfcs/rfc-2093-infer-outlives/nested-enum.stderr b/tests/ui/rfcs/rfc-2093-infer-outlives/nested-enum.stderr new file mode 100644 index 000000000..4350e6e8b --- /dev/null +++ b/tests/ui/rfcs/rfc-2093-infer-outlives/nested-enum.stderr @@ -0,0 +1,10 @@ +error: rustc_outlives + --> $DIR/nested-enum.rs:4:1 + | +LL | enum Foo<'a, T> { + | ^^^^^^^^^^^^^^^ + | + = note: T: 'a + +error: aborting due to previous error + diff --git a/tests/ui/rfcs/rfc-2093-infer-outlives/nested-regions.rs b/tests/ui/rfcs/rfc-2093-infer-outlives/nested-regions.rs new file mode 100644 index 000000000..a01c50681 --- /dev/null +++ b/tests/ui/rfcs/rfc-2093-infer-outlives/nested-regions.rs @@ -0,0 +1,8 @@ +#![feature(rustc_attrs)] + +#[rustc_outlives] +struct Foo<'a, 'b, T> { //~ ERROR rustc_outlives + x: &'a &'b T +} + +fn main() {} diff --git a/tests/ui/rfcs/rfc-2093-infer-outlives/nested-regions.stderr b/tests/ui/rfcs/rfc-2093-infer-outlives/nested-regions.stderr new file mode 100644 index 000000000..c08add7ed --- /dev/null +++ b/tests/ui/rfcs/rfc-2093-infer-outlives/nested-regions.stderr @@ -0,0 +1,12 @@ +error: rustc_outlives + --> $DIR/nested-regions.rs:4:1 + | +LL | struct Foo<'a, 'b, T> { + | ^^^^^^^^^^^^^^^^^^^^^ + | + = note: 'b: 'a + = note: T: 'a + = note: T: 'b + +error: aborting due to previous error + diff --git a/tests/ui/rfcs/rfc-2093-infer-outlives/nested-structs.rs b/tests/ui/rfcs/rfc-2093-infer-outlives/nested-structs.rs new file mode 100644 index 000000000..ac6817d22 --- /dev/null +++ b/tests/ui/rfcs/rfc-2093-infer-outlives/nested-structs.rs @@ -0,0 +1,12 @@ +#![feature(rustc_attrs)] + +#[rustc_outlives] +struct Foo<'a, T> { //~ ERROR rustc_outlives + field1: Bar<'a, T> +} + +struct Bar<'b, U> { + field2: &'b U +} + +fn main() {} diff --git a/tests/ui/rfcs/rfc-2093-infer-outlives/nested-structs.stderr b/tests/ui/rfcs/rfc-2093-infer-outlives/nested-structs.stderr new file mode 100644 index 000000000..769555234 --- /dev/null +++ b/tests/ui/rfcs/rfc-2093-infer-outlives/nested-structs.stderr @@ -0,0 +1,10 @@ +error: rustc_outlives + --> $DIR/nested-structs.rs:4:1 + | +LL | struct Foo<'a, T> { + | ^^^^^^^^^^^^^^^^^ + | + = note: T: 'a + +error: aborting due to previous error + diff --git a/tests/ui/rfcs/rfc-2093-infer-outlives/nested-union.rs b/tests/ui/rfcs/rfc-2093-infer-outlives/nested-union.rs new file mode 100644 index 000000000..27ebd0b54 --- /dev/null +++ b/tests/ui/rfcs/rfc-2093-infer-outlives/nested-union.rs @@ -0,0 +1,14 @@ +#![feature(rustc_attrs)] + +#[rustc_outlives] +union Foo<'a, T: Copy> { //~ ERROR rustc_outlives + field1: Bar<'a, T> +} + +// Type U needs to outlive lifetime 'b +#[derive(Clone, Copy)] +union Bar<'b, U: Copy> { + field2: &'b U +} + +fn main() {} diff --git a/tests/ui/rfcs/rfc-2093-infer-outlives/nested-union.stderr b/tests/ui/rfcs/rfc-2093-infer-outlives/nested-union.stderr new file mode 100644 index 000000000..a785c63ce --- /dev/null +++ b/tests/ui/rfcs/rfc-2093-infer-outlives/nested-union.stderr @@ -0,0 +1,10 @@ +error: rustc_outlives + --> $DIR/nested-union.rs:4:1 + | +LL | union Foo<'a, T: Copy> { + | ^^^^^^^^^^^^^^^^^^^^^^ + | + = note: T: 'a + +error: aborting due to previous error + diff --git a/tests/ui/rfcs/rfc-2093-infer-outlives/privacy.rs b/tests/ui/rfcs/rfc-2093-infer-outlives/privacy.rs new file mode 100644 index 000000000..180f5ac6c --- /dev/null +++ b/tests/ui/rfcs/rfc-2093-infer-outlives/privacy.rs @@ -0,0 +1,20 @@ +// Test that we do not get a privacy error here. Initially, we did, +// because we inferred an outlives predciate of `<Foo<'a> as +// Private>::Out: 'a`, but the private trait is -- well -- private, +// and hence it was not something that a pub trait could refer to. +// +// run-pass + +#![allow(dead_code)] + +pub struct Foo<'a> { + field: Option<&'a <Foo<'a> as Private>::Out> +} + +trait Private { + type Out: ?Sized; +} + +impl<T: ?Sized> Private for T { type Out = Self; } + +fn main() { } diff --git a/tests/ui/rfcs/rfc-2093-infer-outlives/projection.rs b/tests/ui/rfcs/rfc-2093-infer-outlives/projection.rs new file mode 100644 index 000000000..411c86da1 --- /dev/null +++ b/tests/ui/rfcs/rfc-2093-infer-outlives/projection.rs @@ -0,0 +1,8 @@ +#![feature(rustc_attrs)] + +#[rustc_outlives] +struct Foo<'a, T: Iterator> { //~ ERROR rustc_outlives + bar: &'a T::Item +} + +fn main() {} diff --git a/tests/ui/rfcs/rfc-2093-infer-outlives/projection.stderr b/tests/ui/rfcs/rfc-2093-infer-outlives/projection.stderr new file mode 100644 index 000000000..d9342013f --- /dev/null +++ b/tests/ui/rfcs/rfc-2093-infer-outlives/projection.stderr @@ -0,0 +1,10 @@ +error: rustc_outlives + --> $DIR/projection.rs:4:1 + | +LL | struct Foo<'a, T: Iterator> { + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^ + | + = note: <T as Iterator>::Item: 'a + +error: aborting due to previous error + diff --git a/tests/ui/rfcs/rfc-2093-infer-outlives/reference.rs b/tests/ui/rfcs/rfc-2093-infer-outlives/reference.rs new file mode 100644 index 000000000..a48a3315a --- /dev/null +++ b/tests/ui/rfcs/rfc-2093-infer-outlives/reference.rs @@ -0,0 +1,8 @@ +#![feature(rustc_attrs)] + +#[rustc_outlives] +struct Foo<'a, T> { //~ ERROR rustc_outlives + bar: &'a T, +} + +fn main() {} diff --git a/tests/ui/rfcs/rfc-2093-infer-outlives/reference.stderr b/tests/ui/rfcs/rfc-2093-infer-outlives/reference.stderr new file mode 100644 index 000000000..508114357 --- /dev/null +++ b/tests/ui/rfcs/rfc-2093-infer-outlives/reference.stderr @@ -0,0 +1,10 @@ +error: rustc_outlives + --> $DIR/reference.rs:4:1 + | +LL | struct Foo<'a, T> { + | ^^^^^^^^^^^^^^^^^ + | + = note: T: 'a + +error: aborting due to previous error + diff --git a/tests/ui/rfcs/rfc-2093-infer-outlives/regions-enum-not-wf.rs b/tests/ui/rfcs/rfc-2093-infer-outlives/regions-enum-not-wf.rs new file mode 100644 index 000000000..8b491ee4e --- /dev/null +++ b/tests/ui/rfcs/rfc-2093-infer-outlives/regions-enum-not-wf.rs @@ -0,0 +1,39 @@ +// Various examples of structs whose fields are not well-formed. + +#![allow(dead_code)] + +trait Dummy<'a> { + type Out; +} +impl<'a, T> Dummy<'a> for T +where + T: 'a, +{ + type Out = (); +} +type RequireOutlives<'a, T> = <T as Dummy<'a>>::Out; + +enum Ref1<'a, T> { + Ref1Variant1(RequireOutlives<'a, T>), //~ ERROR the parameter type `T` may not live long enough +} + +enum Ref2<'a, T> { + Ref2Variant1, + Ref2Variant2(isize, RequireOutlives<'a, T>), //~ ERROR the parameter type `T` may not live long enough +} + +enum RefOk<'a, T: 'a> { + RefOkVariant1(&'a T), +} + +// This is now well formed. RFC 2093 +enum RefIndirect<'a, T> { + RefIndirectVariant1(isize, RefOk<'a, T>), +} + +enum RefDouble<'a, 'b, T> { + RefDoubleVariant1(&'a RequireOutlives<'b, T>), + //~^ the parameter type `T` may not live long enough [E0309] +} + +fn main() {} diff --git a/tests/ui/rfcs/rfc-2093-infer-outlives/regions-enum-not-wf.stderr b/tests/ui/rfcs/rfc-2093-infer-outlives/regions-enum-not-wf.stderr new file mode 100644 index 000000000..2c660b285 --- /dev/null +++ b/tests/ui/rfcs/rfc-2093-infer-outlives/regions-enum-not-wf.stderr @@ -0,0 +1,36 @@ +error[E0309]: the parameter type `T` may not live long enough + --> $DIR/regions-enum-not-wf.rs:17:18 + | +LL | Ref1Variant1(RequireOutlives<'a, T>), + | ^^^^^^^^^^^^^^^^^^^^^^ ...so that the type `T` will meet its required lifetime bounds + | +help: consider adding an explicit lifetime bound... + | +LL | enum Ref1<'a, T: 'a> { + | ++++ + +error[E0309]: the parameter type `T` may not live long enough + --> $DIR/regions-enum-not-wf.rs:22:25 + | +LL | Ref2Variant2(isize, RequireOutlives<'a, T>), + | ^^^^^^^^^^^^^^^^^^^^^^ ...so that the type `T` will meet its required lifetime bounds + | +help: consider adding an explicit lifetime bound... + | +LL | enum Ref2<'a, T: 'a> { + | ++++ + +error[E0309]: the parameter type `T` may not live long enough + --> $DIR/regions-enum-not-wf.rs:35:23 + | +LL | RefDoubleVariant1(&'a RequireOutlives<'b, T>), + | ^^^^^^^^^^^^^^^^^^^^^^^^^^ ...so that the type `T` will meet its required lifetime bounds + | +help: consider adding an explicit lifetime bound... + | +LL | enum RefDouble<'a, 'b, T: 'b> { + | ++++ + +error: aborting due to 3 previous errors + +For more information about this error, try `rustc --explain E0309`. diff --git a/tests/ui/rfcs/rfc-2093-infer-outlives/regions-outlives-nominal-type-region-rev.rs b/tests/ui/rfcs/rfc-2093-infer-outlives/regions-outlives-nominal-type-region-rev.rs new file mode 100644 index 000000000..36b024d2e --- /dev/null +++ b/tests/ui/rfcs/rfc-2093-infer-outlives/regions-outlives-nominal-type-region-rev.rs @@ -0,0 +1,22 @@ +// Test that a nominal type (like `Foo<'a>`) outlives `'b` if its +// arguments (like `'a`) outlive `'b`. +// +// Rule OutlivesNominalType from RFC 1214. + + +#![allow(dead_code)] + +mod rev_variant_struct_region { + struct Foo<'a> { + x: fn(&'a i32), + } + trait Trait<'a, 'b> { + type Out; + } + impl<'a, 'b> Trait<'a, 'b> for usize { + type Out = &'a Foo<'b>; //~ ERROR reference has a longer lifetime + } +} + + +fn main() { } diff --git a/tests/ui/rfcs/rfc-2093-infer-outlives/regions-outlives-nominal-type-region-rev.stderr b/tests/ui/rfcs/rfc-2093-infer-outlives/regions-outlives-nominal-type-region-rev.stderr new file mode 100644 index 000000000..5dff4c8ff --- /dev/null +++ b/tests/ui/rfcs/rfc-2093-infer-outlives/regions-outlives-nominal-type-region-rev.stderr @@ -0,0 +1,20 @@ +error[E0491]: in type `&'a Foo<'b>`, reference has a longer lifetime than the data it references + --> $DIR/regions-outlives-nominal-type-region-rev.rs:17:20 + | +LL | type Out = &'a Foo<'b>; + | ^^^^^^^^^^^ + | +note: the pointer is valid for the lifetime `'a` as defined here + --> $DIR/regions-outlives-nominal-type-region-rev.rs:16:10 + | +LL | impl<'a, 'b> Trait<'a, 'b> for usize { + | ^^ +note: but the referenced data is only valid for the lifetime `'b` as defined here + --> $DIR/regions-outlives-nominal-type-region-rev.rs:16:14 + | +LL | impl<'a, 'b> Trait<'a, 'b> for usize { + | ^^ + +error: aborting due to previous error + +For more information about this error, try `rustc --explain E0491`. diff --git a/tests/ui/rfcs/rfc-2093-infer-outlives/regions-outlives-nominal-type-region.rs b/tests/ui/rfcs/rfc-2093-infer-outlives/regions-outlives-nominal-type-region.rs new file mode 100644 index 000000000..47a38f7c4 --- /dev/null +++ b/tests/ui/rfcs/rfc-2093-infer-outlives/regions-outlives-nominal-type-region.rs @@ -0,0 +1,22 @@ +// Test that a nominal type (like `Foo<'a>`) outlives `'b` if its +// arguments (like `'a`) outlive `'b`. +// +// Rule OutlivesNominalType from RFC 1214. + + +#![allow(dead_code)] + +mod variant_struct_region { + struct Foo<'a> { + x: &'a i32, + } + trait Trait<'a, 'b> { + type Out; + } + impl<'a, 'b> Trait<'a, 'b> for usize { + type Out = &'a Foo<'b>; //~ ERROR reference has a longer lifetime + } +} + + +fn main() { } diff --git a/tests/ui/rfcs/rfc-2093-infer-outlives/regions-outlives-nominal-type-region.stderr b/tests/ui/rfcs/rfc-2093-infer-outlives/regions-outlives-nominal-type-region.stderr new file mode 100644 index 000000000..975776cdd --- /dev/null +++ b/tests/ui/rfcs/rfc-2093-infer-outlives/regions-outlives-nominal-type-region.stderr @@ -0,0 +1,20 @@ +error[E0491]: in type `&'a Foo<'b>`, reference has a longer lifetime than the data it references + --> $DIR/regions-outlives-nominal-type-region.rs:17:20 + | +LL | type Out = &'a Foo<'b>; + | ^^^^^^^^^^^ + | +note: the pointer is valid for the lifetime `'a` as defined here + --> $DIR/regions-outlives-nominal-type-region.rs:16:10 + | +LL | impl<'a, 'b> Trait<'a, 'b> for usize { + | ^^ +note: but the referenced data is only valid for the lifetime `'b` as defined here + --> $DIR/regions-outlives-nominal-type-region.rs:16:14 + | +LL | impl<'a, 'b> Trait<'a, 'b> for usize { + | ^^ + +error: aborting due to previous error + +For more information about this error, try `rustc --explain E0491`. diff --git a/tests/ui/rfcs/rfc-2093-infer-outlives/regions-outlives-nominal-type-type-rev.rs b/tests/ui/rfcs/rfc-2093-infer-outlives/regions-outlives-nominal-type-type-rev.rs new file mode 100644 index 000000000..083ba8948 --- /dev/null +++ b/tests/ui/rfcs/rfc-2093-infer-outlives/regions-outlives-nominal-type-type-rev.rs @@ -0,0 +1,22 @@ +// Test that a nominal type (like `Foo<'a>`) outlives `'b` if its +// arguments (like `'a`) outlive `'b`. +// +// Rule OutlivesNominalType from RFC 1214. + + +#![allow(dead_code)] + +mod variant_struct_type { + struct Foo<T> { + x: fn(T) + } + trait Trait<'a, 'b> { + type Out; + } + impl<'a, 'b> Trait<'a, 'b> for usize { + type Out = &'a Foo<&'b i32>; //~ ERROR reference has a longer lifetime + } +} + + +fn main() { } diff --git a/tests/ui/rfcs/rfc-2093-infer-outlives/regions-outlives-nominal-type-type-rev.stderr b/tests/ui/rfcs/rfc-2093-infer-outlives/regions-outlives-nominal-type-type-rev.stderr new file mode 100644 index 000000000..be05ecec0 --- /dev/null +++ b/tests/ui/rfcs/rfc-2093-infer-outlives/regions-outlives-nominal-type-type-rev.stderr @@ -0,0 +1,20 @@ +error[E0491]: in type `&'a Foo<&'b i32>`, reference has a longer lifetime than the data it references + --> $DIR/regions-outlives-nominal-type-type-rev.rs:17:20 + | +LL | type Out = &'a Foo<&'b i32>; + | ^^^^^^^^^^^^^^^^ + | +note: the pointer is valid for the lifetime `'a` as defined here + --> $DIR/regions-outlives-nominal-type-type-rev.rs:16:10 + | +LL | impl<'a, 'b> Trait<'a, 'b> for usize { + | ^^ +note: but the referenced data is only valid for the lifetime `'b` as defined here + --> $DIR/regions-outlives-nominal-type-type-rev.rs:16:14 + | +LL | impl<'a, 'b> Trait<'a, 'b> for usize { + | ^^ + +error: aborting due to previous error + +For more information about this error, try `rustc --explain E0491`. diff --git a/tests/ui/rfcs/rfc-2093-infer-outlives/regions-outlives-nominal-type-type.rs b/tests/ui/rfcs/rfc-2093-infer-outlives/regions-outlives-nominal-type-type.rs new file mode 100644 index 000000000..f3e4e39ac --- /dev/null +++ b/tests/ui/rfcs/rfc-2093-infer-outlives/regions-outlives-nominal-type-type.rs @@ -0,0 +1,22 @@ +// Test that a nominal type (like `Foo<'a>`) outlives `'b` if its +// arguments (like `'a`) outlive `'b`. +// +// Rule OutlivesNominalType from RFC 1214. + + +#![allow(dead_code)] + +mod variant_struct_type { + struct Foo<T> { + x: T + } + trait Trait<'a, 'b> { + type Out; + } + impl<'a, 'b> Trait<'a, 'b> for usize { + type Out = &'a Foo<&'b i32>; //~ ERROR reference has a longer lifetime + } +} + + +fn main() { } diff --git a/tests/ui/rfcs/rfc-2093-infer-outlives/regions-outlives-nominal-type-type.stderr b/tests/ui/rfcs/rfc-2093-infer-outlives/regions-outlives-nominal-type-type.stderr new file mode 100644 index 000000000..4ba1778d6 --- /dev/null +++ b/tests/ui/rfcs/rfc-2093-infer-outlives/regions-outlives-nominal-type-type.stderr @@ -0,0 +1,20 @@ +error[E0491]: in type `&'a Foo<&'b i32>`, reference has a longer lifetime than the data it references + --> $DIR/regions-outlives-nominal-type-type.rs:17:20 + | +LL | type Out = &'a Foo<&'b i32>; + | ^^^^^^^^^^^^^^^^ + | +note: the pointer is valid for the lifetime `'a` as defined here + --> $DIR/regions-outlives-nominal-type-type.rs:16:10 + | +LL | impl<'a, 'b> Trait<'a, 'b> for usize { + | ^^ +note: but the referenced data is only valid for the lifetime `'b` as defined here + --> $DIR/regions-outlives-nominal-type-type.rs:16:14 + | +LL | impl<'a, 'b> Trait<'a, 'b> for usize { + | ^^ + +error: aborting due to previous error + +For more information about this error, try `rustc --explain E0491`. diff --git a/tests/ui/rfcs/rfc-2093-infer-outlives/regions-struct-not-wf.rs b/tests/ui/rfcs/rfc-2093-infer-outlives/regions-struct-not-wf.rs new file mode 100644 index 000000000..552c6cf00 --- /dev/null +++ b/tests/ui/rfcs/rfc-2093-infer-outlives/regions-struct-not-wf.rs @@ -0,0 +1,28 @@ +// Various examples of structs whose fields are not well-formed. + +#![allow(dead_code)] + +trait Trait<'a, T> { + type Out; +} +trait Trait1<'a, 'b, T> { + type Out; +} + +impl<'a, T> Trait<'a, T> for usize { + type Out = &'a T; //~ ERROR `T` may not live long enough +} + +struct RefOk<'a, T:'a> { + field: &'a T +} + +impl<'a, T> Trait<'a, T> for u32 { + type Out = RefOk<'a, T>; //~ ERROR `T` may not live long enough +} + +impl<'a, 'b, T> Trait1<'a, 'b, T> for u32 { + type Out = &'a &'b T; //~ ERROR reference has a longer lifetime than the data +} + +fn main() { } diff --git a/tests/ui/rfcs/rfc-2093-infer-outlives/regions-struct-not-wf.stderr b/tests/ui/rfcs/rfc-2093-infer-outlives/regions-struct-not-wf.stderr new file mode 100644 index 000000000..34ff1362c --- /dev/null +++ b/tests/ui/rfcs/rfc-2093-infer-outlives/regions-struct-not-wf.stderr @@ -0,0 +1,48 @@ +error[E0309]: the parameter type `T` may not live long enough + --> $DIR/regions-struct-not-wf.rs:13:16 + | +LL | type Out = &'a T; + | ^^^^^ ...so that the reference type `&'a T` does not outlive the data it points at + | +help: consider adding an explicit lifetime bound... + | +LL | impl<'a, T: 'a> Trait<'a, T> for usize { + | ++++ + +error[E0309]: the parameter type `T` may not live long enough + --> $DIR/regions-struct-not-wf.rs:21:16 + | +LL | type Out = RefOk<'a, T>; + | ^^^^^^^^^^^^ ...so that the type `T` will meet its required lifetime bounds... + | +note: ...that is required by this bound + --> $DIR/regions-struct-not-wf.rs:16:20 + | +LL | struct RefOk<'a, T:'a> { + | ^^ +help: consider adding an explicit lifetime bound... + | +LL | impl<'a, T: 'a> Trait<'a, T> for u32 { + | ++++ + +error[E0491]: in type `&'a &'b T`, reference has a longer lifetime than the data it references + --> $DIR/regions-struct-not-wf.rs:25:16 + | +LL | type Out = &'a &'b T; + | ^^^^^^^^^ + | +note: the pointer is valid for the lifetime `'a` as defined here + --> $DIR/regions-struct-not-wf.rs:24:6 + | +LL | impl<'a, 'b, T> Trait1<'a, 'b, T> for u32 { + | ^^ +note: but the referenced data is only valid for the lifetime `'b` as defined here + --> $DIR/regions-struct-not-wf.rs:24:10 + | +LL | impl<'a, 'b, T> Trait1<'a, 'b, T> for u32 { + | ^^ + +error: aborting due to 3 previous errors + +Some errors have detailed explanations: E0309, E0491. +For more information about an error, try `rustc --explain E0309`. diff --git a/tests/ui/rfcs/rfc-2093-infer-outlives/self-dyn.rs b/tests/ui/rfcs/rfc-2093-infer-outlives/self-dyn.rs new file mode 100644 index 000000000..c53d6c18f --- /dev/null +++ b/tests/ui/rfcs/rfc-2093-infer-outlives/self-dyn.rs @@ -0,0 +1,13 @@ +#![feature(rustc_attrs)] + +trait Trait<'x, 's, T> where T: 'x, + 's: { +} + +#[rustc_outlives] +struct Foo<'a, 'b, A> //~ ERROR rustc_outlives +{ + foo: Box<dyn Trait<'a, 'b, A>> +} + +fn main() {} diff --git a/tests/ui/rfcs/rfc-2093-infer-outlives/self-dyn.stderr b/tests/ui/rfcs/rfc-2093-infer-outlives/self-dyn.stderr new file mode 100644 index 000000000..9c836b190 --- /dev/null +++ b/tests/ui/rfcs/rfc-2093-infer-outlives/self-dyn.stderr @@ -0,0 +1,10 @@ +error: rustc_outlives + --> $DIR/self-dyn.rs:8:1 + | +LL | struct Foo<'a, 'b, A> + | ^^^^^^^^^^^^^^^^^^^^^ + | + = note: A: 'a + +error: aborting due to previous error + diff --git a/tests/ui/rfcs/rfc-2093-infer-outlives/self-structs.rs b/tests/ui/rfcs/rfc-2093-infer-outlives/self-structs.rs new file mode 100644 index 000000000..8f2d29d6f --- /dev/null +++ b/tests/ui/rfcs/rfc-2093-infer-outlives/self-structs.rs @@ -0,0 +1,13 @@ +#![feature(rustc_attrs)] + +#[rustc_outlives] +struct Foo<'a, 'b, T> { //~ ERROR rustc_outlives + field1: dyn Bar<'a, 'b, T> +} + +trait Bar<'x, 's, U> + where U: 'x, + Self:'s +{} + +fn main() {} diff --git a/tests/ui/rfcs/rfc-2093-infer-outlives/self-structs.stderr b/tests/ui/rfcs/rfc-2093-infer-outlives/self-structs.stderr new file mode 100644 index 000000000..2b4625f77 --- /dev/null +++ b/tests/ui/rfcs/rfc-2093-infer-outlives/self-structs.stderr @@ -0,0 +1,10 @@ +error: rustc_outlives + --> $DIR/self-structs.rs:4:1 + | +LL | struct Foo<'a, 'b, T> { + | ^^^^^^^^^^^^^^^^^^^^^ + | + = note: T: 'a + +error: aborting due to previous error + diff --git a/tests/ui/rfcs/rfc-2126-crate-paths/crate-path-non-absolute.rs b/tests/ui/rfcs/rfc-2126-crate-paths/crate-path-non-absolute.rs new file mode 100644 index 000000000..79f6b0dfe --- /dev/null +++ b/tests/ui/rfcs/rfc-2126-crate-paths/crate-path-non-absolute.rs @@ -0,0 +1,11 @@ +struct S; + +pub mod m { + fn f() { + let s = ::m::crate::S; //~ ERROR failed to resolve + let s1 = ::crate::S; //~ ERROR failed to resolve + let s2 = crate::S; // no error + } +} + +fn main() {} diff --git a/tests/ui/rfcs/rfc-2126-crate-paths/crate-path-non-absolute.stderr b/tests/ui/rfcs/rfc-2126-crate-paths/crate-path-non-absolute.stderr new file mode 100644 index 000000000..7e7ee3ce0 --- /dev/null +++ b/tests/ui/rfcs/rfc-2126-crate-paths/crate-path-non-absolute.stderr @@ -0,0 +1,15 @@ +error[E0433]: failed to resolve: `crate` in paths can only be used in start position + --> $DIR/crate-path-non-absolute.rs:5:22 + | +LL | let s = ::m::crate::S; + | ^^^^^ `crate` in paths can only be used in start position + +error[E0433]: failed to resolve: global paths cannot start with `crate` + --> $DIR/crate-path-non-absolute.rs:6:20 + | +LL | let s1 = ::crate::S; + | ^^^^^ global paths cannot start with `crate` + +error: aborting due to 2 previous errors + +For more information about this error, try `rustc --explain E0433`. diff --git a/tests/ui/rfcs/rfc-2126-crate-paths/keyword-crate-as-identifier.rs b/tests/ui/rfcs/rfc-2126-crate-paths/keyword-crate-as-identifier.rs new file mode 100644 index 000000000..019ef8e9d --- /dev/null +++ b/tests/ui/rfcs/rfc-2126-crate-paths/keyword-crate-as-identifier.rs @@ -0,0 +1,4 @@ +fn main() { + let crate = 0; + //~^ ERROR expected unit struct, unit variant or constant, found module `crate` +} diff --git a/tests/ui/rfcs/rfc-2126-crate-paths/keyword-crate-as-identifier.stderr b/tests/ui/rfcs/rfc-2126-crate-paths/keyword-crate-as-identifier.stderr new file mode 100644 index 000000000..c39a70f66 --- /dev/null +++ b/tests/ui/rfcs/rfc-2126-crate-paths/keyword-crate-as-identifier.stderr @@ -0,0 +1,9 @@ +error[E0532]: expected unit struct, unit variant or constant, found module `crate` + --> $DIR/keyword-crate-as-identifier.rs:2:9 + | +LL | let crate = 0; + | ^^^^^ not a unit struct, unit variant or constant + +error: aborting due to previous error + +For more information about this error, try `rustc --explain E0532`. diff --git a/tests/ui/rfcs/rfc-2126-extern-absolute-paths/auxiliary/xcrate.rs b/tests/ui/rfcs/rfc-2126-extern-absolute-paths/auxiliary/xcrate.rs new file mode 100644 index 000000000..c4d444764 --- /dev/null +++ b/tests/ui/rfcs/rfc-2126-extern-absolute-paths/auxiliary/xcrate.rs @@ -0,0 +1,5 @@ +#[derive(Debug)] +pub struct S; + +#[derive(Debug)] +pub struct Z; diff --git a/tests/ui/rfcs/rfc-2126-extern-absolute-paths/non-existent-1.rs b/tests/ui/rfcs/rfc-2126-extern-absolute-paths/non-existent-1.rs new file mode 100644 index 000000000..9c0e0bef4 --- /dev/null +++ b/tests/ui/rfcs/rfc-2126-extern-absolute-paths/non-existent-1.rs @@ -0,0 +1,5 @@ +// edition:2018 + +use xcrate::S; //~ ERROR unresolved import `xcrate` + +fn main() {} diff --git a/tests/ui/rfcs/rfc-2126-extern-absolute-paths/non-existent-1.stderr b/tests/ui/rfcs/rfc-2126-extern-absolute-paths/non-existent-1.stderr new file mode 100644 index 000000000..818915721 --- /dev/null +++ b/tests/ui/rfcs/rfc-2126-extern-absolute-paths/non-existent-1.stderr @@ -0,0 +1,9 @@ +error[E0432]: unresolved import `xcrate` + --> $DIR/non-existent-1.rs:3:5 + | +LL | use xcrate::S; + | ^^^^^^ use of undeclared crate or module `xcrate` + +error: aborting due to previous error + +For more information about this error, try `rustc --explain E0432`. diff --git a/tests/ui/rfcs/rfc-2126-extern-absolute-paths/non-existent-2.rs b/tests/ui/rfcs/rfc-2126-extern-absolute-paths/non-existent-2.rs new file mode 100644 index 000000000..def60feb5 --- /dev/null +++ b/tests/ui/rfcs/rfc-2126-extern-absolute-paths/non-existent-2.rs @@ -0,0 +1,6 @@ +// edition:2018 + +fn main() { + let s = ::xcrate::S; + //~^ ERROR failed to resolve: could not find `xcrate` in the list of imported crates +} diff --git a/tests/ui/rfcs/rfc-2126-extern-absolute-paths/non-existent-2.stderr b/tests/ui/rfcs/rfc-2126-extern-absolute-paths/non-existent-2.stderr new file mode 100644 index 000000000..7df4f06d1 --- /dev/null +++ b/tests/ui/rfcs/rfc-2126-extern-absolute-paths/non-existent-2.stderr @@ -0,0 +1,9 @@ +error[E0433]: failed to resolve: could not find `xcrate` in the list of imported crates + --> $DIR/non-existent-2.rs:4:15 + | +LL | let s = ::xcrate::S; + | ^^^^^^ could not find `xcrate` in the list of imported crates + +error: aborting due to previous error + +For more information about this error, try `rustc --explain E0433`. diff --git a/tests/ui/rfcs/rfc-2126-extern-absolute-paths/non-existent-3.rs b/tests/ui/rfcs/rfc-2126-extern-absolute-paths/non-existent-3.rs new file mode 100644 index 000000000..486159c0e --- /dev/null +++ b/tests/ui/rfcs/rfc-2126-extern-absolute-paths/non-existent-3.rs @@ -0,0 +1,5 @@ +// edition:2018 + +use ycrate; //~ ERROR unresolved import `ycrate` + +fn main() {} diff --git a/tests/ui/rfcs/rfc-2126-extern-absolute-paths/non-existent-3.stderr b/tests/ui/rfcs/rfc-2126-extern-absolute-paths/non-existent-3.stderr new file mode 100644 index 000000000..bd6778cf3 --- /dev/null +++ b/tests/ui/rfcs/rfc-2126-extern-absolute-paths/non-existent-3.stderr @@ -0,0 +1,9 @@ +error[E0432]: unresolved import `ycrate` + --> $DIR/non-existent-3.rs:3:5 + | +LL | use ycrate; + | ^^^^^^ no external crate `ycrate` + +error: aborting due to previous error + +For more information about this error, try `rustc --explain E0432`. diff --git a/tests/ui/rfcs/rfc-2126-extern-absolute-paths/not-allowed.rs b/tests/ui/rfcs/rfc-2126-extern-absolute-paths/not-allowed.rs new file mode 100644 index 000000000..acb4bbebe --- /dev/null +++ b/tests/ui/rfcs/rfc-2126-extern-absolute-paths/not-allowed.rs @@ -0,0 +1,9 @@ +// edition:2018 + +// Tests that arbitrary crates (other than `core`, `std` and `meta`) +// aren't allowed without `--extern`, even if they're in the sysroot. +use alloc; //~ ERROR unresolved import `alloc` +use test; // OK, imports the built-in attribute macro `#[test]`, but not the `test` crate. +use proc_macro; // OK, imports the built-in `proc_macro` attribute, but not the `proc_macro` crate. + +fn main() {} diff --git a/tests/ui/rfcs/rfc-2126-extern-absolute-paths/not-allowed.stderr b/tests/ui/rfcs/rfc-2126-extern-absolute-paths/not-allowed.stderr new file mode 100644 index 000000000..122e8fd35 --- /dev/null +++ b/tests/ui/rfcs/rfc-2126-extern-absolute-paths/not-allowed.stderr @@ -0,0 +1,16 @@ +error[E0432]: unresolved import `alloc` + --> $DIR/not-allowed.rs:5:5 + | +LL | use alloc; + | ^^^^^ no external crate `alloc` + | +help: consider importing one of these items instead + | +LL | use core::alloc; + | ~~~~~~~~~~~ +LL | use std::alloc; + | ~~~~~~~~~~ + +error: aborting due to previous error + +For more information about this error, try `rustc --explain E0432`. diff --git a/tests/ui/rfcs/rfc-2126-extern-absolute-paths/single-segment.rs b/tests/ui/rfcs/rfc-2126-extern-absolute-paths/single-segment.rs new file mode 100644 index 000000000..72e50d78b --- /dev/null +++ b/tests/ui/rfcs/rfc-2126-extern-absolute-paths/single-segment.rs @@ -0,0 +1,11 @@ +// aux-build:xcrate.rs +// compile-flags:--extern xcrate +// edition:2018 + +use crate; //~ ERROR crate root imports need to be explicitly named: `use crate as name;` +use *; //~ ERROR cannot glob-import all possible crates + +fn main() { + let s = ::xcrate; //~ ERROR expected value, found crate `xcrate` + //~^ NOTE not a value +} diff --git a/tests/ui/rfcs/rfc-2126-extern-absolute-paths/single-segment.stderr b/tests/ui/rfcs/rfc-2126-extern-absolute-paths/single-segment.stderr new file mode 100644 index 000000000..253cc1bc5 --- /dev/null +++ b/tests/ui/rfcs/rfc-2126-extern-absolute-paths/single-segment.stderr @@ -0,0 +1,21 @@ +error: crate root imports need to be explicitly named: `use crate as name;` + --> $DIR/single-segment.rs:5:5 + | +LL | use crate; + | ^^^^^ + +error: cannot glob-import all possible crates + --> $DIR/single-segment.rs:6:5 + | +LL | use *; + | ^ + +error[E0423]: expected value, found crate `xcrate` + --> $DIR/single-segment.rs:9:13 + | +LL | let s = ::xcrate; + | ^^^^^^^^ not a value + +error: aborting due to 3 previous errors + +For more information about this error, try `rustc --explain E0423`. diff --git a/tests/ui/rfcs/rfc-2294-if-let-guard/bindings.rs b/tests/ui/rfcs/rfc-2294-if-let-guard/bindings.rs new file mode 100644 index 000000000..1f32e4af1 --- /dev/null +++ b/tests/ui/rfcs/rfc-2294-if-let-guard/bindings.rs @@ -0,0 +1,9 @@ +#![feature(if_let_guard)] + +fn main() { + match Some(None) { + Some(x) if let Some(y) = x => (x, y), + _ => y, //~ ERROR cannot find value `y` + } + y //~ ERROR cannot find value `y` +} diff --git a/tests/ui/rfcs/rfc-2294-if-let-guard/bindings.stderr b/tests/ui/rfcs/rfc-2294-if-let-guard/bindings.stderr new file mode 100644 index 000000000..2463b7f3e --- /dev/null +++ b/tests/ui/rfcs/rfc-2294-if-let-guard/bindings.stderr @@ -0,0 +1,15 @@ +error[E0425]: cannot find value `y` in this scope + --> $DIR/bindings.rs:6:14 + | +LL | _ => y, + | ^ not found in this scope + +error[E0425]: cannot find value `y` in this scope + --> $DIR/bindings.rs:8:5 + | +LL | y + | ^ not found in this scope + +error: aborting due to 2 previous errors + +For more information about this error, try `rustc --explain E0425`. diff --git a/tests/ui/rfcs/rfc-2294-if-let-guard/feature-gate.rs b/tests/ui/rfcs/rfc-2294-if-let-guard/feature-gate.rs new file mode 100644 index 000000000..3beb20f0a --- /dev/null +++ b/tests/ui/rfcs/rfc-2294-if-let-guard/feature-gate.rs @@ -0,0 +1,96 @@ +// gate-test-if_let_guard + +use std::ops::Range; + +fn _if_let_guard() { + match () { + () if let 0 = 1 => {} + //~^ ERROR `if let` guards are experimental + + () if (let 0 = 1) => {} + //~^ ERROR `let` expressions in this position are unstable + //~| ERROR expected expression, found `let` statement + //~| ERROR `let` expressions are not supported here + + () if (((let 0 = 1))) => {} + //~^ ERROR `let` expressions in this position are unstable + //~| ERROR expected expression, found `let` statement + //~| ERROR `let` expressions are not supported here + + () if true && let 0 = 1 => {} + //~^ ERROR `if let` guards are experimental + //~| ERROR `let` expressions in this position are unstable + + () if let 0 = 1 && true => {} + //~^ ERROR `if let` guards are experimental + //~| ERROR `let` expressions in this position are unstable + + () if (let 0 = 1) && true => {} + //~^ ERROR `let` expressions in this position are unstable + //~| ERROR expected expression, found `let` statement + //~| ERROR `let` expressions are not supported here + + () if true && (let 0 = 1) => {} + //~^ ERROR `let` expressions in this position are unstable + //~| ERROR expected expression, found `let` statement + //~| ERROR `let` expressions are not supported here + + () if (let 0 = 1) && (let 0 = 1) => {} + //~^ ERROR `let` expressions in this position are unstable + //~| ERROR `let` expressions in this position are unstable + //~| ERROR expected expression, found `let` statement + //~| ERROR expected expression, found `let` statement + //~| ERROR `let` expressions are not supported here + //~| ERROR `let` expressions are not supported here + + () if let 0 = 1 && let 1 = 2 && (let 2 = 3 && let 3 = 4 && let 4 = 5) => {} + //~^ ERROR `if let` guards are experimental + //~| ERROR `let` expressions in this position are unstable + //~| ERROR `let` expressions in this position are unstable + //~| ERROR `let` expressions in this position are unstable + //~| ERROR `let` expressions in this position are unstable + //~| ERROR `let` expressions in this position are unstable + //~| ERROR expected expression, found `let` statement + //~| ERROR expected expression, found `let` statement + //~| ERROR expected expression, found `let` statement + //~| ERROR `let` expressions are not supported here + //~| ERROR `let` expressions are not supported here + //~| ERROR `let` expressions are not supported here + + + () if let Range { start: _, end: _ } = (true..true) && false => {} + //~^ ERROR `if let` guards are experimental + //~| ERROR `let` expressions in this position are unstable + + _ => {} + } +} + +fn _macros() { + macro_rules! use_expr { + ($e:expr) => { + match () { + () if $e => {} + _ => {} + } + } + } + use_expr!((let 0 = 1 && 0 == 0)); + //~^ ERROR `let` expressions in this position are unstable + //~| ERROR expected expression, found `let` statement + //~| ERROR `let` expressions are not supported here + use_expr!((let 0 = 1)); + //~^ ERROR `let` expressions in this position are unstable + //~| ERROR expected expression, found `let` statement + //~| ERROR `let` expressions are not supported here + match () { + #[cfg(FALSE)] + () if let 0 = 1 => {} + //~^ ERROR `if let` guards are experimental + _ => {} + } + use_expr!(let 0 = 1); + //~^ ERROR no rules expected the token `let` +} + +fn main() {} diff --git a/tests/ui/rfcs/rfc-2294-if-let-guard/feature-gate.stderr b/tests/ui/rfcs/rfc-2294-if-let-guard/feature-gate.stderr new file mode 100644 index 000000000..dc182ce46 --- /dev/null +++ b/tests/ui/rfcs/rfc-2294-if-let-guard/feature-gate.stderr @@ -0,0 +1,431 @@ +error: expected expression, found `let` statement + --> $DIR/feature-gate.rs:10:16 + | +LL | () if (let 0 = 1) => {} + | ^^^ + +error: expected expression, found `let` statement + --> $DIR/feature-gate.rs:15:18 + | +LL | () if (((let 0 = 1))) => {} + | ^^^ + +error: expected expression, found `let` statement + --> $DIR/feature-gate.rs:28:16 + | +LL | () if (let 0 = 1) && true => {} + | ^^^ + +error: expected expression, found `let` statement + --> $DIR/feature-gate.rs:33:24 + | +LL | () if true && (let 0 = 1) => {} + | ^^^ + +error: expected expression, found `let` statement + --> $DIR/feature-gate.rs:38:16 + | +LL | () if (let 0 = 1) && (let 0 = 1) => {} + | ^^^ + +error: expected expression, found `let` statement + --> $DIR/feature-gate.rs:38:31 + | +LL | () if (let 0 = 1) && (let 0 = 1) => {} + | ^^^ + +error: expected expression, found `let` statement + --> $DIR/feature-gate.rs:46:42 + | +LL | () if let 0 = 1 && let 1 = 2 && (let 2 = 3 && let 3 = 4 && let 4 = 5) => {} + | ^^^ + +error: expected expression, found `let` statement + --> $DIR/feature-gate.rs:46:55 + | +LL | () if let 0 = 1 && let 1 = 2 && (let 2 = 3 && let 3 = 4 && let 4 = 5) => {} + | ^^^ + +error: expected expression, found `let` statement + --> $DIR/feature-gate.rs:46:68 + | +LL | () if let 0 = 1 && let 1 = 2 && (let 2 = 3 && let 3 = 4 && let 4 = 5) => {} + | ^^^ + +error: expected expression, found `let` statement + --> $DIR/feature-gate.rs:78:16 + | +LL | use_expr!((let 0 = 1 && 0 == 0)); + | ^^^ + +error: expected expression, found `let` statement + --> $DIR/feature-gate.rs:82:16 + | +LL | use_expr!((let 0 = 1)); + | ^^^ + +error: no rules expected the token `let` + --> $DIR/feature-gate.rs:92:15 + | +LL | macro_rules! use_expr { + | --------------------- when calling this macro +... +LL | use_expr!(let 0 = 1); + | ^^^ no rules expected this token in macro call + | +note: while trying to match meta-variable `$e:expr` + --> $DIR/feature-gate.rs:71:10 + | +LL | ($e:expr) => { + | ^^^^^^^ + +error: `let` expressions are not supported here + --> $DIR/feature-gate.rs:10:16 + | +LL | () if (let 0 = 1) => {} + | ^^^^^^^^^ + | + = note: only supported directly in conditions of `if` and `while` expressions +note: `let`s wrapped in parentheses are not supported in a context with let chains + --> $DIR/feature-gate.rs:10:16 + | +LL | () if (let 0 = 1) => {} + | ^^^^^^^^^ + +error: `let` expressions are not supported here + --> $DIR/feature-gate.rs:15:18 + | +LL | () if (((let 0 = 1))) => {} + | ^^^^^^^^^ + | + = note: only supported directly in conditions of `if` and `while` expressions +note: `let`s wrapped in parentheses are not supported in a context with let chains + --> $DIR/feature-gate.rs:15:18 + | +LL | () if (((let 0 = 1))) => {} + | ^^^^^^^^^ + +error: `let` expressions are not supported here + --> $DIR/feature-gate.rs:28:16 + | +LL | () if (let 0 = 1) && true => {} + | ^^^^^^^^^ + | + = note: only supported directly in conditions of `if` and `while` expressions +note: `let`s wrapped in parentheses are not supported in a context with let chains + --> $DIR/feature-gate.rs:28:16 + | +LL | () if (let 0 = 1) && true => {} + | ^^^^^^^^^ + +error: `let` expressions are not supported here + --> $DIR/feature-gate.rs:33:24 + | +LL | () if true && (let 0 = 1) => {} + | ^^^^^^^^^ + | + = note: only supported directly in conditions of `if` and `while` expressions +note: `let`s wrapped in parentheses are not supported in a context with let chains + --> $DIR/feature-gate.rs:33:24 + | +LL | () if true && (let 0 = 1) => {} + | ^^^^^^^^^ + +error: `let` expressions are not supported here + --> $DIR/feature-gate.rs:38:16 + | +LL | () if (let 0 = 1) && (let 0 = 1) => {} + | ^^^^^^^^^ + | + = note: only supported directly in conditions of `if` and `while` expressions +note: `let`s wrapped in parentheses are not supported in a context with let chains + --> $DIR/feature-gate.rs:38:16 + | +LL | () if (let 0 = 1) && (let 0 = 1) => {} + | ^^^^^^^^^ + +error: `let` expressions are not supported here + --> $DIR/feature-gate.rs:38:31 + | +LL | () if (let 0 = 1) && (let 0 = 1) => {} + | ^^^^^^^^^ + | + = note: only supported directly in conditions of `if` and `while` expressions +note: `let`s wrapped in parentheses are not supported in a context with let chains + --> $DIR/feature-gate.rs:38:31 + | +LL | () if (let 0 = 1) && (let 0 = 1) => {} + | ^^^^^^^^^ + +error: `let` expressions are not supported here + --> $DIR/feature-gate.rs:46:42 + | +LL | () if let 0 = 1 && let 1 = 2 && (let 2 = 3 && let 3 = 4 && let 4 = 5) => {} + | ^^^^^^^^^ + | + = note: only supported directly in conditions of `if` and `while` expressions +note: `let`s wrapped in parentheses are not supported in a context with let chains + --> $DIR/feature-gate.rs:46:42 + | +LL | () if let 0 = 1 && let 1 = 2 && (let 2 = 3 && let 3 = 4 && let 4 = 5) => {} + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + +error: `let` expressions are not supported here + --> $DIR/feature-gate.rs:46:55 + | +LL | () if let 0 = 1 && let 1 = 2 && (let 2 = 3 && let 3 = 4 && let 4 = 5) => {} + | ^^^^^^^^^ + | + = note: only supported directly in conditions of `if` and `while` expressions +note: `let`s wrapped in parentheses are not supported in a context with let chains + --> $DIR/feature-gate.rs:46:42 + | +LL | () if let 0 = 1 && let 1 = 2 && (let 2 = 3 && let 3 = 4 && let 4 = 5) => {} + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + +error: `let` expressions are not supported here + --> $DIR/feature-gate.rs:46:68 + | +LL | () if let 0 = 1 && let 1 = 2 && (let 2 = 3 && let 3 = 4 && let 4 = 5) => {} + | ^^^^^^^^^ + | + = note: only supported directly in conditions of `if` and `while` expressions +note: `let`s wrapped in parentheses are not supported in a context with let chains + --> $DIR/feature-gate.rs:46:42 + | +LL | () if let 0 = 1 && let 1 = 2 && (let 2 = 3 && let 3 = 4 && let 4 = 5) => {} + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + +error: `let` expressions are not supported here + --> $DIR/feature-gate.rs:78:16 + | +LL | use_expr!((let 0 = 1 && 0 == 0)); + | ^^^^^^^^^ + | + = note: only supported directly in conditions of `if` and `while` expressions +note: `let`s wrapped in parentheses are not supported in a context with let chains + --> $DIR/feature-gate.rs:78:16 + | +LL | use_expr!((let 0 = 1 && 0 == 0)); + | ^^^^^^^^^^^^^^^^^^^ + +error: `let` expressions are not supported here + --> $DIR/feature-gate.rs:82:16 + | +LL | use_expr!((let 0 = 1)); + | ^^^^^^^^^ + | + = note: only supported directly in conditions of `if` and `while` expressions +note: `let`s wrapped in parentheses are not supported in a context with let chains + --> $DIR/feature-gate.rs:82:16 + | +LL | use_expr!((let 0 = 1)); + | ^^^^^^^^^ + +error[E0658]: `if let` guards are experimental + --> $DIR/feature-gate.rs:7:12 + | +LL | () if let 0 = 1 => {} + | ^^^^^^^^^^^^ + | + = note: see issue #51114 <https://github.com/rust-lang/rust/issues/51114> for more information + = help: add `#![feature(if_let_guard)]` to the crate attributes to enable + = help: you can write `if matches!(<expr>, <pattern>)` instead of `if let <pattern> = <expr>` + +error[E0658]: `if let` guards are experimental + --> $DIR/feature-gate.rs:20:12 + | +LL | () if true && let 0 = 1 => {} + | ^^^^^^^^^^^^^^^^^^^^ + | + = note: see issue #51114 <https://github.com/rust-lang/rust/issues/51114> for more information + = help: add `#![feature(if_let_guard)]` to the crate attributes to enable + = help: you can write `if matches!(<expr>, <pattern>)` instead of `if let <pattern> = <expr>` + +error[E0658]: `if let` guards are experimental + --> $DIR/feature-gate.rs:24:12 + | +LL | () if let 0 = 1 && true => {} + | ^^^^^^^^^^^^^^^^^^^^ + | + = note: see issue #51114 <https://github.com/rust-lang/rust/issues/51114> for more information + = help: add `#![feature(if_let_guard)]` to the crate attributes to enable + = help: you can write `if matches!(<expr>, <pattern>)` instead of `if let <pattern> = <expr>` + +error[E0658]: `if let` guards are experimental + --> $DIR/feature-gate.rs:46:12 + | +LL | () if let 0 = 1 && let 1 = 2 && (let 2 = 3 && let 3 = 4 && let 4 = 5) => {} + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + | + = note: see issue #51114 <https://github.com/rust-lang/rust/issues/51114> for more information + = help: add `#![feature(if_let_guard)]` to the crate attributes to enable + = help: you can write `if matches!(<expr>, <pattern>)` instead of `if let <pattern> = <expr>` + +error[E0658]: `if let` guards are experimental + --> $DIR/feature-gate.rs:61:12 + | +LL | () if let Range { start: _, end: _ } = (true..true) && false => {} + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + | + = note: see issue #51114 <https://github.com/rust-lang/rust/issues/51114> for more information + = help: add `#![feature(if_let_guard)]` to the crate attributes to enable + = help: you can write `if matches!(<expr>, <pattern>)` instead of `if let <pattern> = <expr>` + +error[E0658]: `if let` guards are experimental + --> $DIR/feature-gate.rs:88:12 + | +LL | () if let 0 = 1 => {} + | ^^^^^^^^^^^^ + | + = note: see issue #51114 <https://github.com/rust-lang/rust/issues/51114> for more information + = help: add `#![feature(if_let_guard)]` to the crate attributes to enable + = help: you can write `if matches!(<expr>, <pattern>)` instead of `if let <pattern> = <expr>` + +error[E0658]: `let` expressions in this position are unstable + --> $DIR/feature-gate.rs:10:16 + | +LL | () if (let 0 = 1) => {} + | ^^^^^^^^^ + | + = note: see issue #53667 <https://github.com/rust-lang/rust/issues/53667> for more information + = help: add `#![feature(let_chains)]` to the crate attributes to enable + +error[E0658]: `let` expressions in this position are unstable + --> $DIR/feature-gate.rs:15:18 + | +LL | () if (((let 0 = 1))) => {} + | ^^^^^^^^^ + | + = note: see issue #53667 <https://github.com/rust-lang/rust/issues/53667> for more information + = help: add `#![feature(let_chains)]` to the crate attributes to enable + +error[E0658]: `let` expressions in this position are unstable + --> $DIR/feature-gate.rs:20:23 + | +LL | () if true && let 0 = 1 => {} + | ^^^^^^^^^ + | + = note: see issue #53667 <https://github.com/rust-lang/rust/issues/53667> for more information + = help: add `#![feature(let_chains)]` to the crate attributes to enable + +error[E0658]: `let` expressions in this position are unstable + --> $DIR/feature-gate.rs:24:15 + | +LL | () if let 0 = 1 && true => {} + | ^^^^^^^^^ + | + = note: see issue #53667 <https://github.com/rust-lang/rust/issues/53667> for more information + = help: add `#![feature(let_chains)]` to the crate attributes to enable + +error[E0658]: `let` expressions in this position are unstable + --> $DIR/feature-gate.rs:28:16 + | +LL | () if (let 0 = 1) && true => {} + | ^^^^^^^^^ + | + = note: see issue #53667 <https://github.com/rust-lang/rust/issues/53667> for more information + = help: add `#![feature(let_chains)]` to the crate attributes to enable + +error[E0658]: `let` expressions in this position are unstable + --> $DIR/feature-gate.rs:33:24 + | +LL | () if true && (let 0 = 1) => {} + | ^^^^^^^^^ + | + = note: see issue #53667 <https://github.com/rust-lang/rust/issues/53667> for more information + = help: add `#![feature(let_chains)]` to the crate attributes to enable + +error[E0658]: `let` expressions in this position are unstable + --> $DIR/feature-gate.rs:38:16 + | +LL | () if (let 0 = 1) && (let 0 = 1) => {} + | ^^^^^^^^^ + | + = note: see issue #53667 <https://github.com/rust-lang/rust/issues/53667> for more information + = help: add `#![feature(let_chains)]` to the crate attributes to enable + +error[E0658]: `let` expressions in this position are unstable + --> $DIR/feature-gate.rs:38:31 + | +LL | () if (let 0 = 1) && (let 0 = 1) => {} + | ^^^^^^^^^ + | + = note: see issue #53667 <https://github.com/rust-lang/rust/issues/53667> for more information + = help: add `#![feature(let_chains)]` to the crate attributes to enable + +error[E0658]: `let` expressions in this position are unstable + --> $DIR/feature-gate.rs:46:15 + | +LL | () if let 0 = 1 && let 1 = 2 && (let 2 = 3 && let 3 = 4 && let 4 = 5) => {} + | ^^^^^^^^^ + | + = note: see issue #53667 <https://github.com/rust-lang/rust/issues/53667> for more information + = help: add `#![feature(let_chains)]` to the crate attributes to enable + +error[E0658]: `let` expressions in this position are unstable + --> $DIR/feature-gate.rs:46:28 + | +LL | () if let 0 = 1 && let 1 = 2 && (let 2 = 3 && let 3 = 4 && let 4 = 5) => {} + | ^^^^^^^^^ + | + = note: see issue #53667 <https://github.com/rust-lang/rust/issues/53667> for more information + = help: add `#![feature(let_chains)]` to the crate attributes to enable + +error[E0658]: `let` expressions in this position are unstable + --> $DIR/feature-gate.rs:46:42 + | +LL | () if let 0 = 1 && let 1 = 2 && (let 2 = 3 && let 3 = 4 && let 4 = 5) => {} + | ^^^^^^^^^ + | + = note: see issue #53667 <https://github.com/rust-lang/rust/issues/53667> for more information + = help: add `#![feature(let_chains)]` to the crate attributes to enable + +error[E0658]: `let` expressions in this position are unstable + --> $DIR/feature-gate.rs:46:55 + | +LL | () if let 0 = 1 && let 1 = 2 && (let 2 = 3 && let 3 = 4 && let 4 = 5) => {} + | ^^^^^^^^^ + | + = note: see issue #53667 <https://github.com/rust-lang/rust/issues/53667> for more information + = help: add `#![feature(let_chains)]` to the crate attributes to enable + +error[E0658]: `let` expressions in this position are unstable + --> $DIR/feature-gate.rs:46:68 + | +LL | () if let 0 = 1 && let 1 = 2 && (let 2 = 3 && let 3 = 4 && let 4 = 5) => {} + | ^^^^^^^^^ + | + = note: see issue #53667 <https://github.com/rust-lang/rust/issues/53667> for more information + = help: add `#![feature(let_chains)]` to the crate attributes to enable + +error[E0658]: `let` expressions in this position are unstable + --> $DIR/feature-gate.rs:61:15 + | +LL | () if let Range { start: _, end: _ } = (true..true) && false => {} + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + | + = note: see issue #53667 <https://github.com/rust-lang/rust/issues/53667> for more information + = help: add `#![feature(let_chains)]` to the crate attributes to enable + +error[E0658]: `let` expressions in this position are unstable + --> $DIR/feature-gate.rs:78:16 + | +LL | use_expr!((let 0 = 1 && 0 == 0)); + | ^^^^^^^^^ + | + = note: see issue #53667 <https://github.com/rust-lang/rust/issues/53667> for more information + = help: add `#![feature(let_chains)]` to the crate attributes to enable + +error[E0658]: `let` expressions in this position are unstable + --> $DIR/feature-gate.rs:82:16 + | +LL | use_expr!((let 0 = 1)); + | ^^^^^^^^^ + | + = note: see issue #53667 <https://github.com/rust-lang/rust/issues/53667> for more information + = help: add `#![feature(let_chains)]` to the crate attributes to enable + +error: aborting due to 45 previous errors + +For more information about this error, try `rustc --explain E0658`. diff --git a/tests/ui/rfcs/rfc-2294-if-let-guard/run-pass.rs b/tests/ui/rfcs/rfc-2294-if-let-guard/run-pass.rs new file mode 100644 index 000000000..a303a0d1f --- /dev/null +++ b/tests/ui/rfcs/rfc-2294-if-let-guard/run-pass.rs @@ -0,0 +1,40 @@ +// run-pass + +#![feature(if_let_guard)] + +enum Foo { + Bar, + Baz, + Qux(u8), +} + +fn bar(x: bool) -> Foo { + if x { Foo::Baz } else { Foo::Bar } +} + +fn baz(x: u8) -> Foo { + if x % 2 == 0 { Foo::Bar } else { Foo::Baz } +} + +fn qux(x: u8) -> Foo { + Foo::Qux(x.rotate_left(1)) +} + +fn main() { + match Some((true, 3)) { + Some((x, _)) if let Foo::Bar = bar(x) => panic!(), + Some((_, x)) if let Foo::Baz = baz(x) => {}, + _ => panic!(), + } + match Some(42) { + Some(x) if let Foo::Qux(y) = qux(x) => assert_eq!(y, 84), + _ => panic!(), + } + + // issue #88015 + #[allow(irrefutable_let_patterns)] + match () { + () | () if let x = 42 => assert_eq!(x, 42), + _ => panic!() + } +} diff --git a/tests/ui/rfcs/rfc-2294-if-let-guard/typeck.rs b/tests/ui/rfcs/rfc-2294-if-let-guard/typeck.rs new file mode 100644 index 000000000..ad178dfa4 --- /dev/null +++ b/tests/ui/rfcs/rfc-2294-if-let-guard/typeck.rs @@ -0,0 +1,15 @@ +#![feature(if_let_guard)] + +fn ok() -> Result<Option<bool>, ()> { + Ok(Some(true)) +} + +fn main() { + match ok() { + Ok(x) if let Err(_) = x => {}, + //~^ ERROR mismatched types + Ok(x) if let 0 = x => {}, + //~^ ERROR mismatched types + _ => {} + } +} diff --git a/tests/ui/rfcs/rfc-2294-if-let-guard/typeck.stderr b/tests/ui/rfcs/rfc-2294-if-let-guard/typeck.stderr new file mode 100644 index 000000000..4ce97a68a --- /dev/null +++ b/tests/ui/rfcs/rfc-2294-if-let-guard/typeck.stderr @@ -0,0 +1,25 @@ +error[E0308]: mismatched types + --> $DIR/typeck.rs:9:22 + | +LL | Ok(x) if let Err(_) = x => {}, + | ^^^^^^ - this expression has type `Option<bool>` + | | + | expected `Option<bool>`, found `Result<_, _>` + | + = note: expected enum `Option<bool>` + found enum `Result<_, _>` + +error[E0308]: mismatched types + --> $DIR/typeck.rs:11:22 + | +LL | Ok(x) if let 0 = x => {}, + | ^ - this expression has type `Option<bool>` + | | + | expected `Option<bool>`, found integer + | + = note: expected enum `Option<bool>` + found type `{integer}` + +error: aborting due to 2 previous errors + +For more information about this error, try `rustc --explain E0308`. diff --git a/tests/ui/rfcs/rfc-2294-if-let-guard/warns.rs b/tests/ui/rfcs/rfc-2294-if-let-guard/warns.rs new file mode 100644 index 000000000..3ad1a50c6 --- /dev/null +++ b/tests/ui/rfcs/rfc-2294-if-let-guard/warns.rs @@ -0,0 +1,21 @@ +#![feature(if_let_guard)] + +#[deny(irrefutable_let_patterns)] +fn irrefutable_let_guard() { + match Some(()) { + Some(x) if let () = x => {} + //~^ ERROR irrefutable `if let` guard + _ => {} + } +} + +#[deny(unreachable_patterns)] +fn unreachable_pattern() { + match Some(()) { + x if let None | None = x => {} + //~^ ERROR unreachable pattern + _ => {} + } +} + +fn main() {} diff --git a/tests/ui/rfcs/rfc-2294-if-let-guard/warns.stderr b/tests/ui/rfcs/rfc-2294-if-let-guard/warns.stderr new file mode 100644 index 000000000..75f22ac8d --- /dev/null +++ b/tests/ui/rfcs/rfc-2294-if-let-guard/warns.stderr @@ -0,0 +1,28 @@ +error: irrefutable `if let` guard pattern + --> $DIR/warns.rs:6:24 + | +LL | Some(x) if let () = x => {} + | ^^ + | + = note: this pattern will always match, so the guard is useless + = help: consider removing the guard and adding a `let` inside the match arm +note: the lint level is defined here + --> $DIR/warns.rs:3:8 + | +LL | #[deny(irrefutable_let_patterns)] + | ^^^^^^^^^^^^^^^^^^^^^^^^ + +error: unreachable pattern + --> $DIR/warns.rs:15:25 + | +LL | x if let None | None = x => {} + | ^^^^ + | +note: the lint level is defined here + --> $DIR/warns.rs:12:8 + | +LL | #[deny(unreachable_patterns)] + | ^^^^^^^^^^^^^^^^^^^^ + +error: aborting due to 2 previous errors + diff --git a/tests/ui/rfcs/rfc-2302-self-struct-ctor.rs b/tests/ui/rfcs/rfc-2302-self-struct-ctor/rfc-2302-self-struct-ctor.rs index 1ec20c500..1ec20c500 100644 --- a/tests/ui/rfcs/rfc-2302-self-struct-ctor.rs +++ b/tests/ui/rfcs/rfc-2302-self-struct-ctor/rfc-2302-self-struct-ctor.rs diff --git a/tests/ui/rfcs/rfc-2306-convert-id/convert-id-const-with-gate.rs b/tests/ui/rfcs/rfc-2306-convert-id/convert-id-const-with-gate.rs new file mode 100644 index 000000000..762dfbe48 --- /dev/null +++ b/tests/ui/rfcs/rfc-2306-convert-id/convert-id-const-with-gate.rs @@ -0,0 +1,7 @@ +// This test should pass since 'identity' is const fn. + +// build-pass (FIXME(62277): could be check-pass?) + +fn main() { + const _FOO: u8 = ::std::convert::identity(42u8); +} diff --git a/tests/ui/rfcs/rfc-2361-dbg-macro/dbg-macro-expected-behavior.rs b/tests/ui/rfcs/rfc-2361-dbg-macro/dbg-macro-expected-behavior.rs new file mode 100644 index 000000000..542be3942 --- /dev/null +++ b/tests/ui/rfcs/rfc-2361-dbg-macro/dbg-macro-expected-behavior.rs @@ -0,0 +1,69 @@ +// run-pass +// check-run-results + +// Tests ensuring that `dbg!(expr)` has the expected run-time behavior. +// as well as some compile time properties we expect. + +#![allow(dropping_copy_types)] + +#[derive(Copy, Clone, Debug)] +struct Unit; + +#[derive(Copy, Clone, Debug, PartialEq)] +struct Point<T> { + x: T, + y: T, +} + +#[derive(Debug, PartialEq)] +struct NoCopy(usize); + +fn main() { + let a: Unit = dbg!(Unit); + let _: Unit = dbg!(a); + // We can move `a` because it's Copy. + drop(a); + + // `Point<T>` will be faithfully formatted according to `{:#?}`. + let a = Point { x: 42, y: 24 }; + let b: Point<u8> = dbg!(Point { x: 42, y: 24 }); // test stringify!(..) + let c: Point<u8> = dbg!(b); + // Identity conversion: + assert_eq!(a, b); + assert_eq!(a, c); + // We can move `b` because it's Copy. + drop(b); + + // Without parameters works as expected. + let _: () = dbg!(); + + // Test that we can borrow and that successive applications is still identity. + let a = NoCopy(1337); + let b: &NoCopy = dbg!(dbg!(&a)); + assert_eq!(&a, b); + + // Test involving lifetimes of temporaries: + fn f<'a>(x: &'a u8) -> &'a u8 { x } + let a: &u8 = dbg!(f(&42)); + assert_eq!(a, &42); + + // Test side effects: + let mut foo = 41; + assert_eq!(7331, dbg!({ + foo += 1; + eprintln!("before"); + 7331 + })); + assert_eq!(foo, 42); + + // Test trailing comma: + assert_eq!(("Yeah",), dbg!(("Yeah",))); + + // Test multiple arguments: + assert_eq!((1u8, 2u32), dbg!(1, + 2)); + + // Test multiple arguments + trailing comma: + assert_eq!((1u8, 2u32, "Yeah"), dbg!(1u8, 2u32, + "Yeah",)); +} diff --git a/tests/ui/rfcs/rfc-2361-dbg-macro/dbg-macro-expected-behavior.run.stderr b/tests/ui/rfcs/rfc-2361-dbg-macro/dbg-macro-expected-behavior.run.stderr new file mode 100644 index 000000000..a20a6062c --- /dev/null +++ b/tests/ui/rfcs/rfc-2361-dbg-macro/dbg-macro-expected-behavior.run.stderr @@ -0,0 +1,28 @@ +[$DIR/dbg-macro-expected-behavior.rs:22] Unit = Unit +[$DIR/dbg-macro-expected-behavior.rs:23] a = Unit +[$DIR/dbg-macro-expected-behavior.rs:29] Point { x: 42, y: 24 } = Point { + x: 42, + y: 24, +} +[$DIR/dbg-macro-expected-behavior.rs:30] b = Point { + x: 42, + y: 24, +} +[$DIR/dbg-macro-expected-behavior.rs:38] +[$DIR/dbg-macro-expected-behavior.rs:42] &a = NoCopy( + 1337, +) +[$DIR/dbg-macro-expected-behavior.rs:42] dbg!(& a) = NoCopy( + 1337, +) +[$DIR/dbg-macro-expected-behavior.rs:47] f(&42) = 42 +before +[$DIR/dbg-macro-expected-behavior.rs:52] { foo += 1; eprintln!("before"); 7331 } = 7331 +[$DIR/dbg-macro-expected-behavior.rs:60] ("Yeah",) = ( + "Yeah", +) +[$DIR/dbg-macro-expected-behavior.rs:63] 1 = 1 +[$DIR/dbg-macro-expected-behavior.rs:63] 2 = 2 +[$DIR/dbg-macro-expected-behavior.rs:67] 1u8 = 1 +[$DIR/dbg-macro-expected-behavior.rs:67] 2u32 = 2 +[$DIR/dbg-macro-expected-behavior.rs:67] "Yeah" = "Yeah" diff --git a/tests/ui/rfcs/rfc-2361-dbg-macro/dbg-macro-move-semantics.rs b/tests/ui/rfcs/rfc-2361-dbg-macro/dbg-macro-move-semantics.rs new file mode 100644 index 000000000..9f3c567b6 --- /dev/null +++ b/tests/ui/rfcs/rfc-2361-dbg-macro/dbg-macro-move-semantics.rs @@ -0,0 +1,10 @@ +// Test ensuring that `dbg!(expr)` will take ownership of the argument. + +#[derive(Debug)] +struct NoCopy(usize); + +fn main() { + let a = NoCopy(0); + let _ = dbg!(a); + let _ = dbg!(a); //~ ERROR use of moved value +} diff --git a/tests/ui/rfcs/rfc-2361-dbg-macro/dbg-macro-move-semantics.stderr b/tests/ui/rfcs/rfc-2361-dbg-macro/dbg-macro-move-semantics.stderr new file mode 100644 index 000000000..e97fdcce1 --- /dev/null +++ b/tests/ui/rfcs/rfc-2361-dbg-macro/dbg-macro-move-semantics.stderr @@ -0,0 +1,14 @@ +error[E0382]: use of moved value: `a` + --> $DIR/dbg-macro-move-semantics.rs:9:18 + | +LL | let a = NoCopy(0); + | - move occurs because `a` has type `NoCopy`, which does not implement the `Copy` trait +LL | let _ = dbg!(a); + | ------- value moved here +LL | let _ = dbg!(a); + | ^ value used here after move + | + +error: aborting due to previous error + +For more information about this error, try `rustc --explain E0382`. diff --git a/tests/ui/rfcs/rfc-2361-dbg-macro/dbg-macro-requires-debug.rs b/tests/ui/rfcs/rfc-2361-dbg-macro/dbg-macro-requires-debug.rs new file mode 100644 index 000000000..f2fb62d76 --- /dev/null +++ b/tests/ui/rfcs/rfc-2361-dbg-macro/dbg-macro-requires-debug.rs @@ -0,0 +1,7 @@ +// Test ensuring that `dbg!(expr)` requires the passed type to implement `Debug`. + +struct NotDebug; + +fn main() { + let _: NotDebug = dbg!(NotDebug); //~ ERROR `NotDebug` doesn't implement `Debug` +} diff --git a/tests/ui/rfcs/rfc-2361-dbg-macro/dbg-macro-requires-debug.stderr b/tests/ui/rfcs/rfc-2361-dbg-macro/dbg-macro-requires-debug.stderr new file mode 100644 index 000000000..ce165e646 --- /dev/null +++ b/tests/ui/rfcs/rfc-2361-dbg-macro/dbg-macro-requires-debug.stderr @@ -0,0 +1,18 @@ +error[E0277]: `NotDebug` doesn't implement `Debug` + --> $DIR/dbg-macro-requires-debug.rs:6:23 + | +LL | let _: NotDebug = dbg!(NotDebug); + | ^^^^^^^^^^^^^^ `NotDebug` cannot be formatted using `{:?}` + | + = help: the trait `Debug` is not implemented for `NotDebug` + = note: add `#[derive(Debug)]` to `NotDebug` or manually `impl Debug for NotDebug` + = note: this error originates in the macro `$crate::format_args_nl` which comes from the expansion of the macro `dbg` (in Nightly builds, run with -Z macro-backtrace for more info) +help: consider annotating `NotDebug` with `#[derive(Debug)]` + | +LL + #[derive(Debug)] +LL | struct NotDebug; + | + +error: aborting due to previous error + +For more information about this error, try `rustc --explain E0277`. diff --git a/tests/ui/rfcs/rfc-2397-do-not-recommend/feature-gate-do_not_recommend.rs b/tests/ui/rfcs/rfc-2397-do-not-recommend/feature-gate-do_not_recommend.rs new file mode 100644 index 000000000..5053c115b --- /dev/null +++ b/tests/ui/rfcs/rfc-2397-do-not-recommend/feature-gate-do_not_recommend.rs @@ -0,0 +1,21 @@ +#![feature(do_not_recommend)] + +pub trait Foo { +} + +impl Foo for i32 { +} + +pub trait Bar { +} + +#[do_not_recommend] +impl<T: Foo> Bar for T { +} + +fn stuff<T: Bar>(_: T) {} + +fn main() { + stuff(1u8); + //~^ the trait bound `u8: Foo` is not satisfied +} diff --git a/tests/ui/rfcs/rfc-2397-do-not-recommend/feature-gate-do_not_recommend.stderr b/tests/ui/rfcs/rfc-2397-do-not-recommend/feature-gate-do_not_recommend.stderr new file mode 100644 index 000000000..a3e559054 --- /dev/null +++ b/tests/ui/rfcs/rfc-2397-do-not-recommend/feature-gate-do_not_recommend.stderr @@ -0,0 +1,25 @@ +error[E0277]: the trait bound `u8: Foo` is not satisfied + --> $DIR/feature-gate-do_not_recommend.rs:19:11 + | +LL | stuff(1u8); + | ----- ^^^ the trait `Foo` is not implemented for `u8` + | | + | required by a bound introduced by this call + | + = help: the trait `Foo` is implemented for `i32` +note: required for `u8` to implement `Bar` + --> $DIR/feature-gate-do_not_recommend.rs:13:14 + | +LL | impl<T: Foo> Bar for T { + | --- ^^^ ^ + | | + | unsatisfied trait bound introduced here +note: required by a bound in `stuff` + --> $DIR/feature-gate-do_not_recommend.rs:16:13 + | +LL | fn stuff<T: Bar>(_: T) {} + | ^^^ required by this bound in `stuff` + +error: aborting due to previous error + +For more information about this error, try `rustc --explain E0277`. diff --git a/tests/ui/rfcs/rfc-2397-do-not-recommend/incorrect-locations.rs b/tests/ui/rfcs/rfc-2397-do-not-recommend/incorrect-locations.rs new file mode 100644 index 000000000..91863f5e4 --- /dev/null +++ b/tests/ui/rfcs/rfc-2397-do-not-recommend/incorrect-locations.rs @@ -0,0 +1,45 @@ +#![feature(do_not_recommend)] + +#[do_not_recommend] +//~^ `#[do_not_recommend]` can only be placed +const CONST: () = (); + +#[do_not_recommend] +//~^ `#[do_not_recommend]` can only be placed +static Static: () = (); + +#[do_not_recommend] +//~^ `#[do_not_recommend]` can only be placed +type Type = (); + +#[do_not_recommend] +//~^ `#[do_not_recommend]` can only be placed +enum Enum { +} + +#[do_not_recommend] +//~^ `#[do_not_recommend]` can only be placed +extern { +} + +#[do_not_recommend] +//~^ `#[do_not_recommend]` can only be placed +fn fun() { +} + +#[do_not_recommend] +//~^ `#[do_not_recommend]` can only be placed +struct Struct { +} + +#[do_not_recommend] +//~^ `#[do_not_recommend]` can only be placed +trait Trait { +} + +#[do_not_recommend] +impl Trait for i32 { +} + +fn main() { +} diff --git a/tests/ui/rfcs/rfc-2397-do-not-recommend/incorrect-locations.stderr b/tests/ui/rfcs/rfc-2397-do-not-recommend/incorrect-locations.stderr new file mode 100644 index 000000000..01ebc23c8 --- /dev/null +++ b/tests/ui/rfcs/rfc-2397-do-not-recommend/incorrect-locations.stderr @@ -0,0 +1,50 @@ +error: `#[do_not_recommend]` can only be placed on trait implementations + --> $DIR/incorrect-locations.rs:3:1 + | +LL | #[do_not_recommend] + | ^^^^^^^^^^^^^^^^^^^ + +error: `#[do_not_recommend]` can only be placed on trait implementations + --> $DIR/incorrect-locations.rs:7:1 + | +LL | #[do_not_recommend] + | ^^^^^^^^^^^^^^^^^^^ + +error: `#[do_not_recommend]` can only be placed on trait implementations + --> $DIR/incorrect-locations.rs:11:1 + | +LL | #[do_not_recommend] + | ^^^^^^^^^^^^^^^^^^^ + +error: `#[do_not_recommend]` can only be placed on trait implementations + --> $DIR/incorrect-locations.rs:15:1 + | +LL | #[do_not_recommend] + | ^^^^^^^^^^^^^^^^^^^ + +error: `#[do_not_recommend]` can only be placed on trait implementations + --> $DIR/incorrect-locations.rs:20:1 + | +LL | #[do_not_recommend] + | ^^^^^^^^^^^^^^^^^^^ + +error: `#[do_not_recommend]` can only be placed on trait implementations + --> $DIR/incorrect-locations.rs:25:1 + | +LL | #[do_not_recommend] + | ^^^^^^^^^^^^^^^^^^^ + +error: `#[do_not_recommend]` can only be placed on trait implementations + --> $DIR/incorrect-locations.rs:30:1 + | +LL | #[do_not_recommend] + | ^^^^^^^^^^^^^^^^^^^ + +error: `#[do_not_recommend]` can only be placed on trait implementations + --> $DIR/incorrect-locations.rs:35:1 + | +LL | #[do_not_recommend] + | ^^^^^^^^^^^^^^^^^^^ + +error: aborting due to 8 previous errors + diff --git a/tests/ui/rfcs/rfc-2397-do-not-recommend/unstable-feature.rs b/tests/ui/rfcs/rfc-2397-do-not-recommend/unstable-feature.rs new file mode 100644 index 000000000..f0c5c222e --- /dev/null +++ b/tests/ui/rfcs/rfc-2397-do-not-recommend/unstable-feature.rs @@ -0,0 +1,10 @@ +trait Foo { +} + +#[do_not_recommend] +//~^ ERROR the `#[do_not_recommend]` attribute is an experimental feature +impl Foo for i32 { +} + +fn main() { +} diff --git a/tests/ui/rfcs/rfc-2397-do-not-recommend/unstable-feature.stderr b/tests/ui/rfcs/rfc-2397-do-not-recommend/unstable-feature.stderr new file mode 100644 index 000000000..1597e5be4 --- /dev/null +++ b/tests/ui/rfcs/rfc-2397-do-not-recommend/unstable-feature.stderr @@ -0,0 +1,12 @@ +error[E0658]: the `#[do_not_recommend]` attribute is an experimental feature + --> $DIR/unstable-feature.rs:4:1 + | +LL | #[do_not_recommend] + | ^^^^^^^^^^^^^^^^^^^ + | + = note: see issue #51992 <https://github.com/rust-lang/rust/issues/51992> for more information + = help: add `#![feature(do_not_recommend)]` 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/tests/ui/rfcs/rfc-2421-unreserve-pure-offsetof-sizeof-alignof.rs b/tests/ui/rfcs/rfc-2421-unreserve-pure-offsetof-sizeof-alignof/offsetof-alignof-sizeof-pure-can-be-used-as-idents.rs index 6d7bca4da..6d7bca4da 100644 --- a/tests/ui/rfcs/rfc-2421-unreserve-pure-offsetof-sizeof-alignof.rs +++ b/tests/ui/rfcs/rfc-2421-unreserve-pure-offsetof-sizeof-alignof/offsetof-alignof-sizeof-pure-can-be-used-as-idents.rs diff --git a/tests/ui/rfcs/rfc-2457-non-ascii-idents/auxiliary/mod_file_nonascii_with_path_allowed-aux.rs b/tests/ui/rfcs/rfc-2457-non-ascii-idents/auxiliary/mod_file_nonascii_with_path_allowed-aux.rs new file mode 100644 index 000000000..e373b6438 --- /dev/null +++ b/tests/ui/rfcs/rfc-2457-non-ascii-idents/auxiliary/mod_file_nonascii_with_path_allowed-aux.rs @@ -0,0 +1 @@ +pub trait Foo {} diff --git a/tests/ui/rfcs/rfc-2457-non-ascii-idents/crate_name_nonascii_forbidden-1.rs b/tests/ui/rfcs/rfc-2457-non-ascii-idents/crate_name_nonascii_forbidden-1.rs new file mode 100644 index 000000000..c07ba54af --- /dev/null +++ b/tests/ui/rfcs/rfc-2457-non-ascii-idents/crate_name_nonascii_forbidden-1.rs @@ -0,0 +1,3 @@ +extern crate ьаг; //~ ERROR cannot load a crate with a non-ascii name `ьаг` + +fn main() {} diff --git a/tests/ui/rfcs/rfc-2457-non-ascii-idents/crate_name_nonascii_forbidden-1.stderr b/tests/ui/rfcs/rfc-2457-non-ascii-idents/crate_name_nonascii_forbidden-1.stderr new file mode 100644 index 000000000..a8f3abe59 --- /dev/null +++ b/tests/ui/rfcs/rfc-2457-non-ascii-idents/crate_name_nonascii_forbidden-1.stderr @@ -0,0 +1,8 @@ +error: cannot load a crate with a non-ascii name `ьаг` + --> $DIR/crate_name_nonascii_forbidden-1.rs:1:1 + | +LL | extern crate ьаг; + | ^^^^^^^^^^^^^^^^^ + +error: aborting due to previous error + diff --git a/tests/ui/rfcs/rfc-2457-non-ascii-idents/crate_name_nonascii_forbidden-2.rs b/tests/ui/rfcs/rfc-2457-non-ascii-idents/crate_name_nonascii_forbidden-2.rs new file mode 100644 index 000000000..f8e033937 --- /dev/null +++ b/tests/ui/rfcs/rfc-2457-non-ascii-idents/crate_name_nonascii_forbidden-2.rs @@ -0,0 +1,6 @@ +// compile-flags:--extern му_сгате +// edition:2018 + +use му_сгате::baz; //~ ERROR cannot load a crate with a non-ascii name `му_сгате` + +fn main() {} diff --git a/tests/ui/rfcs/rfc-2457-non-ascii-idents/crate_name_nonascii_forbidden-2.stderr b/tests/ui/rfcs/rfc-2457-non-ascii-idents/crate_name_nonascii_forbidden-2.stderr new file mode 100644 index 000000000..05fc4fb22 --- /dev/null +++ b/tests/ui/rfcs/rfc-2457-non-ascii-idents/crate_name_nonascii_forbidden-2.stderr @@ -0,0 +1,8 @@ +error: cannot load a crate with a non-ascii name `му_сгате` + --> $DIR/crate_name_nonascii_forbidden-2.rs:4:5 + | +LL | use му_сгате::baz; + | ^^^^^^^^ + +error: aborting due to previous error + diff --git a/tests/ui/rfcs/rfc-2457-non-ascii-idents/extern_block_nonascii_forbidden.rs b/tests/ui/rfcs/rfc-2457-non-ascii-idents/extern_block_nonascii_forbidden.rs new file mode 100644 index 000000000..ad6825404 --- /dev/null +++ b/tests/ui/rfcs/rfc-2457-non-ascii-idents/extern_block_nonascii_forbidden.rs @@ -0,0 +1,9 @@ +#![feature(extern_types)] + +extern "C" { + type 一; //~ items in `extern` blocks cannot use non-ascii identifiers + fn 二(); //~ items in `extern` blocks cannot use non-ascii identifiers + static 三: usize; //~ items in `extern` blocks cannot use non-ascii identifiers +} + +fn main() {} diff --git a/tests/ui/rfcs/rfc-2457-non-ascii-idents/extern_block_nonascii_forbidden.stderr b/tests/ui/rfcs/rfc-2457-non-ascii-idents/extern_block_nonascii_forbidden.stderr new file mode 100644 index 000000000..ca1b8a6e7 --- /dev/null +++ b/tests/ui/rfcs/rfc-2457-non-ascii-idents/extern_block_nonascii_forbidden.stderr @@ -0,0 +1,34 @@ +error: items in `extern` blocks cannot use non-ascii identifiers + --> $DIR/extern_block_nonascii_forbidden.rs:4:10 + | +LL | extern "C" { + | ---------- in this `extern` block +LL | type 一; + | ^^ + | + = note: this limitation may be lifted in the future; see issue #83942 <https://github.com/rust-lang/rust/issues/83942> for more information + +error: items in `extern` blocks cannot use non-ascii identifiers + --> $DIR/extern_block_nonascii_forbidden.rs:5:8 + | +LL | extern "C" { + | ---------- in this `extern` block +LL | type 一; +LL | fn 二(); + | ^^ + | + = note: this limitation may be lifted in the future; see issue #83942 <https://github.com/rust-lang/rust/issues/83942> for more information + +error: items in `extern` blocks cannot use non-ascii identifiers + --> $DIR/extern_block_nonascii_forbidden.rs:6:12 + | +LL | extern "C" { + | ---------- in this `extern` block +... +LL | static 三: usize; + | ^^ + | + = note: this limitation may be lifted in the future; see issue #83942 <https://github.com/rust-lang/rust/issues/83942> for more information + +error: aborting due to 3 previous errors + diff --git a/tests/ui/rfcs/rfc-2457-non-ascii-idents/idents-normalized.rs b/tests/ui/rfcs/rfc-2457-non-ascii-idents/idents-normalized.rs new file mode 100644 index 000000000..1023fee37 --- /dev/null +++ b/tests/ui/rfcs/rfc-2457-non-ascii-idents/idents-normalized.rs @@ -0,0 +1,7 @@ +// check-pass + +struct Résumé; // ['LATIN SMALL LETTER E WITH ACUTE'] + +fn main() { + let _ = Résumé; // ['LATIN SMALL LETTER E', 'COMBINING ACUTE ACCENT'] +} diff --git a/tests/ui/rfcs/rfc-2457-non-ascii-idents/mod_file_nonascii_forbidden.rs b/tests/ui/rfcs/rfc-2457-non-ascii-idents/mod_file_nonascii_forbidden.rs new file mode 100644 index 000000000..e949e2319 --- /dev/null +++ b/tests/ui/rfcs/rfc-2457-non-ascii-idents/mod_file_nonascii_forbidden.rs @@ -0,0 +1,4 @@ +mod řųśť; //~ trying to load file for +//~^ file not found for + +fn main() {} diff --git a/tests/ui/rfcs/rfc-2457-non-ascii-idents/mod_file_nonascii_forbidden.stderr b/tests/ui/rfcs/rfc-2457-non-ascii-idents/mod_file_nonascii_forbidden.stderr new file mode 100644 index 000000000..7639ae9f6 --- /dev/null +++ b/tests/ui/rfcs/rfc-2457-non-ascii-idents/mod_file_nonascii_forbidden.stderr @@ -0,0 +1,20 @@ +error[E0583]: file not found for module `řųśť` + --> $DIR/mod_file_nonascii_forbidden.rs:1:1 + | +LL | mod řųśť; + | ^^^^^^^^^ + | + = help: to create the module `řųśť`, create file "$DIR/řųśť.rs" or "$DIR/řųśť/mod.rs" + +error[E0754]: trying to load file for module `řųśť` with non-ascii identifier name + --> $DIR/mod_file_nonascii_forbidden.rs:1:5 + | +LL | mod řųśť; + | ^^^^ + | + = help: consider using the `#[path]` attribute to specify filesystem path + +error: aborting due to 2 previous errors + +Some errors have detailed explanations: E0583, E0754. +For more information about an error, try `rustc --explain E0583`. diff --git a/tests/ui/rfcs/rfc-2457-non-ascii-idents/mod_file_nonascii_with_path_allowed.rs b/tests/ui/rfcs/rfc-2457-non-ascii-idents/mod_file_nonascii_with_path_allowed.rs new file mode 100644 index 000000000..94327846d --- /dev/null +++ b/tests/ui/rfcs/rfc-2457-non-ascii-idents/mod_file_nonascii_with_path_allowed.rs @@ -0,0 +1,6 @@ +// check-pass + +#[path="auxiliary/mod_file_nonascii_with_path_allowed-aux.rs"] +mod řųśť; + +fn main() {} diff --git a/tests/ui/rfcs/rfc-2457-non-ascii-idents/mod_inline_nonascii_allowed.rs b/tests/ui/rfcs/rfc-2457-non-ascii-idents/mod_inline_nonascii_allowed.rs new file mode 100644 index 000000000..e1d836b7c --- /dev/null +++ b/tests/ui/rfcs/rfc-2457-non-ascii-idents/mod_inline_nonascii_allowed.rs @@ -0,0 +1,7 @@ +// check-pass + +mod řųśť { + const IS_GREAT: bool = true; +} + +fn main() {} diff --git a/tests/ui/rfcs/rfc-2457-non-ascii-idents/no_mangle_nonascii_forbidden.rs b/tests/ui/rfcs/rfc-2457-non-ascii-idents/no_mangle_nonascii_forbidden.rs new file mode 100644 index 000000000..f4c126a6e --- /dev/null +++ b/tests/ui/rfcs/rfc-2457-non-ascii-idents/no_mangle_nonascii_forbidden.rs @@ -0,0 +1,20 @@ +#[no_mangle] +pub fn řųśť() {} //~ `#[no_mangle]` requires ASCII identifier + +pub struct Foo; + +impl Foo { + #[no_mangle] + pub fn řųśť() {} //~ `#[no_mangle]` requires ASCII identifier +} + +trait Bar { + fn řųśť(); +} + +impl Bar for Foo { + #[no_mangle] + fn řųśť() {} //~ `#[no_mangle]` requires ASCII identifier +} + +fn main() {} diff --git a/tests/ui/rfcs/rfc-2457-non-ascii-idents/no_mangle_nonascii_forbidden.stderr b/tests/ui/rfcs/rfc-2457-non-ascii-idents/no_mangle_nonascii_forbidden.stderr new file mode 100644 index 000000000..459d5d6b5 --- /dev/null +++ b/tests/ui/rfcs/rfc-2457-non-ascii-idents/no_mangle_nonascii_forbidden.stderr @@ -0,0 +1,21 @@ +error[E0754]: `#[no_mangle]` requires ASCII identifier + --> $DIR/no_mangle_nonascii_forbidden.rs:2:1 + | +LL | pub fn řųśť() {} + | ^^^^^^^^^^^^^ + +error[E0754]: `#[no_mangle]` requires ASCII identifier + --> $DIR/no_mangle_nonascii_forbidden.rs:8:5 + | +LL | pub fn řųśť() {} + | ^^^^^^^^^^^^^ + +error[E0754]: `#[no_mangle]` requires ASCII identifier + --> $DIR/no_mangle_nonascii_forbidden.rs:17:5 + | +LL | fn řųśť() {} + | ^^^^^^^^^ + +error: aborting due to 3 previous errors + +For more information about this error, try `rustc --explain E0754`. diff --git a/tests/ui/rfcs/rfc-2497-if-let-chains/ast-lowering-does-not-wrap-let-chains.rs b/tests/ui/rfcs/rfc-2497-if-let-chains/ast-lowering-does-not-wrap-let-chains.rs new file mode 100644 index 000000000..d851fac8e --- /dev/null +++ b/tests/ui/rfcs/rfc-2497-if-let-chains/ast-lowering-does-not-wrap-let-chains.rs @@ -0,0 +1,16 @@ +// run-pass + +#![feature(let_chains)] +#![allow(irrefutable_let_patterns)] + +fn main() { + let first = Some(1); + let second = Some(2); + let mut n = 0; + if let x = first && let y = second && 1 == 1 { + assert_eq!(x, first); + assert_eq!(y, second); + n = 1; + } + assert_eq!(n, 1); +} diff --git a/tests/ui/rfcs/rfc-2497-if-let-chains/ast-pretty-check.rs b/tests/ui/rfcs/rfc-2497-if-let-chains/ast-pretty-check.rs new file mode 100644 index 000000000..69bc189dd --- /dev/null +++ b/tests/ui/rfcs/rfc-2497-if-let-chains/ast-pretty-check.rs @@ -0,0 +1,6 @@ +// check-pass +// compile-flags: -Z unpretty=expanded + +fn main() { + if let 0 = 1 {} +} diff --git a/tests/ui/rfcs/rfc-2497-if-let-chains/ast-pretty-check.stdout b/tests/ui/rfcs/rfc-2497-if-let-chains/ast-pretty-check.stdout new file mode 100644 index 000000000..e737ef26e --- /dev/null +++ b/tests/ui/rfcs/rfc-2497-if-let-chains/ast-pretty-check.stdout @@ -0,0 +1,10 @@ +#![feature(prelude_import)] +#![no_std] +#[prelude_import] +use ::std::prelude::rust_2015::*; +#[macro_use] +extern crate std; +// check-pass +// compile-flags: -Z unpretty=expanded + +fn main() { if let 0 = 1 {} } diff --git a/tests/ui/rfcs/rfc-2497-if-let-chains/ast-validate-guards.rs b/tests/ui/rfcs/rfc-2497-if-let-chains/ast-validate-guards.rs new file mode 100644 index 000000000..e6dee2a1d --- /dev/null +++ b/tests/ui/rfcs/rfc-2497-if-let-chains/ast-validate-guards.rs @@ -0,0 +1,23 @@ +#![feature(let_chains)] + +fn let_or_guard(x: Result<Option<i32>, ()>) { + match x { + Ok(opt) if let Some(4) = opt || false => {} + //~^ ERROR `let` expressions are not supported here + _ => {} + } +} + +fn hiding_unsafe_mod(x: Result<Option<i32>, ()>) { + match x { + Ok(opt) + if { + unsafe mod a {}; + //~^ ERROR module cannot be declared unsafe + false + } => {} + _ => {} + } +} + +fn main() {} diff --git a/tests/ui/rfcs/rfc-2497-if-let-chains/ast-validate-guards.stderr b/tests/ui/rfcs/rfc-2497-if-let-chains/ast-validate-guards.stderr new file mode 100644 index 000000000..26850998c --- /dev/null +++ b/tests/ui/rfcs/rfc-2497-if-let-chains/ast-validate-guards.stderr @@ -0,0 +1,21 @@ +error: `let` expressions are not supported here + --> $DIR/ast-validate-guards.rs:5:20 + | +LL | Ok(opt) if let Some(4) = opt || false => {} + | ^^^^^^^^^^^^^^^^^ + | + = note: only supported directly in conditions of `if` and `while` expressions +note: `||` operators are not supported in let chain expressions + --> $DIR/ast-validate-guards.rs:5:38 + | +LL | Ok(opt) if let Some(4) = opt || false => {} + | ^^ + +error: module cannot be declared unsafe + --> $DIR/ast-validate-guards.rs:15:17 + | +LL | unsafe mod a {}; + | ^^^^^^ + +error: aborting due to 2 previous errors + diff --git a/tests/ui/rfcs/rfc-2497-if-let-chains/chains-without-let.rs b/tests/ui/rfcs/rfc-2497-if-let-chains/chains-without-let.rs new file mode 100644 index 000000000..e0dded152 --- /dev/null +++ b/tests/ui/rfcs/rfc-2497-if-let-chains/chains-without-let.rs @@ -0,0 +1,20 @@ +fn and_chain() { + let z; + if true && { z = 3; true} && z == 3 {} + //~^ ERROR E0381 +} + +fn and_chain_2() { + let z; + true && { z = 3; true} && z == 3; + //~^ ERROR E0381 +} + +fn or_chain() { + let z; + if false || { z = 3; false} || z == 3 {} + //~^ ERROR E0381 +} + +fn main() { +} diff --git a/tests/ui/rfcs/rfc-2497-if-let-chains/chains-without-let.stderr b/tests/ui/rfcs/rfc-2497-if-let-chains/chains-without-let.stderr new file mode 100644 index 000000000..30d5a6779 --- /dev/null +++ b/tests/ui/rfcs/rfc-2497-if-let-chains/chains-without-let.stderr @@ -0,0 +1,33 @@ +error[E0381]: used binding `z` is possibly-uninitialized + --> $DIR/chains-without-let.rs:3:34 + | +LL | let z; + | - binding declared here but left uninitialized +LL | if true && { z = 3; true} && z == 3 {} + | ----- ^ `z` used here but it is possibly-uninitialized + | | + | binding initialized here in some conditions + +error[E0381]: used binding `z` is possibly-uninitialized + --> $DIR/chains-without-let.rs:9:31 + | +LL | let z; + | - binding declared here but left uninitialized +LL | true && { z = 3; true} && z == 3; + | ----- ^ `z` used here but it is possibly-uninitialized + | | + | binding initialized here in some conditions + +error[E0381]: used binding `z` is possibly-uninitialized + --> $DIR/chains-without-let.rs:15:36 + | +LL | let z; + | - binding declared here but left uninitialized +LL | if false || { z = 3; false} || z == 3 {} + | ----- ^ `z` used here but it is possibly-uninitialized + | | + | binding initialized here in some conditions + +error: aborting due to 3 previous errors + +For more information about this error, try `rustc --explain E0381`. diff --git a/tests/ui/rfcs/rfc-2497-if-let-chains/disallowed-positions.rs b/tests/ui/rfcs/rfc-2497-if-let-chains/disallowed-positions.rs new file mode 100644 index 000000000..2a9a5472b --- /dev/null +++ b/tests/ui/rfcs/rfc-2497-if-let-chains/disallowed-positions.rs @@ -0,0 +1,480 @@ +// Here we test that `lowering` behaves correctly wrt. `let $pats = $expr` expressions. +// +// We want to make sure that `let` is banned in situations other than: +// +// expr = +// | ... +// | "if" expr_with_let block {"else" block}? +// | {label ":"}? while" expr_with_let block +// ; +// +// expr_with_let = +// | "let" top_pats "=" expr +// | expr_with_let "&&" expr_with_let +// | "(" expr_with_let ")" +// | expr +// ; +// +// To that end, we check some positions which is not part of the language above. + +#![feature(let_chains)] // Avoid inflating `.stderr` with overzealous gates in this test. + +#![allow(irrefutable_let_patterns)] + +use std::ops::Range; + +fn main() {} + +fn _if() { + if (let 0 = 1) {} + //~^ ERROR `let` expressions are not supported here + //~| ERROR expected expression, found `let` statement + + if (((let 0 = 1))) {} + //~^ ERROR `let` expressions are not supported here + //~| ERROR expected expression, found `let` statement + + if (let 0 = 1) && true {} + //~^ ERROR `let` expressions are not supported here + //~| ERROR expected expression, found `let` statement + + if true && (let 0 = 1) {} + //~^ ERROR `let` expressions are not supported here + //~| ERROR expected expression, found `let` statement + + if (let 0 = 1) && (let 0 = 1) {} + //~^ ERROR `let` expressions are not supported here + //~| ERROR `let` expressions are not supported here + //~| ERROR expected expression, found `let` statement + //~| ERROR expected expression, found `let` statement + + if let 0 = 1 && let 1 = 2 && (let 2 = 3 && let 3 = 4 && let 4 = 5) {} + //~^ ERROR `let` expressions are not supported here + //~| ERROR `let` expressions are not supported here + //~| ERROR `let` expressions are not supported here + //~| ERROR expected expression, found `let` statement + //~| ERROR expected expression, found `let` statement + //~| ERROR expected expression, found `let` statement +} + +fn _while() { + while (let 0 = 1) {} + //~^ ERROR `let` expressions are not supported here + //~| ERROR expected expression, found `let` statement + + while (((let 0 = 1))) {} + //~^ ERROR `let` expressions are not supported here + //~| ERROR expected expression, found `let` statement + + while (let 0 = 1) && true {} + //~^ ERROR `let` expressions are not supported here + //~| ERROR expected expression, found `let` statement + + while true && (let 0 = 1) {} + //~^ ERROR `let` expressions are not supported here + //~| ERROR expected expression, found `let` statement + + while (let 0 = 1) && (let 0 = 1) {} + //~^ ERROR `let` expressions are not supported here + //~| ERROR `let` expressions are not supported here + //~| ERROR expected expression, found `let` statement + //~| ERROR expected expression, found `let` statement + + while let 0 = 1 && let 1 = 2 && (let 2 = 3 && let 3 = 4 && let 4 = 5) {} + //~^ ERROR `let` expressions are not supported here + //~| ERROR `let` expressions are not supported here + //~| ERROR `let` expressions are not supported here + //~| ERROR expected expression, found `let` statement + //~| ERROR expected expression, found `let` statement + //~| ERROR expected expression, found `let` statement +} + +fn _macros() { + macro_rules! use_expr { + ($e:expr) => { + if $e {} + while $e {} + } + } + use_expr!((let 0 = 1 && 0 == 0)); + //~^ ERROR `let` expressions are not supported here + //~| ERROR `let` expressions are not supported here + //~| ERROR expected expression, found `let` statement + use_expr!((let 0 = 1)); + //~^ ERROR `let` expressions are not supported here + //~| ERROR `let` expressions are not supported here + //~| ERROR expected expression, found `let` statement +} + +fn nested_within_if_expr() { + if &let 0 = 0 {} + //~^ ERROR `let` expressions are not supported here + //~| ERROR mismatched types + //~| ERROR expected expression, found `let` statement + + if !let 0 = 0 {} + //~^ ERROR `let` expressions are not supported here + //~| ERROR expected expression, found `let` statement + if *let 0 = 0 {} + //~^ ERROR `let` expressions are not supported here + //~| ERROR type `bool` cannot be dereferenced + //~| ERROR expected expression, found `let` statement + if -let 0 = 0 {} + //~^ ERROR `let` expressions are not supported here + //~| ERROR cannot apply unary operator `-` to type `bool` + //~| ERROR expected expression, found `let` statement + + fn _check_try_binds_tighter() -> Result<(), ()> { + if let 0 = 0? {} + //~^ ERROR the `?` operator can only be applied to values that implement `Try` + Ok(()) + } + if (let 0 = 0)? {} + //~^ ERROR `let` expressions are not supported here + //~| ERROR the `?` operator can only be applied to values that implement `Try` + //~| ERROR the `?` operator can only be used in a function that returns `Result` + //~| ERROR expected expression, found `let` statement + + if true || let 0 = 0 {} + //~^ ERROR `let` expressions are not supported here + //~| ERROR expected expression, found `let` statement + if (true || let 0 = 0) {} + //~^ ERROR `let` expressions are not supported here + //~| ERROR expected expression, found `let` statement + if true && (true || let 0 = 0) {} + //~^ ERROR `let` expressions are not supported here + //~| ERROR expected expression, found `let` statement + if true || (true && let 0 = 0) {} + //~^ ERROR `let` expressions are not supported here + //~| ERROR expected expression, found `let` statement + + let mut x = true; + if x = let 0 = 0 {} + //~^ ERROR `let` expressions are not supported here + //~| ERROR mismatched types + //~| ERROR expected expression, found `let` statement + + if true..(let 0 = 0) {} + //~^ ERROR `let` expressions are not supported here + //~| ERROR mismatched types + //~| ERROR expected expression, found `let` statement + if ..(let 0 = 0) {} + //~^ ERROR `let` expressions are not supported here + //~| ERROR mismatched types + //~| ERROR expected expression, found `let` statement + if (let 0 = 0).. {} + //~^ ERROR `let` expressions are not supported here + //~| ERROR mismatched types + //~| ERROR expected expression, found `let` statement + + // Binds as `(let ... = true)..true &&/|| false`. + if let Range { start: _, end: _ } = true..true && false {} + //~^ ERROR `let` expressions are not supported here + //~| ERROR mismatched types + //~| ERROR mismatched types + if let Range { start: _, end: _ } = true..true || false {} + //~^ ERROR `let` expressions are not supported here + //~| ERROR mismatched types + //~| ERROR mismatched types + + // Binds as `(let Range { start: F, end } = F)..(|| true)`. + const F: fn() -> bool = || true; + if let Range { start: F, end } = F..|| true {} + //~^ ERROR `let` expressions are not supported here + //~| ERROR mismatched types + //~| ERROR mismatched types + //~| ERROR mismatched types + + // Binds as `(let Range { start: true, end } = t)..(&&false)`. + let t = &&true; + if let Range { start: true, end } = t..&&false {} + //~^ ERROR `let` expressions are not supported here + //~| ERROR mismatched types + //~| ERROR mismatched types + //~| ERROR mismatched types + + if let true = let true = true {} + //~^ ERROR `let` expressions are not supported here + //~| ERROR expected expression, found `let` statement +} + +fn nested_within_while_expr() { + while &let 0 = 0 {} + //~^ ERROR `let` expressions are not supported here + //~| ERROR mismatched types + //~| ERROR expected expression, found `let` statement + + while !let 0 = 0 {} + //~^ ERROR `let` expressions are not supported here + //~| ERROR expected expression, found `let` statement + while *let 0 = 0 {} + //~^ ERROR `let` expressions are not supported here + //~| ERROR type `bool` cannot be dereferenced + //~| ERROR expected expression, found `let` statement + while -let 0 = 0 {} + //~^ ERROR `let` expressions are not supported here + //~| ERROR cannot apply unary operator `-` to type `bool` + //~| ERROR expected expression, found `let` statement + + fn _check_try_binds_tighter() -> Result<(), ()> { + while let 0 = 0? {} + //~^ ERROR the `?` operator can only be applied to values that implement `Try` + Ok(()) + } + while (let 0 = 0)? {} + //~^ ERROR `let` expressions are not supported here + //~| ERROR the `?` operator can only be applied to values that implement `Try` + //~| ERROR the `?` operator can only be used in a function that returns `Result` + //~| ERROR expected expression, found `let` statement + + while true || let 0 = 0 {} + //~^ ERROR `let` expressions are not supported here + //~| ERROR expected expression, found `let` statement + while (true || let 0 = 0) {} + //~^ ERROR `let` expressions are not supported here + //~| ERROR expected expression, found `let` statement + while true && (true || let 0 = 0) {} + //~^ ERROR `let` expressions are not supported here + //~| ERROR expected expression, found `let` statement + while true || (true && let 0 = 0) {} + //~^ ERROR `let` expressions are not supported here + //~| ERROR expected expression, found `let` statement + + let mut x = true; + while x = let 0 = 0 {} + //~^ ERROR `let` expressions are not supported here + //~| ERROR mismatched types + //~| ERROR expected expression, found `let` statement + + while true..(let 0 = 0) {} + //~^ ERROR `let` expressions are not supported here + //~| ERROR mismatched types + //~| ERROR expected expression, found `let` statement + while ..(let 0 = 0) {} + //~^ ERROR `let` expressions are not supported here + //~| ERROR mismatched types + //~| ERROR expected expression, found `let` statement + while (let 0 = 0).. {} + //~^ ERROR `let` expressions are not supported here + //~| ERROR mismatched types + //~| ERROR expected expression, found `let` statement + + // Binds as `(let ... = true)..true &&/|| false`. + while let Range { start: _, end: _ } = true..true && false {} + //~^ ERROR `let` expressions are not supported here + //~| ERROR mismatched types + //~| ERROR mismatched types + while let Range { start: _, end: _ } = true..true || false {} + //~^ ERROR `let` expressions are not supported here + //~| ERROR mismatched types + //~| ERROR mismatched types + + // Binds as `(let Range { start: F, end } = F)..(|| true)`. + const F: fn() -> bool = || true; + while let Range { start: F, end } = F..|| true {} + //~^ ERROR `let` expressions are not supported here + //~| ERROR mismatched types + //~| ERROR mismatched types + //~| ERROR mismatched types + + // Binds as `(let Range { start: true, end } = t)..(&&false)`. + let t = &&true; + while let Range { start: true, end } = t..&&false {} + //~^ ERROR `let` expressions are not supported here + //~| ERROR mismatched types + //~| ERROR mismatched types + //~| ERROR mismatched types + + while let true = let true = true {} + //~^ ERROR `let` expressions are not supported here + //~| ERROR expected expression, found `let` statement +} + +fn not_error_because_clarified_intent() { + if let Range { start: _, end: _ } = (true..true || false) { } + + if let Range { start: _, end: _ } = (true..true && false) { } + + while let Range { start: _, end: _ } = (true..true || false) { } + + while let Range { start: _, end: _ } = (true..true && false) { } +} + +fn outside_if_and_while_expr() { + &let 0 = 0; + //~^ ERROR `let` expressions are not supported here + //~| ERROR expected expression, found `let` statement + + !let 0 = 0; + //~^ ERROR `let` expressions are not supported here + //~| ERROR expected expression, found `let` statement + *let 0 = 0; + //~^ ERROR `let` expressions are not supported here + //~| ERROR type `bool` cannot be dereferenced + //~| ERROR expected expression, found `let` statement + -let 0 = 0; + //~^ ERROR `let` expressions are not supported here + //~| ERROR cannot apply unary operator `-` to type `bool` + //~| ERROR expected expression, found `let` statement + + fn _check_try_binds_tighter() -> Result<(), ()> { + let 0 = 0?; + //~^ ERROR the `?` operator can only be applied to values that implement `Try` + Ok(()) + } + (let 0 = 0)?; + //~^ ERROR `let` expressions are not supported here + //~| ERROR the `?` operator can only be used in a function that returns `Result` + //~| ERROR the `?` operator can only be applied to values that implement `Try` + //~| ERROR expected expression, found `let` statement + + true || let 0 = 0; + //~^ ERROR `let` expressions are not supported here + //~| ERROR expected expression, found `let` statement + (true || let 0 = 0); + //~^ ERROR `let` expressions are not supported here + //~| ERROR expected expression, found `let` statement + true && (true || let 0 = 0); + //~^ ERROR `let` expressions are not supported here + //~| ERROR expected expression, found `let` statement + + let mut x = true; + x = let 0 = 0; + //~^ ERROR `let` expressions are not supported here + //~| ERROR expected expression, found `let` statement + + true..(let 0 = 0); + //~^ ERROR `let` expressions are not supported here + //~| ERROR expected expression, found `let` statement + ..(let 0 = 0); + //~^ ERROR `let` expressions are not supported here + //~| ERROR expected expression, found `let` statement + (let 0 = 0)..; + //~^ ERROR `let` expressions are not supported here + //~| ERROR expected expression, found `let` statement + + (let Range { start: _, end: _ } = true..true || false); + //~^ ERROR `let` expressions are not supported here + //~| ERROR mismatched types + //~| ERROR expected expression, found `let` statement + + (let true = let true = true); + //~^ ERROR `let` expressions are not supported here + //~| ERROR expected expression, found `let` statement + //~| ERROR expected expression, found `let` statement + + { + #[cfg(FALSE)] + let x = true && let y = 1; + //~^ ERROR expected expression, found `let` statement + } + + #[cfg(FALSE)] + { + [1, 2, 3][let _ = ()] + //~^ ERROR expected expression, found `let` statement + } + + // Check function tail position. + &let 0 = 0 + //~^ ERROR `let` expressions are not supported here + //~| ERROR mismatched types + //~| ERROR expected expression, found `let` statement +} + +// Let's make sure that `let` inside const generic arguments are considered. +fn inside_const_generic_arguments() { + struct A<const B: bool>; + impl<const B: bool> A<{B}> { const O: u32 = 5; } + + if let A::<{ + true && let 1 = 1 + //~^ ERROR `let` expressions are not supported here + //~| ERROR expected expression, found `let` statement + }>::O = 5 {} + + while let A::<{ + true && let 1 = 1 + //~^ ERROR `let` expressions are not supported here + //~| ERROR expected expression, found `let` statement + }>::O = 5 {} + + if A::<{ + true && let 1 = 1 + //~^ ERROR `let` expressions are not supported here + //~| ERROR expected expression, found `let` statement + }>::O == 5 {} + + // In the cases above we have `ExprKind::Block` to help us out. + // Below however, we would not have a block and so an implementation might go + // from visiting expressions to types without banning `let` expressions down the tree. + // This tests ensures that we are not caught by surprise should the parser + // admit non-IDENT expressions in const generic arguments. + + if A::< + true && let 1 = 1 + //~^ ERROR `let` expressions are not supported here + //~| ERROR expressions must be enclosed in braces + //~| ERROR expected expression, found `let` statement + >::O == 5 {} +} + +fn with_parenthesis() { + let opt = Some(Some(1i32)); + + if (let Some(a) = opt && true) { + //~^ ERROR `let` expressions are not supported here + //~| ERROR expected expression, found `let` statement + } + + if (let Some(a) = opt) && true { + //~^ ERROR `let` expressions are not supported here + //~| ERROR expected expression, found `let` statement + } + if (let Some(a) = opt) && (let Some(b) = a) { + //~^ ERROR `let` expressions are not supported here + //~| ERROR `let` expressions are not supported here + //~| ERROR expected expression, found `let` statement + //~| ERROR expected expression, found `let` statement + } + if let Some(a) = opt && (true && true) { + } + + if (let Some(a) = opt && (let Some(b) = a)) && b == 1 { + //~^ ERROR `let` expressions are not supported here + //~| ERROR `let` expressions are not supported here + //~| ERROR expected expression, found `let` statement + //~| ERROR expected expression, found `let` statement + } + if (let Some(a) = opt && (let Some(b) = a)) && true { + //~^ ERROR `let` expressions are not supported here + //~| ERROR `let` expressions are not supported here + //~| ERROR expected expression, found `let` statement + //~| ERROR expected expression, found `let` statement + } + if (let Some(a) = opt && (true)) && true { + //~^ ERROR `let` expressions are not supported here + //~| ERROR expected expression, found `let` statement + } + + if (true && (true)) && let Some(a) = opt { + } + if (true) && let Some(a) = opt { + } + if true && let Some(a) = opt { + } + + let fun = || true; + if let true = (true && fun()) && (true) { + } + + #[cfg(FALSE)] + let x = (true && let y = 1); + //~^ ERROR expected expression, found `let` statement + + #[cfg(FALSE)] + { + ([1, 2, 3][let _ = ()]) + //~^ ERROR expected expression, found `let` statement + } +} diff --git a/tests/ui/rfcs/rfc-2497-if-let-chains/disallowed-positions.stderr b/tests/ui/rfcs/rfc-2497-if-let-chains/disallowed-positions.stderr new file mode 100644 index 000000000..81933173c --- /dev/null +++ b/tests/ui/rfcs/rfc-2497-if-let-chains/disallowed-positions.stderr @@ -0,0 +1,1911 @@ +error: expected expression, found `let` statement + --> $DIR/disallowed-positions.rs:29:9 + | +LL | if (let 0 = 1) {} + | ^^^ + +error: expected expression, found `let` statement + --> $DIR/disallowed-positions.rs:33:11 + | +LL | if (((let 0 = 1))) {} + | ^^^ + +error: expected expression, found `let` statement + --> $DIR/disallowed-positions.rs:37:9 + | +LL | if (let 0 = 1) && true {} + | ^^^ + +error: expected expression, found `let` statement + --> $DIR/disallowed-positions.rs:41:17 + | +LL | if true && (let 0 = 1) {} + | ^^^ + +error: expected expression, found `let` statement + --> $DIR/disallowed-positions.rs:45:9 + | +LL | if (let 0 = 1) && (let 0 = 1) {} + | ^^^ + +error: expected expression, found `let` statement + --> $DIR/disallowed-positions.rs:45:24 + | +LL | if (let 0 = 1) && (let 0 = 1) {} + | ^^^ + +error: expected expression, found `let` statement + --> $DIR/disallowed-positions.rs:51:35 + | +LL | if let 0 = 1 && let 1 = 2 && (let 2 = 3 && let 3 = 4 && let 4 = 5) {} + | ^^^ + +error: expected expression, found `let` statement + --> $DIR/disallowed-positions.rs:51:48 + | +LL | if let 0 = 1 && let 1 = 2 && (let 2 = 3 && let 3 = 4 && let 4 = 5) {} + | ^^^ + +error: expected expression, found `let` statement + --> $DIR/disallowed-positions.rs:51:61 + | +LL | if let 0 = 1 && let 1 = 2 && (let 2 = 3 && let 3 = 4 && let 4 = 5) {} + | ^^^ + +error: expected expression, found `let` statement + --> $DIR/disallowed-positions.rs:61:12 + | +LL | while (let 0 = 1) {} + | ^^^ + +error: expected expression, found `let` statement + --> $DIR/disallowed-positions.rs:65:14 + | +LL | while (((let 0 = 1))) {} + | ^^^ + +error: expected expression, found `let` statement + --> $DIR/disallowed-positions.rs:69:12 + | +LL | while (let 0 = 1) && true {} + | ^^^ + +error: expected expression, found `let` statement + --> $DIR/disallowed-positions.rs:73:20 + | +LL | while true && (let 0 = 1) {} + | ^^^ + +error: expected expression, found `let` statement + --> $DIR/disallowed-positions.rs:77:12 + | +LL | while (let 0 = 1) && (let 0 = 1) {} + | ^^^ + +error: expected expression, found `let` statement + --> $DIR/disallowed-positions.rs:77:27 + | +LL | while (let 0 = 1) && (let 0 = 1) {} + | ^^^ + +error: expected expression, found `let` statement + --> $DIR/disallowed-positions.rs:83:38 + | +LL | while let 0 = 1 && let 1 = 2 && (let 2 = 3 && let 3 = 4 && let 4 = 5) {} + | ^^^ + +error: expected expression, found `let` statement + --> $DIR/disallowed-positions.rs:83:51 + | +LL | while let 0 = 1 && let 1 = 2 && (let 2 = 3 && let 3 = 4 && let 4 = 5) {} + | ^^^ + +error: expected expression, found `let` statement + --> $DIR/disallowed-positions.rs:83:64 + | +LL | while let 0 = 1 && let 1 = 2 && (let 2 = 3 && let 3 = 4 && let 4 = 5) {} + | ^^^ + +error: expected expression, found `let` statement + --> $DIR/disallowed-positions.rs:110:9 + | +LL | if &let 0 = 0 {} + | ^^^ + +error: expected expression, found `let` statement + --> $DIR/disallowed-positions.rs:115:9 + | +LL | if !let 0 = 0 {} + | ^^^ + +error: expected expression, found `let` statement + --> $DIR/disallowed-positions.rs:118:9 + | +LL | if *let 0 = 0 {} + | ^^^ + +error: expected expression, found `let` statement + --> $DIR/disallowed-positions.rs:122:9 + | +LL | if -let 0 = 0 {} + | ^^^ + +error: expected expression, found `let` statement + --> $DIR/disallowed-positions.rs:132:9 + | +LL | if (let 0 = 0)? {} + | ^^^ + +error: expected expression, found `let` statement + --> $DIR/disallowed-positions.rs:138:16 + | +LL | if true || let 0 = 0 {} + | ^^^ + +error: expected expression, found `let` statement + --> $DIR/disallowed-positions.rs:141:17 + | +LL | if (true || let 0 = 0) {} + | ^^^ + +error: expected expression, found `let` statement + --> $DIR/disallowed-positions.rs:144:25 + | +LL | if true && (true || let 0 = 0) {} + | ^^^ + +error: expected expression, found `let` statement + --> $DIR/disallowed-positions.rs:147:25 + | +LL | if true || (true && let 0 = 0) {} + | ^^^ + +error: expected expression, found `let` statement + --> $DIR/disallowed-positions.rs:152:12 + | +LL | if x = let 0 = 0 {} + | ^^^ + +error: expected expression, found `let` statement + --> $DIR/disallowed-positions.rs:157:15 + | +LL | if true..(let 0 = 0) {} + | ^^^ + +error: expected expression, found `let` statement + --> $DIR/disallowed-positions.rs:161:11 + | +LL | if ..(let 0 = 0) {} + | ^^^ + +error: expected expression, found `let` statement + --> $DIR/disallowed-positions.rs:165:9 + | +LL | if (let 0 = 0).. {} + | ^^^ + +error: expected expression, found `let` statement + --> $DIR/disallowed-positions.rs:196:19 + | +LL | if let true = let true = true {} + | ^^^ + +error: expected expression, found `let` statement + --> $DIR/disallowed-positions.rs:202:12 + | +LL | while &let 0 = 0 {} + | ^^^ + +error: expected expression, found `let` statement + --> $DIR/disallowed-positions.rs:207:12 + | +LL | while !let 0 = 0 {} + | ^^^ + +error: expected expression, found `let` statement + --> $DIR/disallowed-positions.rs:210:12 + | +LL | while *let 0 = 0 {} + | ^^^ + +error: expected expression, found `let` statement + --> $DIR/disallowed-positions.rs:214:12 + | +LL | while -let 0 = 0 {} + | ^^^ + +error: expected expression, found `let` statement + --> $DIR/disallowed-positions.rs:224:12 + | +LL | while (let 0 = 0)? {} + | ^^^ + +error: expected expression, found `let` statement + --> $DIR/disallowed-positions.rs:230:19 + | +LL | while true || let 0 = 0 {} + | ^^^ + +error: expected expression, found `let` statement + --> $DIR/disallowed-positions.rs:233:20 + | +LL | while (true || let 0 = 0) {} + | ^^^ + +error: expected expression, found `let` statement + --> $DIR/disallowed-positions.rs:236:28 + | +LL | while true && (true || let 0 = 0) {} + | ^^^ + +error: expected expression, found `let` statement + --> $DIR/disallowed-positions.rs:239:28 + | +LL | while true || (true && let 0 = 0) {} + | ^^^ + +error: expected expression, found `let` statement + --> $DIR/disallowed-positions.rs:244:15 + | +LL | while x = let 0 = 0 {} + | ^^^ + +error: expected expression, found `let` statement + --> $DIR/disallowed-positions.rs:249:18 + | +LL | while true..(let 0 = 0) {} + | ^^^ + +error: expected expression, found `let` statement + --> $DIR/disallowed-positions.rs:253:14 + | +LL | while ..(let 0 = 0) {} + | ^^^ + +error: expected expression, found `let` statement + --> $DIR/disallowed-positions.rs:257:12 + | +LL | while (let 0 = 0).. {} + | ^^^ + +error: expected expression, found `let` statement + --> $DIR/disallowed-positions.rs:288:22 + | +LL | while let true = let true = true {} + | ^^^ + +error: expected expression, found `let` statement + --> $DIR/disallowed-positions.rs:304:6 + | +LL | &let 0 = 0; + | ^^^ + +error: expected expression, found `let` statement + --> $DIR/disallowed-positions.rs:308:6 + | +LL | !let 0 = 0; + | ^^^ + +error: expected expression, found `let` statement + --> $DIR/disallowed-positions.rs:311:6 + | +LL | *let 0 = 0; + | ^^^ + +error: expected expression, found `let` statement + --> $DIR/disallowed-positions.rs:315:6 + | +LL | -let 0 = 0; + | ^^^ + +error: expected expression, found `let` statement + --> $DIR/disallowed-positions.rs:325:6 + | +LL | (let 0 = 0)?; + | ^^^ + +error: expected expression, found `let` statement + --> $DIR/disallowed-positions.rs:331:13 + | +LL | true || let 0 = 0; + | ^^^ + +error: expected expression, found `let` statement + --> $DIR/disallowed-positions.rs:334:14 + | +LL | (true || let 0 = 0); + | ^^^ + +error: expected expression, found `let` statement + --> $DIR/disallowed-positions.rs:337:22 + | +LL | true && (true || let 0 = 0); + | ^^^ + +error: expected expression, found `let` statement + --> $DIR/disallowed-positions.rs:342:9 + | +LL | x = let 0 = 0; + | ^^^ + +error: expected expression, found `let` statement + --> $DIR/disallowed-positions.rs:346:12 + | +LL | true..(let 0 = 0); + | ^^^ + +error: expected expression, found `let` statement + --> $DIR/disallowed-positions.rs:349:8 + | +LL | ..(let 0 = 0); + | ^^^ + +error: expected expression, found `let` statement + --> $DIR/disallowed-positions.rs:352:6 + | +LL | (let 0 = 0)..; + | ^^^ + +error: expected expression, found `let` statement + --> $DIR/disallowed-positions.rs:356:6 + | +LL | (let Range { start: _, end: _ } = true..true || false); + | ^^^ + +error: expected expression, found `let` statement + --> $DIR/disallowed-positions.rs:361:6 + | +LL | (let true = let true = true); + | ^^^ + +error: expected expression, found `let` statement + --> $DIR/disallowed-positions.rs:361:17 + | +LL | (let true = let true = true); + | ^^^ + +error: expected expression, found `let` statement + --> $DIR/disallowed-positions.rs:368:25 + | +LL | let x = true && let y = 1; + | ^^^ + +error: expected expression, found `let` statement + --> $DIR/disallowed-positions.rs:374:19 + | +LL | [1, 2, 3][let _ = ()] + | ^^^ + +error: expected expression, found `let` statement + --> $DIR/disallowed-positions.rs:379:6 + | +LL | &let 0 = 0 + | ^^^ + +error: expected expression, found `let` statement + --> $DIR/disallowed-positions.rs:391:17 + | +LL | true && let 1 = 1 + | ^^^ + +error: expected expression, found `let` statement + --> $DIR/disallowed-positions.rs:397:17 + | +LL | true && let 1 = 1 + | ^^^ + +error: expected expression, found `let` statement + --> $DIR/disallowed-positions.rs:403:17 + | +LL | true && let 1 = 1 + | ^^^ + +error: expected expression, found `let` statement + --> $DIR/disallowed-positions.rs:415:17 + | +LL | true && let 1 = 1 + | ^^^ + +error: expressions must be enclosed in braces to be used as const generic arguments + --> $DIR/disallowed-positions.rs:415:9 + | +LL | true && let 1 = 1 + | ^^^^^^^^^^^^^^^^^ + | +help: enclose the `const` expression in braces + | +LL | { true && let 1 = 1 } + | + + + +error: expected expression, found `let` statement + --> $DIR/disallowed-positions.rs:425:9 + | +LL | if (let Some(a) = opt && true) { + | ^^^ + +error: expected expression, found `let` statement + --> $DIR/disallowed-positions.rs:430:9 + | +LL | if (let Some(a) = opt) && true { + | ^^^ + +error: expected expression, found `let` statement + --> $DIR/disallowed-positions.rs:434:9 + | +LL | if (let Some(a) = opt) && (let Some(b) = a) { + | ^^^ + +error: expected expression, found `let` statement + --> $DIR/disallowed-positions.rs:434:32 + | +LL | if (let Some(a) = opt) && (let Some(b) = a) { + | ^^^ + +error: expected expression, found `let` statement + --> $DIR/disallowed-positions.rs:443:9 + | +LL | if (let Some(a) = opt && (let Some(b) = a)) && b == 1 { + | ^^^ + +error: expected expression, found `let` statement + --> $DIR/disallowed-positions.rs:443:31 + | +LL | if (let Some(a) = opt && (let Some(b) = a)) && b == 1 { + | ^^^ + +error: expected expression, found `let` statement + --> $DIR/disallowed-positions.rs:449:9 + | +LL | if (let Some(a) = opt && (let Some(b) = a)) && true { + | ^^^ + +error: expected expression, found `let` statement + --> $DIR/disallowed-positions.rs:449:31 + | +LL | if (let Some(a) = opt && (let Some(b) = a)) && true { + | ^^^ + +error: expected expression, found `let` statement + --> $DIR/disallowed-positions.rs:455:9 + | +LL | if (let Some(a) = opt && (true)) && true { + | ^^^ + +error: expected expression, found `let` statement + --> $DIR/disallowed-positions.rs:472:22 + | +LL | let x = (true && let y = 1); + | ^^^ + +error: expected expression, found `let` statement + --> $DIR/disallowed-positions.rs:477:20 + | +LL | ([1, 2, 3][let _ = ()]) + | ^^^ + +error: expected expression, found `let` statement + --> $DIR/disallowed-positions.rs:99:16 + | +LL | use_expr!((let 0 = 1 && 0 == 0)); + | ^^^ + +error: expected expression, found `let` statement + --> $DIR/disallowed-positions.rs:103:16 + | +LL | use_expr!((let 0 = 1)); + | ^^^ + +error: `let` expressions are not supported here + --> $DIR/disallowed-positions.rs:29:9 + | +LL | if (let 0 = 1) {} + | ^^^^^^^^^ + | + = note: only supported directly in conditions of `if` and `while` expressions +note: `let`s wrapped in parentheses are not supported in a context with let chains + --> $DIR/disallowed-positions.rs:29:9 + | +LL | if (let 0 = 1) {} + | ^^^^^^^^^ + +error: `let` expressions are not supported here + --> $DIR/disallowed-positions.rs:33:11 + | +LL | if (((let 0 = 1))) {} + | ^^^^^^^^^ + | + = note: only supported directly in conditions of `if` and `while` expressions +note: `let`s wrapped in parentheses are not supported in a context with let chains + --> $DIR/disallowed-positions.rs:33:11 + | +LL | if (((let 0 = 1))) {} + | ^^^^^^^^^ + +error: `let` expressions are not supported here + --> $DIR/disallowed-positions.rs:37:9 + | +LL | if (let 0 = 1) && true {} + | ^^^^^^^^^ + | + = note: only supported directly in conditions of `if` and `while` expressions +note: `let`s wrapped in parentheses are not supported in a context with let chains + --> $DIR/disallowed-positions.rs:37:9 + | +LL | if (let 0 = 1) && true {} + | ^^^^^^^^^ + +error: `let` expressions are not supported here + --> $DIR/disallowed-positions.rs:41:17 + | +LL | if true && (let 0 = 1) {} + | ^^^^^^^^^ + | + = note: only supported directly in conditions of `if` and `while` expressions +note: `let`s wrapped in parentheses are not supported in a context with let chains + --> $DIR/disallowed-positions.rs:41:17 + | +LL | if true && (let 0 = 1) {} + | ^^^^^^^^^ + +error: `let` expressions are not supported here + --> $DIR/disallowed-positions.rs:45:9 + | +LL | if (let 0 = 1) && (let 0 = 1) {} + | ^^^^^^^^^ + | + = note: only supported directly in conditions of `if` and `while` expressions +note: `let`s wrapped in parentheses are not supported in a context with let chains + --> $DIR/disallowed-positions.rs:45:9 + | +LL | if (let 0 = 1) && (let 0 = 1) {} + | ^^^^^^^^^ + +error: `let` expressions are not supported here + --> $DIR/disallowed-positions.rs:45:24 + | +LL | if (let 0 = 1) && (let 0 = 1) {} + | ^^^^^^^^^ + | + = note: only supported directly in conditions of `if` and `while` expressions +note: `let`s wrapped in parentheses are not supported in a context with let chains + --> $DIR/disallowed-positions.rs:45:24 + | +LL | if (let 0 = 1) && (let 0 = 1) {} + | ^^^^^^^^^ + +error: `let` expressions are not supported here + --> $DIR/disallowed-positions.rs:51:35 + | +LL | if let 0 = 1 && let 1 = 2 && (let 2 = 3 && let 3 = 4 && let 4 = 5) {} + | ^^^^^^^^^ + | + = note: only supported directly in conditions of `if` and `while` expressions +note: `let`s wrapped in parentheses are not supported in a context with let chains + --> $DIR/disallowed-positions.rs:51:35 + | +LL | if let 0 = 1 && let 1 = 2 && (let 2 = 3 && let 3 = 4 && let 4 = 5) {} + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + +error: `let` expressions are not supported here + --> $DIR/disallowed-positions.rs:51:48 + | +LL | if let 0 = 1 && let 1 = 2 && (let 2 = 3 && let 3 = 4 && let 4 = 5) {} + | ^^^^^^^^^ + | + = note: only supported directly in conditions of `if` and `while` expressions +note: `let`s wrapped in parentheses are not supported in a context with let chains + --> $DIR/disallowed-positions.rs:51:35 + | +LL | if let 0 = 1 && let 1 = 2 && (let 2 = 3 && let 3 = 4 && let 4 = 5) {} + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + +error: `let` expressions are not supported here + --> $DIR/disallowed-positions.rs:51:61 + | +LL | if let 0 = 1 && let 1 = 2 && (let 2 = 3 && let 3 = 4 && let 4 = 5) {} + | ^^^^^^^^^ + | + = note: only supported directly in conditions of `if` and `while` expressions +note: `let`s wrapped in parentheses are not supported in a context with let chains + --> $DIR/disallowed-positions.rs:51:35 + | +LL | if let 0 = 1 && let 1 = 2 && (let 2 = 3 && let 3 = 4 && let 4 = 5) {} + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + +error: `let` expressions are not supported here + --> $DIR/disallowed-positions.rs:61:12 + | +LL | while (let 0 = 1) {} + | ^^^^^^^^^ + | + = note: only supported directly in conditions of `if` and `while` expressions +note: `let`s wrapped in parentheses are not supported in a context with let chains + --> $DIR/disallowed-positions.rs:61:12 + | +LL | while (let 0 = 1) {} + | ^^^^^^^^^ + +error: `let` expressions are not supported here + --> $DIR/disallowed-positions.rs:65:14 + | +LL | while (((let 0 = 1))) {} + | ^^^^^^^^^ + | + = note: only supported directly in conditions of `if` and `while` expressions +note: `let`s wrapped in parentheses are not supported in a context with let chains + --> $DIR/disallowed-positions.rs:65:14 + | +LL | while (((let 0 = 1))) {} + | ^^^^^^^^^ + +error: `let` expressions are not supported here + --> $DIR/disallowed-positions.rs:69:12 + | +LL | while (let 0 = 1) && true {} + | ^^^^^^^^^ + | + = note: only supported directly in conditions of `if` and `while` expressions +note: `let`s wrapped in parentheses are not supported in a context with let chains + --> $DIR/disallowed-positions.rs:69:12 + | +LL | while (let 0 = 1) && true {} + | ^^^^^^^^^ + +error: `let` expressions are not supported here + --> $DIR/disallowed-positions.rs:73:20 + | +LL | while true && (let 0 = 1) {} + | ^^^^^^^^^ + | + = note: only supported directly in conditions of `if` and `while` expressions +note: `let`s wrapped in parentheses are not supported in a context with let chains + --> $DIR/disallowed-positions.rs:73:20 + | +LL | while true && (let 0 = 1) {} + | ^^^^^^^^^ + +error: `let` expressions are not supported here + --> $DIR/disallowed-positions.rs:77:12 + | +LL | while (let 0 = 1) && (let 0 = 1) {} + | ^^^^^^^^^ + | + = note: only supported directly in conditions of `if` and `while` expressions +note: `let`s wrapped in parentheses are not supported in a context with let chains + --> $DIR/disallowed-positions.rs:77:12 + | +LL | while (let 0 = 1) && (let 0 = 1) {} + | ^^^^^^^^^ + +error: `let` expressions are not supported here + --> $DIR/disallowed-positions.rs:77:27 + | +LL | while (let 0 = 1) && (let 0 = 1) {} + | ^^^^^^^^^ + | + = note: only supported directly in conditions of `if` and `while` expressions +note: `let`s wrapped in parentheses are not supported in a context with let chains + --> $DIR/disallowed-positions.rs:77:27 + | +LL | while (let 0 = 1) && (let 0 = 1) {} + | ^^^^^^^^^ + +error: `let` expressions are not supported here + --> $DIR/disallowed-positions.rs:83:38 + | +LL | while let 0 = 1 && let 1 = 2 && (let 2 = 3 && let 3 = 4 && let 4 = 5) {} + | ^^^^^^^^^ + | + = note: only supported directly in conditions of `if` and `while` expressions +note: `let`s wrapped in parentheses are not supported in a context with let chains + --> $DIR/disallowed-positions.rs:83:38 + | +LL | while let 0 = 1 && let 1 = 2 && (let 2 = 3 && let 3 = 4 && let 4 = 5) {} + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + +error: `let` expressions are not supported here + --> $DIR/disallowed-positions.rs:83:51 + | +LL | while let 0 = 1 && let 1 = 2 && (let 2 = 3 && let 3 = 4 && let 4 = 5) {} + | ^^^^^^^^^ + | + = note: only supported directly in conditions of `if` and `while` expressions +note: `let`s wrapped in parentheses are not supported in a context with let chains + --> $DIR/disallowed-positions.rs:83:38 + | +LL | while let 0 = 1 && let 1 = 2 && (let 2 = 3 && let 3 = 4 && let 4 = 5) {} + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + +error: `let` expressions are not supported here + --> $DIR/disallowed-positions.rs:83:64 + | +LL | while let 0 = 1 && let 1 = 2 && (let 2 = 3 && let 3 = 4 && let 4 = 5) {} + | ^^^^^^^^^ + | + = note: only supported directly in conditions of `if` and `while` expressions +note: `let`s wrapped in parentheses are not supported in a context with let chains + --> $DIR/disallowed-positions.rs:83:38 + | +LL | while let 0 = 1 && let 1 = 2 && (let 2 = 3 && let 3 = 4 && let 4 = 5) {} + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + +error: `let` expressions are not supported here + --> $DIR/disallowed-positions.rs:99:16 + | +LL | use_expr!((let 0 = 1 && 0 == 0)); + | ^^^^^^^^^ + | + = note: only supported directly in conditions of `if` and `while` expressions +note: `let`s wrapped in parentheses are not supported in a context with let chains + --> $DIR/disallowed-positions.rs:99:16 + | +LL | use_expr!((let 0 = 1 && 0 == 0)); + | ^^^^^^^^^^^^^^^^^^^ + +error: `let` expressions are not supported here + --> $DIR/disallowed-positions.rs:99:16 + | +LL | use_expr!((let 0 = 1 && 0 == 0)); + | ^^^^^^^^^ + | + = note: only supported directly in conditions of `if` and `while` expressions +note: `let`s wrapped in parentheses are not supported in a context with let chains + --> $DIR/disallowed-positions.rs:99:16 + | +LL | use_expr!((let 0 = 1 && 0 == 0)); + | ^^^^^^^^^^^^^^^^^^^ + +error: `let` expressions are not supported here + --> $DIR/disallowed-positions.rs:103:16 + | +LL | use_expr!((let 0 = 1)); + | ^^^^^^^^^ + | + = note: only supported directly in conditions of `if` and `while` expressions +note: `let`s wrapped in parentheses are not supported in a context with let chains + --> $DIR/disallowed-positions.rs:103:16 + | +LL | use_expr!((let 0 = 1)); + | ^^^^^^^^^ + +error: `let` expressions are not supported here + --> $DIR/disallowed-positions.rs:103:16 + | +LL | use_expr!((let 0 = 1)); + | ^^^^^^^^^ + | + = note: only supported directly in conditions of `if` and `while` expressions +note: `let`s wrapped in parentheses are not supported in a context with let chains + --> $DIR/disallowed-positions.rs:103:16 + | +LL | use_expr!((let 0 = 1)); + | ^^^^^^^^^ + +error: `let` expressions are not supported here + --> $DIR/disallowed-positions.rs:110:9 + | +LL | if &let 0 = 0 {} + | ^^^^^^^^^ + | + = note: only supported directly in conditions of `if` and `while` expressions + +error: `let` expressions are not supported here + --> $DIR/disallowed-positions.rs:115:9 + | +LL | if !let 0 = 0 {} + | ^^^^^^^^^ + | + = note: only supported directly in conditions of `if` and `while` expressions + +error: `let` expressions are not supported here + --> $DIR/disallowed-positions.rs:118:9 + | +LL | if *let 0 = 0 {} + | ^^^^^^^^^ + | + = note: only supported directly in conditions of `if` and `while` expressions + +error: `let` expressions are not supported here + --> $DIR/disallowed-positions.rs:122:9 + | +LL | if -let 0 = 0 {} + | ^^^^^^^^^ + | + = note: only supported directly in conditions of `if` and `while` expressions + +error: `let` expressions are not supported here + --> $DIR/disallowed-positions.rs:132:9 + | +LL | if (let 0 = 0)? {} + | ^^^^^^^^^ + | + = note: only supported directly in conditions of `if` and `while` expressions +note: `let`s wrapped in parentheses are not supported in a context with let chains + --> $DIR/disallowed-positions.rs:132:9 + | +LL | if (let 0 = 0)? {} + | ^^^^^^^^^ + +error: `let` expressions are not supported here + --> $DIR/disallowed-positions.rs:138:16 + | +LL | if true || let 0 = 0 {} + | ^^^^^^^^^ + | + = note: only supported directly in conditions of `if` and `while` expressions +note: `||` operators are not supported in let chain expressions + --> $DIR/disallowed-positions.rs:138:13 + | +LL | if true || let 0 = 0 {} + | ^^ + +error: `let` expressions are not supported here + --> $DIR/disallowed-positions.rs:141:17 + | +LL | if (true || let 0 = 0) {} + | ^^^^^^^^^ + | + = note: only supported directly in conditions of `if` and `while` expressions +note: `||` operators are not supported in let chain expressions + --> $DIR/disallowed-positions.rs:141:14 + | +LL | if (true || let 0 = 0) {} + | ^^ + +error: `let` expressions are not supported here + --> $DIR/disallowed-positions.rs:144:25 + | +LL | if true && (true || let 0 = 0) {} + | ^^^^^^^^^ + | + = note: only supported directly in conditions of `if` and `while` expressions +note: `||` operators are not supported in let chain expressions + --> $DIR/disallowed-positions.rs:144:22 + | +LL | if true && (true || let 0 = 0) {} + | ^^ + +error: `let` expressions are not supported here + --> $DIR/disallowed-positions.rs:147:25 + | +LL | if true || (true && let 0 = 0) {} + | ^^^^^^^^^ + | + = note: only supported directly in conditions of `if` and `while` expressions +note: `let`s wrapped in parentheses are not supported in a context with let chains + --> $DIR/disallowed-positions.rs:147:17 + | +LL | if true || (true && let 0 = 0) {} + | ^^^^^^^^^^^^^^^^^ + +error: `let` expressions are not supported here + --> $DIR/disallowed-positions.rs:152:12 + | +LL | if x = let 0 = 0 {} + | ^^^^^^^^^ + | + = note: only supported directly in conditions of `if` and `while` expressions + +error: `let` expressions are not supported here + --> $DIR/disallowed-positions.rs:157:15 + | +LL | if true..(let 0 = 0) {} + | ^^^^^^^^^ + | + = note: only supported directly in conditions of `if` and `while` expressions +note: `let`s wrapped in parentheses are not supported in a context with let chains + --> $DIR/disallowed-positions.rs:157:15 + | +LL | if true..(let 0 = 0) {} + | ^^^^^^^^^ + +error: `let` expressions are not supported here + --> $DIR/disallowed-positions.rs:161:11 + | +LL | if ..(let 0 = 0) {} + | ^^^^^^^^^ + | + = note: only supported directly in conditions of `if` and `while` expressions +note: `let`s wrapped in parentheses are not supported in a context with let chains + --> $DIR/disallowed-positions.rs:161:11 + | +LL | if ..(let 0 = 0) {} + | ^^^^^^^^^ + +error: `let` expressions are not supported here + --> $DIR/disallowed-positions.rs:165:9 + | +LL | if (let 0 = 0).. {} + | ^^^^^^^^^ + | + = note: only supported directly in conditions of `if` and `while` expressions +note: `let`s wrapped in parentheses are not supported in a context with let chains + --> $DIR/disallowed-positions.rs:165:9 + | +LL | if (let 0 = 0).. {} + | ^^^^^^^^^ + +error: `let` expressions are not supported here + --> $DIR/disallowed-positions.rs:171:8 + | +LL | if let Range { start: _, end: _ } = true..true && false {} + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + | + = note: only supported directly in conditions of `if` and `while` expressions + +error: `let` expressions are not supported here + --> $DIR/disallowed-positions.rs:175:8 + | +LL | if let Range { start: _, end: _ } = true..true || false {} + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + | + = note: only supported directly in conditions of `if` and `while` expressions + +error: `let` expressions are not supported here + --> $DIR/disallowed-positions.rs:182:8 + | +LL | if let Range { start: F, end } = F..|| true {} + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + | + = note: only supported directly in conditions of `if` and `while` expressions + +error: `let` expressions are not supported here + --> $DIR/disallowed-positions.rs:190:8 + | +LL | if let Range { start: true, end } = t..&&false {} + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + | + = note: only supported directly in conditions of `if` and `while` expressions + +error: `let` expressions are not supported here + --> $DIR/disallowed-positions.rs:196:19 + | +LL | if let true = let true = true {} + | ^^^^^^^^^^^^^^^ + | + = note: only supported directly in conditions of `if` and `while` expressions + +error: `let` expressions are not supported here + --> $DIR/disallowed-positions.rs:202:12 + | +LL | while &let 0 = 0 {} + | ^^^^^^^^^ + | + = note: only supported directly in conditions of `if` and `while` expressions + +error: `let` expressions are not supported here + --> $DIR/disallowed-positions.rs:207:12 + | +LL | while !let 0 = 0 {} + | ^^^^^^^^^ + | + = note: only supported directly in conditions of `if` and `while` expressions + +error: `let` expressions are not supported here + --> $DIR/disallowed-positions.rs:210:12 + | +LL | while *let 0 = 0 {} + | ^^^^^^^^^ + | + = note: only supported directly in conditions of `if` and `while` expressions + +error: `let` expressions are not supported here + --> $DIR/disallowed-positions.rs:214:12 + | +LL | while -let 0 = 0 {} + | ^^^^^^^^^ + | + = note: only supported directly in conditions of `if` and `while` expressions + +error: `let` expressions are not supported here + --> $DIR/disallowed-positions.rs:224:12 + | +LL | while (let 0 = 0)? {} + | ^^^^^^^^^ + | + = note: only supported directly in conditions of `if` and `while` expressions +note: `let`s wrapped in parentheses are not supported in a context with let chains + --> $DIR/disallowed-positions.rs:224:12 + | +LL | while (let 0 = 0)? {} + | ^^^^^^^^^ + +error: `let` expressions are not supported here + --> $DIR/disallowed-positions.rs:230:19 + | +LL | while true || let 0 = 0 {} + | ^^^^^^^^^ + | + = note: only supported directly in conditions of `if` and `while` expressions +note: `||` operators are not supported in let chain expressions + --> $DIR/disallowed-positions.rs:230:16 + | +LL | while true || let 0 = 0 {} + | ^^ + +error: `let` expressions are not supported here + --> $DIR/disallowed-positions.rs:233:20 + | +LL | while (true || let 0 = 0) {} + | ^^^^^^^^^ + | + = note: only supported directly in conditions of `if` and `while` expressions +note: `||` operators are not supported in let chain expressions + --> $DIR/disallowed-positions.rs:233:17 + | +LL | while (true || let 0 = 0) {} + | ^^ + +error: `let` expressions are not supported here + --> $DIR/disallowed-positions.rs:236:28 + | +LL | while true && (true || let 0 = 0) {} + | ^^^^^^^^^ + | + = note: only supported directly in conditions of `if` and `while` expressions +note: `||` operators are not supported in let chain expressions + --> $DIR/disallowed-positions.rs:236:25 + | +LL | while true && (true || let 0 = 0) {} + | ^^ + +error: `let` expressions are not supported here + --> $DIR/disallowed-positions.rs:239:28 + | +LL | while true || (true && let 0 = 0) {} + | ^^^^^^^^^ + | + = note: only supported directly in conditions of `if` and `while` expressions +note: `let`s wrapped in parentheses are not supported in a context with let chains + --> $DIR/disallowed-positions.rs:239:20 + | +LL | while true || (true && let 0 = 0) {} + | ^^^^^^^^^^^^^^^^^ + +error: `let` expressions are not supported here + --> $DIR/disallowed-positions.rs:244:15 + | +LL | while x = let 0 = 0 {} + | ^^^^^^^^^ + | + = note: only supported directly in conditions of `if` and `while` expressions + +error: `let` expressions are not supported here + --> $DIR/disallowed-positions.rs:249:18 + | +LL | while true..(let 0 = 0) {} + | ^^^^^^^^^ + | + = note: only supported directly in conditions of `if` and `while` expressions +note: `let`s wrapped in parentheses are not supported in a context with let chains + --> $DIR/disallowed-positions.rs:249:18 + | +LL | while true..(let 0 = 0) {} + | ^^^^^^^^^ + +error: `let` expressions are not supported here + --> $DIR/disallowed-positions.rs:253:14 + | +LL | while ..(let 0 = 0) {} + | ^^^^^^^^^ + | + = note: only supported directly in conditions of `if` and `while` expressions +note: `let`s wrapped in parentheses are not supported in a context with let chains + --> $DIR/disallowed-positions.rs:253:14 + | +LL | while ..(let 0 = 0) {} + | ^^^^^^^^^ + +error: `let` expressions are not supported here + --> $DIR/disallowed-positions.rs:257:12 + | +LL | while (let 0 = 0).. {} + | ^^^^^^^^^ + | + = note: only supported directly in conditions of `if` and `while` expressions +note: `let`s wrapped in parentheses are not supported in a context with let chains + --> $DIR/disallowed-positions.rs:257:12 + | +LL | while (let 0 = 0).. {} + | ^^^^^^^^^ + +error: `let` expressions are not supported here + --> $DIR/disallowed-positions.rs:263:11 + | +LL | while let Range { start: _, end: _ } = true..true && false {} + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + | + = note: only supported directly in conditions of `if` and `while` expressions + +error: `let` expressions are not supported here + --> $DIR/disallowed-positions.rs:267:11 + | +LL | while let Range { start: _, end: _ } = true..true || false {} + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + | + = note: only supported directly in conditions of `if` and `while` expressions + +error: `let` expressions are not supported here + --> $DIR/disallowed-positions.rs:274:11 + | +LL | while let Range { start: F, end } = F..|| true {} + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + | + = note: only supported directly in conditions of `if` and `while` expressions + +error: `let` expressions are not supported here + --> $DIR/disallowed-positions.rs:282:11 + | +LL | while let Range { start: true, end } = t..&&false {} + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + | + = note: only supported directly in conditions of `if` and `while` expressions + +error: `let` expressions are not supported here + --> $DIR/disallowed-positions.rs:288:22 + | +LL | while let true = let true = true {} + | ^^^^^^^^^^^^^^^ + | + = note: only supported directly in conditions of `if` and `while` expressions + +error: `let` expressions are not supported here + --> $DIR/disallowed-positions.rs:304:6 + | +LL | &let 0 = 0; + | ^^^^^^^^^ + | + = note: only supported directly in conditions of `if` and `while` expressions + +error: `let` expressions are not supported here + --> $DIR/disallowed-positions.rs:308:6 + | +LL | !let 0 = 0; + | ^^^^^^^^^ + | + = note: only supported directly in conditions of `if` and `while` expressions + +error: `let` expressions are not supported here + --> $DIR/disallowed-positions.rs:311:6 + | +LL | *let 0 = 0; + | ^^^^^^^^^ + | + = note: only supported directly in conditions of `if` and `while` expressions + +error: `let` expressions are not supported here + --> $DIR/disallowed-positions.rs:315:6 + | +LL | -let 0 = 0; + | ^^^^^^^^^ + | + = note: only supported directly in conditions of `if` and `while` expressions + +error: `let` expressions are not supported here + --> $DIR/disallowed-positions.rs:325:6 + | +LL | (let 0 = 0)?; + | ^^^^^^^^^ + | + = note: only supported directly in conditions of `if` and `while` expressions +note: `let`s wrapped in parentheses are not supported in a context with let chains + --> $DIR/disallowed-positions.rs:325:6 + | +LL | (let 0 = 0)?; + | ^^^^^^^^^ + +error: `let` expressions are not supported here + --> $DIR/disallowed-positions.rs:331:13 + | +LL | true || let 0 = 0; + | ^^^^^^^^^ + | + = note: only supported directly in conditions of `if` and `while` expressions +note: `||` operators are not supported in let chain expressions + --> $DIR/disallowed-positions.rs:331:10 + | +LL | true || let 0 = 0; + | ^^ + +error: `let` expressions are not supported here + --> $DIR/disallowed-positions.rs:334:14 + | +LL | (true || let 0 = 0); + | ^^^^^^^^^ + | + = note: only supported directly in conditions of `if` and `while` expressions +note: `||` operators are not supported in let chain expressions + --> $DIR/disallowed-positions.rs:334:11 + | +LL | (true || let 0 = 0); + | ^^ + +error: `let` expressions are not supported here + --> $DIR/disallowed-positions.rs:337:22 + | +LL | true && (true || let 0 = 0); + | ^^^^^^^^^ + | + = note: only supported directly in conditions of `if` and `while` expressions +note: `||` operators are not supported in let chain expressions + --> $DIR/disallowed-positions.rs:337:19 + | +LL | true && (true || let 0 = 0); + | ^^ + +error: `let` expressions are not supported here + --> $DIR/disallowed-positions.rs:342:9 + | +LL | x = let 0 = 0; + | ^^^^^^^^^ + | + = note: only supported directly in conditions of `if` and `while` expressions + +error: `let` expressions are not supported here + --> $DIR/disallowed-positions.rs:346:12 + | +LL | true..(let 0 = 0); + | ^^^^^^^^^ + | + = note: only supported directly in conditions of `if` and `while` expressions +note: `let`s wrapped in parentheses are not supported in a context with let chains + --> $DIR/disallowed-positions.rs:346:12 + | +LL | true..(let 0 = 0); + | ^^^^^^^^^ + +error: `let` expressions are not supported here + --> $DIR/disallowed-positions.rs:349:8 + | +LL | ..(let 0 = 0); + | ^^^^^^^^^ + | + = note: only supported directly in conditions of `if` and `while` expressions +note: `let`s wrapped in parentheses are not supported in a context with let chains + --> $DIR/disallowed-positions.rs:349:8 + | +LL | ..(let 0 = 0); + | ^^^^^^^^^ + +error: `let` expressions are not supported here + --> $DIR/disallowed-positions.rs:352:6 + | +LL | (let 0 = 0)..; + | ^^^^^^^^^ + | + = note: only supported directly in conditions of `if` and `while` expressions +note: `let`s wrapped in parentheses are not supported in a context with let chains + --> $DIR/disallowed-positions.rs:352:6 + | +LL | (let 0 = 0)..; + | ^^^^^^^^^ + +error: `let` expressions are not supported here + --> $DIR/disallowed-positions.rs:356:6 + | +LL | (let Range { start: _, end: _ } = true..true || false); + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + | + = note: only supported directly in conditions of `if` and `while` expressions + +error: `let` expressions are not supported here + --> $DIR/disallowed-positions.rs:361:6 + | +LL | (let true = let true = true); + | ^^^^^^^^^^^^^^^^^^^^^^^^^^ + | + = note: only supported directly in conditions of `if` and `while` expressions +note: `let`s wrapped in parentheses are not supported in a context with let chains + --> $DIR/disallowed-positions.rs:361:6 + | +LL | (let true = let true = true); + | ^^^^^^^^^^^^^^^^^^^^^^^^^^ + +error: `let` expressions are not supported here + --> $DIR/disallowed-positions.rs:379:6 + | +LL | &let 0 = 0 + | ^^^^^^^^^ + | + = note: only supported directly in conditions of `if` and `while` expressions + +error: `let` expressions are not supported here + --> $DIR/disallowed-positions.rs:391:17 + | +LL | true && let 1 = 1 + | ^^^^^^^^^ + | + = note: only supported directly in conditions of `if` and `while` expressions + +error: `let` expressions are not supported here + --> $DIR/disallowed-positions.rs:397:17 + | +LL | true && let 1 = 1 + | ^^^^^^^^^ + | + = note: only supported directly in conditions of `if` and `while` expressions + +error: `let` expressions are not supported here + --> $DIR/disallowed-positions.rs:403:17 + | +LL | true && let 1 = 1 + | ^^^^^^^^^ + | + = note: only supported directly in conditions of `if` and `while` expressions + +error: `let` expressions are not supported here + --> $DIR/disallowed-positions.rs:415:17 + | +LL | true && let 1 = 1 + | ^^^^^^^^^ + | + = note: only supported directly in conditions of `if` and `while` expressions + +error: `let` expressions are not supported here + --> $DIR/disallowed-positions.rs:425:9 + | +LL | if (let Some(a) = opt && true) { + | ^^^^^^^^^^^^^^^^^ + | + = note: only supported directly in conditions of `if` and `while` expressions +note: `let`s wrapped in parentheses are not supported in a context with let chains + --> $DIR/disallowed-positions.rs:425:9 + | +LL | if (let Some(a) = opt && true) { + | ^^^^^^^^^^^^^^^^^^^^^^^^^ + +error: `let` expressions are not supported here + --> $DIR/disallowed-positions.rs:430:9 + | +LL | if (let Some(a) = opt) && true { + | ^^^^^^^^^^^^^^^^^ + | + = note: only supported directly in conditions of `if` and `while` expressions +note: `let`s wrapped in parentheses are not supported in a context with let chains + --> $DIR/disallowed-positions.rs:430:9 + | +LL | if (let Some(a) = opt) && true { + | ^^^^^^^^^^^^^^^^^ + +error: `let` expressions are not supported here + --> $DIR/disallowed-positions.rs:434:9 + | +LL | if (let Some(a) = opt) && (let Some(b) = a) { + | ^^^^^^^^^^^^^^^^^ + | + = note: only supported directly in conditions of `if` and `while` expressions +note: `let`s wrapped in parentheses are not supported in a context with let chains + --> $DIR/disallowed-positions.rs:434:9 + | +LL | if (let Some(a) = opt) && (let Some(b) = a) { + | ^^^^^^^^^^^^^^^^^ + +error: `let` expressions are not supported here + --> $DIR/disallowed-positions.rs:434:32 + | +LL | if (let Some(a) = opt) && (let Some(b) = a) { + | ^^^^^^^^^^^^^^^ + | + = note: only supported directly in conditions of `if` and `while` expressions +note: `let`s wrapped in parentheses are not supported in a context with let chains + --> $DIR/disallowed-positions.rs:434:32 + | +LL | if (let Some(a) = opt) && (let Some(b) = a) { + | ^^^^^^^^^^^^^^^ + +error: `let` expressions are not supported here + --> $DIR/disallowed-positions.rs:443:9 + | +LL | if (let Some(a) = opt && (let Some(b) = a)) && b == 1 { + | ^^^^^^^^^^^^^^^^^ + | + = note: only supported directly in conditions of `if` and `while` expressions +note: `let`s wrapped in parentheses are not supported in a context with let chains + --> $DIR/disallowed-positions.rs:443:9 + | +LL | if (let Some(a) = opt && (let Some(b) = a)) && b == 1 { + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + +error: `let` expressions are not supported here + --> $DIR/disallowed-positions.rs:443:31 + | +LL | if (let Some(a) = opt && (let Some(b) = a)) && b == 1 { + | ^^^^^^^^^^^^^^^ + | + = note: only supported directly in conditions of `if` and `while` expressions +note: `let`s wrapped in parentheses are not supported in a context with let chains + --> $DIR/disallowed-positions.rs:443:31 + | +LL | if (let Some(a) = opt && (let Some(b) = a)) && b == 1 { + | ^^^^^^^^^^^^^^^ + +error: `let` expressions are not supported here + --> $DIR/disallowed-positions.rs:449:9 + | +LL | if (let Some(a) = opt && (let Some(b) = a)) && true { + | ^^^^^^^^^^^^^^^^^ + | + = note: only supported directly in conditions of `if` and `while` expressions +note: `let`s wrapped in parentheses are not supported in a context with let chains + --> $DIR/disallowed-positions.rs:449:9 + | +LL | if (let Some(a) = opt && (let Some(b) = a)) && true { + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + +error: `let` expressions are not supported here + --> $DIR/disallowed-positions.rs:449:31 + | +LL | if (let Some(a) = opt && (let Some(b) = a)) && true { + | ^^^^^^^^^^^^^^^ + | + = note: only supported directly in conditions of `if` and `while` expressions +note: `let`s wrapped in parentheses are not supported in a context with let chains + --> $DIR/disallowed-positions.rs:449:31 + | +LL | if (let Some(a) = opt && (let Some(b) = a)) && true { + | ^^^^^^^^^^^^^^^ + +error: `let` expressions are not supported here + --> $DIR/disallowed-positions.rs:455:9 + | +LL | if (let Some(a) = opt && (true)) && true { + | ^^^^^^^^^^^^^^^^^ + | + = note: only supported directly in conditions of `if` and `while` expressions +note: `let`s wrapped in parentheses are not supported in a context with let chains + --> $DIR/disallowed-positions.rs:455:9 + | +LL | if (let Some(a) = opt && (true)) && true { + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^ + +error[E0308]: mismatched types + --> $DIR/disallowed-positions.rs:110:8 + | +LL | if &let 0 = 0 {} + | ^^^^^^^^^^ expected `bool`, found `&bool` + | +help: consider removing the borrow + | +LL - if &let 0 = 0 {} +LL + if let 0 = 0 {} + | + +error[E0614]: type `bool` cannot be dereferenced + --> $DIR/disallowed-positions.rs:118:8 + | +LL | if *let 0 = 0 {} + | ^^^^^^^^^^ + +error[E0600]: cannot apply unary operator `-` to type `bool` + --> $DIR/disallowed-positions.rs:122:8 + | +LL | if -let 0 = 0 {} + | ^^^^^^^^^^ cannot apply unary operator `-` + +error[E0277]: the `?` operator can only be applied to values that implement `Try` + --> $DIR/disallowed-positions.rs:132:8 + | +LL | if (let 0 = 0)? {} + | ^^^^^^^^^^^^ the `?` operator cannot be applied to type `bool` + | + = help: the trait `Try` is not implemented for `bool` + +error[E0277]: the `?` operator can only be used in a function that returns `Result` or `Option` (or another type that implements `FromResidual`) + --> $DIR/disallowed-positions.rs:132:19 + | +LL | fn nested_within_if_expr() { + | -------------------------- this function should return `Result` or `Option` to accept `?` +... +LL | if (let 0 = 0)? {} + | ^ cannot use the `?` operator in a function that returns `()` + | + = help: the trait `FromResidual<_>` is not implemented for `()` + +error[E0308]: mismatched types + --> $DIR/disallowed-positions.rs:152:8 + | +LL | if x = let 0 = 0 {} + | ^^^^^^^^^^^^^ expected `bool`, found `()` + | +help: you might have meant to compare for equality + | +LL | if x == let 0 = 0 {} + | + + +error[E0308]: mismatched types + --> $DIR/disallowed-positions.rs:157:8 + | +LL | if true..(let 0 = 0) {} + | ^^^^^^^^^^^^^^^^^ expected `bool`, found `Range<bool>` + | + = note: expected type `bool` + found struct `std::ops::Range<bool>` + +error[E0308]: mismatched types + --> $DIR/disallowed-positions.rs:161:8 + | +LL | if ..(let 0 = 0) {} + | ^^^^^^^^^^^^^ expected `bool`, found `RangeTo<bool>` + | + = note: expected type `bool` + found struct `RangeTo<bool>` + +error[E0308]: mismatched types + --> $DIR/disallowed-positions.rs:165:8 + | +LL | if (let 0 = 0).. {} + | ^^^^^^^^^^^^^ expected `bool`, found `RangeFrom<bool>` + | + = note: expected type `bool` + found struct `RangeFrom<bool>` + +error[E0308]: mismatched types + --> $DIR/disallowed-positions.rs:171:12 + | +LL | if let Range { start: _, end: _ } = true..true && false {} + | ^^^^^^^^^^^^^^^^^^^^^^^^^^ ---- this expression has type `bool` + | | + | expected `bool`, found `Range<_>` + | + = note: expected type `bool` + found struct `std::ops::Range<_>` + +error[E0308]: mismatched types + --> $DIR/disallowed-positions.rs:171:8 + | +LL | if let Range { start: _, end: _ } = true..true && false {} + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ expected `bool`, found `Range<bool>` + | + = note: expected type `bool` + found struct `std::ops::Range<bool>` + +error[E0308]: mismatched types + --> $DIR/disallowed-positions.rs:175:12 + | +LL | if let Range { start: _, end: _ } = true..true || false {} + | ^^^^^^^^^^^^^^^^^^^^^^^^^^ ---- this expression has type `bool` + | | + | expected `bool`, found `Range<_>` + | + = note: expected type `bool` + found struct `std::ops::Range<_>` + +error[E0308]: mismatched types + --> $DIR/disallowed-positions.rs:175:8 + | +LL | if let Range { start: _, end: _ } = true..true || false {} + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ expected `bool`, found `Range<bool>` + | + = note: expected type `bool` + found struct `std::ops::Range<bool>` + +error[E0308]: mismatched types + --> $DIR/disallowed-positions.rs:182:12 + | +LL | if let Range { start: F, end } = F..|| true {} + | ^^^^^^^^^^^^^^^^^^^^^^^ - this expression has type `fn() -> bool` + | | + | expected fn pointer, found `Range<_>` + | + = note: expected fn pointer `fn() -> bool` + found struct `std::ops::Range<_>` + +error[E0308]: mismatched types + --> $DIR/disallowed-positions.rs:182:41 + | +LL | if let Range { start: F, end } = F..|| true {} + | ^^^^^^^ expected `bool`, found closure + | + = note: expected type `bool` + found closure `[closure@$DIR/disallowed-positions.rs:182:41: 182:43]` +help: use parentheses to call this closure + | +LL | if let Range { start: F, end } = F..(|| true)() {} + | + +++ + +error[E0308]: mismatched types + --> $DIR/disallowed-positions.rs:182:8 + | +LL | if let Range { start: F, end } = F..|| true {} + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ expected `bool`, found `Range<bool>` + | + = note: expected type `bool` + found struct `std::ops::Range<bool>` + +error[E0308]: mismatched types + --> $DIR/disallowed-positions.rs:190:12 + | +LL | if let Range { start: true, end } = t..&&false {} + | ^^^^^^^^^^^^^^^^^^^^^^^^^^ - this expression has type `&&bool` + | | + | expected `bool`, found `Range<_>` + | + = note: expected type `bool` + found struct `std::ops::Range<_>` + +error[E0308]: mismatched types + --> $DIR/disallowed-positions.rs:190:44 + | +LL | if let Range { start: true, end } = t..&&false {} + | ^^^^^^^ expected `bool`, found `&&bool` + | +help: consider removing the `&&` + | +LL - if let Range { start: true, end } = t..&&false {} +LL + if let Range { start: true, end } = t..false {} + | + +error[E0308]: mismatched types + --> $DIR/disallowed-positions.rs:190:8 + | +LL | if let Range { start: true, end } = t..&&false {} + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ expected `bool`, found `Range<bool>` + | + = note: expected type `bool` + found struct `std::ops::Range<bool>` + +error[E0277]: the `?` operator can only be applied to values that implement `Try` + --> $DIR/disallowed-positions.rs:128:20 + | +LL | if let 0 = 0? {} + | ^^ the `?` operator cannot be applied to type `{integer}` + | + = help: the trait `Try` is not implemented for `{integer}` + +error[E0308]: mismatched types + --> $DIR/disallowed-positions.rs:202:11 + | +LL | while &let 0 = 0 {} + | ^^^^^^^^^^ expected `bool`, found `&bool` + | +help: consider removing the borrow + | +LL - while &let 0 = 0 {} +LL + while let 0 = 0 {} + | + +error[E0614]: type `bool` cannot be dereferenced + --> $DIR/disallowed-positions.rs:210:11 + | +LL | while *let 0 = 0 {} + | ^^^^^^^^^^ + +error[E0600]: cannot apply unary operator `-` to type `bool` + --> $DIR/disallowed-positions.rs:214:11 + | +LL | while -let 0 = 0 {} + | ^^^^^^^^^^ cannot apply unary operator `-` + +error[E0277]: the `?` operator can only be applied to values that implement `Try` + --> $DIR/disallowed-positions.rs:224:11 + | +LL | while (let 0 = 0)? {} + | ^^^^^^^^^^^^ the `?` operator cannot be applied to type `bool` + | + = help: the trait `Try` is not implemented for `bool` + +error[E0277]: the `?` operator can only be used in a function that returns `Result` or `Option` (or another type that implements `FromResidual`) + --> $DIR/disallowed-positions.rs:224:22 + | +LL | fn nested_within_while_expr() { + | ----------------------------- this function should return `Result` or `Option` to accept `?` +... +LL | while (let 0 = 0)? {} + | ^ cannot use the `?` operator in a function that returns `()` + | + = help: the trait `FromResidual<_>` is not implemented for `()` + +error[E0308]: mismatched types + --> $DIR/disallowed-positions.rs:244:11 + | +LL | while x = let 0 = 0 {} + | ^^^^^^^^^^^^^ expected `bool`, found `()` + | +help: you might have meant to compare for equality + | +LL | while x == let 0 = 0 {} + | + + +error[E0308]: mismatched types + --> $DIR/disallowed-positions.rs:249:11 + | +LL | while true..(let 0 = 0) {} + | ^^^^^^^^^^^^^^^^^ expected `bool`, found `Range<bool>` + | + = note: expected type `bool` + found struct `std::ops::Range<bool>` + +error[E0308]: mismatched types + --> $DIR/disallowed-positions.rs:253:11 + | +LL | while ..(let 0 = 0) {} + | ^^^^^^^^^^^^^ expected `bool`, found `RangeTo<bool>` + | + = note: expected type `bool` + found struct `RangeTo<bool>` + +error[E0308]: mismatched types + --> $DIR/disallowed-positions.rs:257:11 + | +LL | while (let 0 = 0).. {} + | ^^^^^^^^^^^^^ expected `bool`, found `RangeFrom<bool>` + | + = note: expected type `bool` + found struct `RangeFrom<bool>` + +error[E0308]: mismatched types + --> $DIR/disallowed-positions.rs:263:15 + | +LL | while let Range { start: _, end: _ } = true..true && false {} + | ^^^^^^^^^^^^^^^^^^^^^^^^^^ ---- this expression has type `bool` + | | + | expected `bool`, found `Range<_>` + | + = note: expected type `bool` + found struct `std::ops::Range<_>` + +error[E0308]: mismatched types + --> $DIR/disallowed-positions.rs:263:11 + | +LL | while let Range { start: _, end: _ } = true..true && false {} + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ expected `bool`, found `Range<bool>` + | + = note: expected type `bool` + found struct `std::ops::Range<bool>` + +error[E0308]: mismatched types + --> $DIR/disallowed-positions.rs:267:15 + | +LL | while let Range { start: _, end: _ } = true..true || false {} + | ^^^^^^^^^^^^^^^^^^^^^^^^^^ ---- this expression has type `bool` + | | + | expected `bool`, found `Range<_>` + | + = note: expected type `bool` + found struct `std::ops::Range<_>` + +error[E0308]: mismatched types + --> $DIR/disallowed-positions.rs:267:11 + | +LL | while let Range { start: _, end: _ } = true..true || false {} + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ expected `bool`, found `Range<bool>` + | + = note: expected type `bool` + found struct `std::ops::Range<bool>` + +error[E0308]: mismatched types + --> $DIR/disallowed-positions.rs:274:15 + | +LL | while let Range { start: F, end } = F..|| true {} + | ^^^^^^^^^^^^^^^^^^^^^^^ - this expression has type `fn() -> bool` + | | + | expected fn pointer, found `Range<_>` + | + = note: expected fn pointer `fn() -> bool` + found struct `std::ops::Range<_>` + +error[E0308]: mismatched types + --> $DIR/disallowed-positions.rs:274:44 + | +LL | while let Range { start: F, end } = F..|| true {} + | ^^^^^^^ expected `bool`, found closure + | + = note: expected type `bool` + found closure `[closure@$DIR/disallowed-positions.rs:274:44: 274:46]` +help: use parentheses to call this closure + | +LL | while let Range { start: F, end } = F..(|| true)() {} + | + +++ + +error[E0308]: mismatched types + --> $DIR/disallowed-positions.rs:274:11 + | +LL | while let Range { start: F, end } = F..|| true {} + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ expected `bool`, found `Range<bool>` + | + = note: expected type `bool` + found struct `std::ops::Range<bool>` + +error[E0308]: mismatched types + --> $DIR/disallowed-positions.rs:282:15 + | +LL | while let Range { start: true, end } = t..&&false {} + | ^^^^^^^^^^^^^^^^^^^^^^^^^^ - this expression has type `&&bool` + | | + | expected `bool`, found `Range<_>` + | + = note: expected type `bool` + found struct `std::ops::Range<_>` + +error[E0308]: mismatched types + --> $DIR/disallowed-positions.rs:282:47 + | +LL | while let Range { start: true, end } = t..&&false {} + | ^^^^^^^ expected `bool`, found `&&bool` + | +help: consider removing the `&&` + | +LL - while let Range { start: true, end } = t..&&false {} +LL + while let Range { start: true, end } = t..false {} + | + +error[E0308]: mismatched types + --> $DIR/disallowed-positions.rs:282:11 + | +LL | while let Range { start: true, end } = t..&&false {} + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ expected `bool`, found `Range<bool>` + | + = note: expected type `bool` + found struct `std::ops::Range<bool>` + +error[E0277]: the `?` operator can only be applied to values that implement `Try` + --> $DIR/disallowed-positions.rs:220:23 + | +LL | while let 0 = 0? {} + | ^^ the `?` operator cannot be applied to type `{integer}` + | + = help: the trait `Try` is not implemented for `{integer}` + +error[E0614]: type `bool` cannot be dereferenced + --> $DIR/disallowed-positions.rs:311:5 + | +LL | *let 0 = 0; + | ^^^^^^^^^^ + +error[E0600]: cannot apply unary operator `-` to type `bool` + --> $DIR/disallowed-positions.rs:315:5 + | +LL | -let 0 = 0; + | ^^^^^^^^^^ cannot apply unary operator `-` + +error[E0277]: the `?` operator can only be applied to values that implement `Try` + --> $DIR/disallowed-positions.rs:325:5 + | +LL | (let 0 = 0)?; + | ^^^^^^^^^^^^ the `?` operator cannot be applied to type `bool` + | + = help: the trait `Try` is not implemented for `bool` + +error[E0277]: the `?` operator can only be used in a function that returns `Result` or `Option` (or another type that implements `FromResidual`) + --> $DIR/disallowed-positions.rs:325:16 + | +LL | fn outside_if_and_while_expr() { + | ------------------------------ this function should return `Result` or `Option` to accept `?` +... +LL | (let 0 = 0)?; + | ^ cannot use the `?` operator in a function that returns `()` + | + = help: the trait `FromResidual<_>` is not implemented for `()` + +error[E0308]: mismatched types + --> $DIR/disallowed-positions.rs:356:10 + | +LL | (let Range { start: _, end: _ } = true..true || false); + | ^^^^^^^^^^^^^^^^^^^^^^^^^^ ---- this expression has type `bool` + | | + | expected `bool`, found `Range<_>` + | + = note: expected type `bool` + found struct `std::ops::Range<_>` + +error[E0308]: mismatched types + --> $DIR/disallowed-positions.rs:379:5 + | +LL | fn outside_if_and_while_expr() { + | - help: try adding a return type: `-> &bool` +... +LL | &let 0 = 0 + | ^^^^^^^^^^ expected `()`, found `&bool` + +error[E0277]: the `?` operator can only be applied to values that implement `Try` + --> $DIR/disallowed-positions.rs:321:17 + | +LL | let 0 = 0?; + | ^^ the `?` operator cannot be applied to type `{integer}` + | + = help: the trait `Try` is not implemented for `{integer}` + +error: aborting due to 215 previous errors + +Some errors have detailed explanations: E0277, E0308, E0600, E0614. +For more information about an error, try `rustc --explain E0277`. diff --git a/tests/ui/rfcs/rfc-2497-if-let-chains/ensure-that-let-else-does-not-interact-with-let-chains.rs b/tests/ui/rfcs/rfc-2497-if-let-chains/ensure-that-let-else-does-not-interact-with-let-chains.rs new file mode 100644 index 000000000..2a6c14435 --- /dev/null +++ b/tests/ui/rfcs/rfc-2497-if-let-chains/ensure-that-let-else-does-not-interact-with-let-chains.rs @@ -0,0 +1,55 @@ +#![feature(let_chains)] + +fn main() { + let opt = Some(1i32); + + let Some(n) = opt else { + return; + }; + let Some(n) = opt && n == 1 else { + //~^ ERROR a `&&` expression cannot be directly assigned in `let...else` + //~| ERROR mismatched types + //~| ERROR mismatched types + return; + }; + let Some(n) = opt && let another = n else { + //~^ ERROR a `&&` expression cannot be directly assigned in `let...else` + //~| ERROR `let` expressions are not supported here + //~| ERROR mismatched types + //~| ERROR mismatched types + //~| ERROR expected expression, found `let` statement + return; + }; + + if let Some(n) = opt else { + //~^ ERROR this `if` expression is missing a block after the condition + return; + }; + if let Some(n) = opt && n == 1 else { + //~^ ERROR this `if` expression is missing a block after the condition + return; + }; + if let Some(n) = opt && let another = n else { + //~^ ERROR this `if` expression is missing a block after the condition + return; + }; + + { + while let Some(n) = opt else { + //~^ ERROR expected `{`, found keyword `else` + return; + }; + } + { + while let Some(n) = opt && n == 1 else { + //~^ ERROR expected `{`, found keyword `else` + return; + }; + } + { + while let Some(n) = opt && let another = n else { + //~^ ERROR expected `{`, found keyword `else` + return; + }; + } +} diff --git a/tests/ui/rfcs/rfc-2497-if-let-chains/ensure-that-let-else-does-not-interact-with-let-chains.stderr b/tests/ui/rfcs/rfc-2497-if-let-chains/ensure-that-let-else-does-not-interact-with-let-chains.stderr new file mode 100644 index 000000000..9bc3e7541 --- /dev/null +++ b/tests/ui/rfcs/rfc-2497-if-let-chains/ensure-that-let-else-does-not-interact-with-let-chains.stderr @@ -0,0 +1,147 @@ +error: a `&&` expression cannot be directly assigned in `let...else` + --> $DIR/ensure-that-let-else-does-not-interact-with-let-chains.rs:9:19 + | +LL | let Some(n) = opt && n == 1 else { + | ^^^^^^^^^^^^^ + | +help: wrap the expression in parentheses + | +LL | let Some(n) = (opt && n == 1) else { + | + + + +error: expected expression, found `let` statement + --> $DIR/ensure-that-let-else-does-not-interact-with-let-chains.rs:15:26 + | +LL | let Some(n) = opt && let another = n else { + | ^^^ + +error: a `&&` expression cannot be directly assigned in `let...else` + --> $DIR/ensure-that-let-else-does-not-interact-with-let-chains.rs:15:19 + | +LL | let Some(n) = opt && let another = n else { + | ^^^^^^^^^^^^^^^^^^^^^^ + | +help: wrap the expression in parentheses + | +LL | let Some(n) = (opt && let another = n) else { + | + + + +error: this `if` expression is missing a block after the condition + --> $DIR/ensure-that-let-else-does-not-interact-with-let-chains.rs:24:5 + | +LL | if let Some(n) = opt else { + | ^^ + | +help: add a block here + --> $DIR/ensure-that-let-else-does-not-interact-with-let-chains.rs:24:25 + | +LL | if let Some(n) = opt else { + | ^ +help: remove the `if` if you meant to write a `let...else` statement + | +LL - if let Some(n) = opt else { +LL + let Some(n) = opt else { + | + +error: this `if` expression is missing a block after the condition + --> $DIR/ensure-that-let-else-does-not-interact-with-let-chains.rs:28:5 + | +LL | if let Some(n) = opt && n == 1 else { + | ^^ + | +help: add a block here + --> $DIR/ensure-that-let-else-does-not-interact-with-let-chains.rs:28:35 + | +LL | if let Some(n) = opt && n == 1 else { + | ^ + +error: this `if` expression is missing a block after the condition + --> $DIR/ensure-that-let-else-does-not-interact-with-let-chains.rs:32:5 + | +LL | if let Some(n) = opt && let another = n else { + | ^^ + | +help: add a block here + --> $DIR/ensure-that-let-else-does-not-interact-with-let-chains.rs:32:44 + | +LL | if let Some(n) = opt && let another = n else { + | ^ + +error: expected `{`, found keyword `else` + --> $DIR/ensure-that-let-else-does-not-interact-with-let-chains.rs:38:33 + | +LL | while let Some(n) = opt else { + | ----- ----------------- ^^^^ expected `{` + | | | + | | this `while` condition successfully parsed + | while parsing the body of this `while` expression + +error: expected `{`, found keyword `else` + --> $DIR/ensure-that-let-else-does-not-interact-with-let-chains.rs:44:43 + | +LL | while let Some(n) = opt && n == 1 else { + | ----- --------------------------- ^^^^ expected `{` + | | | + | | this `while` condition successfully parsed + | while parsing the body of this `while` expression + +error: expected `{`, found keyword `else` + --> $DIR/ensure-that-let-else-does-not-interact-with-let-chains.rs:50:52 + | +LL | while let Some(n) = opt && let another = n else { + | ----- ------------------------------------ ^^^^ expected `{` + | | | + | | this `while` condition successfully parsed + | while parsing the body of this `while` expression + +error: `let` expressions are not supported here + --> $DIR/ensure-that-let-else-does-not-interact-with-let-chains.rs:15:26 + | +LL | let Some(n) = opt && let another = n else { + | ^^^^^^^^^^^^^^^ + | + = note: only supported directly in conditions of `if` and `while` expressions + +error[E0308]: mismatched types + --> $DIR/ensure-that-let-else-does-not-interact-with-let-chains.rs:9:19 + | +LL | let Some(n) = opt && n == 1 else { + | ^^^ expected `bool`, found `Option<i32>` + | + = note: expected type `bool` + found enum `Option<i32>` + +error[E0308]: mismatched types + --> $DIR/ensure-that-let-else-does-not-interact-with-let-chains.rs:9:9 + | +LL | let Some(n) = opt && n == 1 else { + | ^^^^^^^ ------------- this expression has type `bool` + | | + | expected `bool`, found `Option<_>` + | + = note: expected type `bool` + found enum `Option<_>` + +error[E0308]: mismatched types + --> $DIR/ensure-that-let-else-does-not-interact-with-let-chains.rs:15:19 + | +LL | let Some(n) = opt && let another = n else { + | ^^^ expected `bool`, found `Option<i32>` + | + = note: expected type `bool` + found enum `Option<i32>` + +error[E0308]: mismatched types + --> $DIR/ensure-that-let-else-does-not-interact-with-let-chains.rs:15:9 + | +LL | let Some(n) = opt && let another = n else { + | ^^^^^^^ ---------------------- this expression has type `bool` + | | + | expected `bool`, found `Option<_>` + | + = note: expected type `bool` + found enum `Option<_>` + +error: aborting due to 14 previous errors + +For more information about this error, try `rustc --explain E0308`. diff --git a/tests/ui/rfcs/rfc-2497-if-let-chains/feature-gate.rs b/tests/ui/rfcs/rfc-2497-if-let-chains/feature-gate.rs new file mode 100644 index 000000000..2b407ef51 --- /dev/null +++ b/tests/ui/rfcs/rfc-2497-if-let-chains/feature-gate.rs @@ -0,0 +1,62 @@ +// gate-test-let_chains + +// Here we test feature gating for ´let_chains`. +// See `disallowed-positions.rs` for the grammar +// defining the language for gated allowed positions. + +#![allow(irrefutable_let_patterns)] + +use std::ops::Range; + +fn _if() { + if let 0 = 1 {} // Stable! + + if true && let 0 = 1 {} + //~^ ERROR `let` expressions in this position are unstable [E0658] + + if let 0 = 1 && true {} + //~^ ERROR `let` expressions in this position are unstable [E0658] + + if let Range { start: _, end: _ } = (true..true) && false {} + //~^ ERROR `let` expressions in this position are unstable [E0658] + + if let 1 = 1 && let true = { true } && false { + //~^ ERROR `let` expressions in this position are unstable [E0658] + //~| ERROR `let` expressions in this position are unstable [E0658] + } +} + +fn _while() { + while let 0 = 1 {} // Stable! + + while true && let 0 = 1 {} + //~^ ERROR `let` expressions in this position are unstable [E0658] + + while let 0 = 1 && true {} + //~^ ERROR `let` expressions in this position are unstable [E0658] + + while let Range { start: _, end: _ } = (true..true) && false {} + //~^ ERROR `let` expressions in this position are unstable [E0658] +} + +fn _macros() { + macro_rules! noop_expr { ($e:expr) => {}; } + + noop_expr!((let 0 = 1)); + //~^ ERROR `let` expressions in this position are unstable [E0658] + //~| ERROR expected expression, found `let` statement + + macro_rules! use_expr { + ($e:expr) => { + if $e {} + while $e {} + } + } + #[cfg(FALSE)] (let 0 = 1); + //~^ ERROR `let` expressions in this position are unstable [E0658] + //~| ERROR expected expression, found `let` statement + use_expr!(let 0 = 1); + //~^ ERROR no rules expected the token `let` +} + +fn main() {} diff --git a/tests/ui/rfcs/rfc-2497-if-let-chains/feature-gate.stderr b/tests/ui/rfcs/rfc-2497-if-let-chains/feature-gate.stderr new file mode 100644 index 000000000..7a43b71fc --- /dev/null +++ b/tests/ui/rfcs/rfc-2497-if-let-chains/feature-gate.stderr @@ -0,0 +1,120 @@ +error: expected expression, found `let` statement + --> $DIR/feature-gate.rs:55:20 + | +LL | #[cfg(FALSE)] (let 0 = 1); + | ^^^ + +error: expected expression, found `let` statement + --> $DIR/feature-gate.rs:45:17 + | +LL | noop_expr!((let 0 = 1)); + | ^^^ + +error: no rules expected the token `let` + --> $DIR/feature-gate.rs:58:15 + | +LL | macro_rules! use_expr { + | --------------------- when calling this macro +... +LL | use_expr!(let 0 = 1); + | ^^^ no rules expected this token in macro call + | +note: while trying to match meta-variable `$e:expr` + --> $DIR/feature-gate.rs:50:10 + | +LL | ($e:expr) => { + | ^^^^^^^ + +error[E0658]: `let` expressions in this position are unstable + --> $DIR/feature-gate.rs:14:16 + | +LL | if true && let 0 = 1 {} + | ^^^^^^^^^ + | + = note: see issue #53667 <https://github.com/rust-lang/rust/issues/53667> for more information + = help: add `#![feature(let_chains)]` to the crate attributes to enable + +error[E0658]: `let` expressions in this position are unstable + --> $DIR/feature-gate.rs:17:8 + | +LL | if let 0 = 1 && true {} + | ^^^^^^^^^ + | + = note: see issue #53667 <https://github.com/rust-lang/rust/issues/53667> for more information + = help: add `#![feature(let_chains)]` to the crate attributes to enable + +error[E0658]: `let` expressions in this position are unstable + --> $DIR/feature-gate.rs:20:8 + | +LL | if let Range { start: _, end: _ } = (true..true) && false {} + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + | + = note: see issue #53667 <https://github.com/rust-lang/rust/issues/53667> for more information + = help: add `#![feature(let_chains)]` to the crate attributes to enable + +error[E0658]: `let` expressions in this position are unstable + --> $DIR/feature-gate.rs:23:8 + | +LL | if let 1 = 1 && let true = { true } && false { + | ^^^^^^^^^ + | + = note: see issue #53667 <https://github.com/rust-lang/rust/issues/53667> for more information + = help: add `#![feature(let_chains)]` to the crate attributes to enable + +error[E0658]: `let` expressions in this position are unstable + --> $DIR/feature-gate.rs:23:21 + | +LL | if let 1 = 1 && let true = { true } && false { + | ^^^^^^^^^^^^^^^^^^^ + | + = note: see issue #53667 <https://github.com/rust-lang/rust/issues/53667> for more information + = help: add `#![feature(let_chains)]` to the crate attributes to enable + +error[E0658]: `let` expressions in this position are unstable + --> $DIR/feature-gate.rs:32:19 + | +LL | while true && let 0 = 1 {} + | ^^^^^^^^^ + | + = note: see issue #53667 <https://github.com/rust-lang/rust/issues/53667> for more information + = help: add `#![feature(let_chains)]` to the crate attributes to enable + +error[E0658]: `let` expressions in this position are unstable + --> $DIR/feature-gate.rs:35:11 + | +LL | while let 0 = 1 && true {} + | ^^^^^^^^^ + | + = note: see issue #53667 <https://github.com/rust-lang/rust/issues/53667> for more information + = help: add `#![feature(let_chains)]` to the crate attributes to enable + +error[E0658]: `let` expressions in this position are unstable + --> $DIR/feature-gate.rs:38:11 + | +LL | while let Range { start: _, end: _ } = (true..true) && false {} + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + | + = note: see issue #53667 <https://github.com/rust-lang/rust/issues/53667> for more information + = help: add `#![feature(let_chains)]` to the crate attributes to enable + +error[E0658]: `let` expressions in this position are unstable + --> $DIR/feature-gate.rs:55:20 + | +LL | #[cfg(FALSE)] (let 0 = 1); + | ^^^^^^^^^ + | + = note: see issue #53667 <https://github.com/rust-lang/rust/issues/53667> for more information + = help: add `#![feature(let_chains)]` to the crate attributes to enable + +error[E0658]: `let` expressions in this position are unstable + --> $DIR/feature-gate.rs:45:17 + | +LL | noop_expr!((let 0 = 1)); + | ^^^^^^^^^ + | + = note: see issue #53667 <https://github.com/rust-lang/rust/issues/53667> for more information + = help: add `#![feature(let_chains)]` to the crate attributes to enable + +error: aborting due to 13 previous errors + +For more information about this error, try `rustc --explain E0658`. diff --git a/tests/ui/rfcs/rfc-2497-if-let-chains/invalid-let-in-a-valid-let-context.rs b/tests/ui/rfcs/rfc-2497-if-let-chains/invalid-let-in-a-valid-let-context.rs new file mode 100644 index 000000000..a942d1f4c --- /dev/null +++ b/tests/ui/rfcs/rfc-2497-if-let-chains/invalid-let-in-a-valid-let-context.rs @@ -0,0 +1,45 @@ +#![feature(let_chains)] + +fn main() { + let _opt = Some(1i32); + + #[cfg(FALSE)] + { + let _ = &&let Some(x) = Some(42); + //~^ ERROR expected expression, found `let` statement + } + #[cfg(FALSE)] + { + if let Some(elem) = _opt && [1, 2, 3][let _ = &&let Some(x) = Some(42)] = 1 { + //~^ ERROR expected expression, found `let` statement + //~| ERROR expected expression, found `let` statement + true + } + } + + #[cfg(FALSE)] + { + if let Some(elem) = _opt && { + [1, 2, 3][let _ = ()]; + //~^ ERROR expected expression, found `let` statement + true + } { + } + } + + #[cfg(FALSE)] + { + if let Some(elem) = _opt && [1, 2, 3][let _ = ()] = 1 { + //~^ ERROR expected expression, found `let` statement + true + } + } + #[cfg(FALSE)] + { + if let a = 1 && { + let x = let y = 1; + //~^ ERROR expected expression, found `let` statement + } { + } + } +} diff --git a/tests/ui/rfcs/rfc-2497-if-let-chains/invalid-let-in-a-valid-let-context.stderr b/tests/ui/rfcs/rfc-2497-if-let-chains/invalid-let-in-a-valid-let-context.stderr new file mode 100644 index 000000000..d1ce83c72 --- /dev/null +++ b/tests/ui/rfcs/rfc-2497-if-let-chains/invalid-let-in-a-valid-let-context.stderr @@ -0,0 +1,38 @@ +error: expected expression, found `let` statement + --> $DIR/invalid-let-in-a-valid-let-context.rs:8:19 + | +LL | let _ = &&let Some(x) = Some(42); + | ^^^ + +error: expected expression, found `let` statement + --> $DIR/invalid-let-in-a-valid-let-context.rs:13:47 + | +LL | if let Some(elem) = _opt && [1, 2, 3][let _ = &&let Some(x) = Some(42)] = 1 { + | ^^^ + +error: expected expression, found `let` statement + --> $DIR/invalid-let-in-a-valid-let-context.rs:13:57 + | +LL | if let Some(elem) = _opt && [1, 2, 3][let _ = &&let Some(x) = Some(42)] = 1 { + | ^^^ + +error: expected expression, found `let` statement + --> $DIR/invalid-let-in-a-valid-let-context.rs:23:23 + | +LL | [1, 2, 3][let _ = ()]; + | ^^^ + +error: expected expression, found `let` statement + --> $DIR/invalid-let-in-a-valid-let-context.rs:32:47 + | +LL | if let Some(elem) = _opt && [1, 2, 3][let _ = ()] = 1 { + | ^^^ + +error: expected expression, found `let` statement + --> $DIR/invalid-let-in-a-valid-let-context.rs:40:21 + | +LL | let x = let y = 1; + | ^^^ + +error: aborting due to 6 previous errors + diff --git a/tests/ui/rfcs/rfc-2497-if-let-chains/irrefutable-lets.disallowed.stderr b/tests/ui/rfcs/rfc-2497-if-let-chains/irrefutable-lets.disallowed.stderr new file mode 100644 index 000000000..be4a52315 --- /dev/null +++ b/tests/ui/rfcs/rfc-2497-if-let-chains/irrefutable-lets.disallowed.stderr @@ -0,0 +1,115 @@ +error: leading irrefutable pattern in let chain + --> $DIR/irrefutable-lets.rs:13:8 + | +LL | if let first = &opt && let Some(ref second) = first && let None = second.start {} + | ^^^^^^^^^^^^^^^^ + | + = note: this pattern will always match + = help: consider moving it outside of the construct +note: the lint level is defined here + --> $DIR/irrefutable-lets.rs:6:30 + | +LL | #![cfg_attr(disallowed, deny(irrefutable_let_patterns))] + | ^^^^^^^^^^^^^^^^^^^^^^^^ + +error: irrefutable `if let` patterns + --> $DIR/irrefutable-lets.rs:19:8 + | +LL | if let first = &opt && let (a, b) = (1, 2) {} + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + | + = note: these patterns will always match, so the `if let` is useless + = help: consider replacing the `if let` with a `let` + +error: leading irrefutable pattern in let chain + --> $DIR/irrefutable-lets.rs:22:8 + | +LL | if let first = &opt && let Some(ref second) = first && let None = second.start && let v = 0 {} + | ^^^^^^^^^^^^^^^^ + | + = note: this pattern will always match + = help: consider moving it outside of the construct + +error: trailing irrefutable pattern in let chain + --> $DIR/irrefutable-lets.rs:22:87 + | +LL | if let first = &opt && let Some(ref second) = first && let None = second.start && let v = 0 {} + | ^^^^^^^^^ + | + = note: this pattern will always match + = help: consider moving it into the body + +error: trailing irrefutable patterns in let chain + --> $DIR/irrefutable-lets.rs:26:37 + | +LL | if let Some(ref first) = opt && let second = first && let _third = second {} + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + | + = note: these patterns will always match + = help: consider moving them into the body + +error: leading irrefutable pattern in let chain + --> $DIR/irrefutable-lets.rs:29:8 + | +LL | if let Range { start: local_start, end: _ } = (None..Some(1)) && let None = local_start {} + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + | + = note: this pattern will always match + = help: consider moving it outside of the construct + +error: leading irrefutable pattern in let chain + --> $DIR/irrefutable-lets.rs:32:8 + | +LL | if let (a, b, c) = (Some(1), Some(1), Some(1)) && let None = Some(1) {} + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + | + = note: this pattern will always match + = help: consider moving it outside of the construct + +error: leading irrefutable pattern in let chain + --> $DIR/irrefutable-lets.rs:35:8 + | +LL | if let first = &opt && let None = Some(1) {} + | ^^^^^^^^^^^^^^^^ + | + = note: this pattern will always match + = help: consider moving it outside of the construct + +error: irrefutable `if let` guard patterns + --> $DIR/irrefutable-lets.rs:44:28 + | +LL | Some(ref first) if let second = first && let _third = second && let v = 4 + 4 => {}, + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + | + = note: these patterns will always match, so the guard is useless + = help: consider removing the guard and adding a `let` inside the match arm + +error: trailing irrefutable patterns in let chain + --> $DIR/irrefutable-lets.rs:59:16 + | +LL | && let v = local_end && let w = v => {}, + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + | + = note: these patterns will always match + = help: consider moving them into the body + +error: irrefutable `while let` patterns + --> $DIR/irrefutable-lets.rs:68:11 + | +LL | while let first = &opt && let (a, b) = (1, 2) {} + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + | + = note: these patterns will always match, so the loop will never exit + = help: consider instead using a `loop { ... }` with a `let` inside it + +error: trailing irrefutable patterns in let chain + --> $DIR/irrefutable-lets.rs:71:40 + | +LL | while let Some(ref first) = opt && let second = first && let _third = second {} + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + | + = note: these patterns will always match + = help: consider moving them into the body + +error: aborting due to 12 previous errors + diff --git a/tests/ui/rfcs/rfc-2497-if-let-chains/irrefutable-lets.rs b/tests/ui/rfcs/rfc-2497-if-let-chains/irrefutable-lets.rs new file mode 100644 index 000000000..9afb6853b --- /dev/null +++ b/tests/ui/rfcs/rfc-2497-if-let-chains/irrefutable-lets.rs @@ -0,0 +1,78 @@ +// revisions: allowed disallowed +//[allowed] check-pass + +#![feature(if_let_guard, let_chains)] +#![cfg_attr(allowed, allow(irrefutable_let_patterns))] +#![cfg_attr(disallowed, deny(irrefutable_let_patterns))] + +use std::ops::Range; + +fn main() { + let opt = Some(None..Some(1)); + + if let first = &opt && let Some(ref second) = first && let None = second.start {} + //[disallowed]~^ ERROR leading irrefutable pattern in let chain + + // No lint as the irrefutable pattern is surrounded by other stuff + if 4 * 2 == 0 && let first = &opt && let Some(ref second) = first && let None = second.start {} + + if let first = &opt && let (a, b) = (1, 2) {} + //[disallowed]~^ ERROR irrefutable `if let` patterns + + if let first = &opt && let Some(ref second) = first && let None = second.start && let v = 0 {} + //[disallowed]~^ ERROR leading irrefutable pattern in let chain + //[disallowed]~^^ ERROR trailing irrefutable pattern in let chain + + if let Some(ref first) = opt && let second = first && let _third = second {} + //[disallowed]~^ ERROR trailing irrefutable patterns in let chain + + if let Range { start: local_start, end: _ } = (None..Some(1)) && let None = local_start {} + //[disallowed]~^ ERROR leading irrefutable pattern in let chain + + if let (a, b, c) = (Some(1), Some(1), Some(1)) && let None = Some(1) {} + //[disallowed]~^ ERROR leading irrefutable pattern in let chain + + if let first = &opt && let None = Some(1) {} + //[disallowed]~^ ERROR leading irrefutable pattern in let chain + + if let Some(ref first) = opt + && let Range { start: local_start, end: _ } = first + && let None = local_start { + } + + match opt { + Some(ref first) if let second = first && let _third = second && let v = 4 + 4 => {}, + //[disallowed]~^ ERROR irrefutable `if let` guard patterns + _ => {} + } + + // No error about leading irrefutable patterns: the expr on the rhs might + // use the bindings created by the match. + match opt { + Some(ref first) if let Range { start: local_start, end: _ } = first + && let None = local_start => {}, + _ => {} + } + + match opt { + Some(ref first) if let Range { start: Some(_), end: local_end } = first + && let v = local_end && let w = v => {}, + //[disallowed]~^ ERROR trailing irrefutable patterns in let chain + _ => {} + } + + // No error, despite the prefix being irrefutable: moving out could change the behaviour, + // due to possible side effects of the operation. + while let first = &opt && let Some(ref second) = first && let None = second.start {} + + while let first = &opt && let (a, b) = (1, 2) {} + //[disallowed]~^ ERROR irrefutable `while let` patterns + + while let Some(ref first) = opt && let second = first && let _third = second {} + //[disallowed]~^ ERROR trailing irrefutable patterns in let chain + + while let Some(ref first) = opt + && let Range { start: local_start, end: _ } = first + && let None = local_start { + } +} diff --git a/tests/ui/rfcs/rfc-2497-if-let-chains/issue-88498.rs b/tests/ui/rfcs/rfc-2497-if-let-chains/issue-88498.rs new file mode 100644 index 000000000..3eb8a9ad0 --- /dev/null +++ b/tests/ui/rfcs/rfc-2497-if-let-chains/issue-88498.rs @@ -0,0 +1,16 @@ +// check-pass + +pub enum UnOp { + Not(Vec<()>), +} + +pub fn foo() { + if let Some(x) = None { + match x { + UnOp::Not(_) => {} + } + } +} + +fn main() { +} diff --git a/tests/ui/rfcs/rfc-2497-if-let-chains/issue-90722.rs b/tests/ui/rfcs/rfc-2497-if-let-chains/issue-90722.rs new file mode 100644 index 000000000..6b7d88356 --- /dev/null +++ b/tests/ui/rfcs/rfc-2497-if-let-chains/issue-90722.rs @@ -0,0 +1,11 @@ +// check-pass + +#![feature(let_chains)] + +fn main() { + let x = Some(vec!["test"]); + + if let Some(v) = x && v.is_empty() { + println!("x == Some([])"); + } +} diff --git a/tests/ui/rfcs/rfc-2497-if-let-chains/issue-92145.rs b/tests/ui/rfcs/rfc-2497-if-let-chains/issue-92145.rs new file mode 100644 index 000000000..7c7e31f4d --- /dev/null +++ b/tests/ui/rfcs/rfc-2497-if-let-chains/issue-92145.rs @@ -0,0 +1,11 @@ +// check-pass + +#![feature(let_chains)] + +fn main() { + let opt = Some("foo bar"); + + if true && let Some(x) = opt { + println!("{}", x); + } +} diff --git a/tests/ui/rfcs/rfc-2497-if-let-chains/issue-93150.rs b/tests/ui/rfcs/rfc-2497-if-let-chains/issue-93150.rs new file mode 100644 index 000000000..f90b9ab0d --- /dev/null +++ b/tests/ui/rfcs/rfc-2497-if-let-chains/issue-93150.rs @@ -0,0 +1,8 @@ +fn main() { + match true { + _ if let true = true && true => {} + //~^ ERROR `if let` guards are + //~| ERROR `let` expressions in this + _ => {} + } +} diff --git a/tests/ui/rfcs/rfc-2497-if-let-chains/issue-93150.stderr b/tests/ui/rfcs/rfc-2497-if-let-chains/issue-93150.stderr new file mode 100644 index 000000000..b25f299a2 --- /dev/null +++ b/tests/ui/rfcs/rfc-2497-if-let-chains/issue-93150.stderr @@ -0,0 +1,22 @@ +error[E0658]: `if let` guards are experimental + --> $DIR/issue-93150.rs:3:11 + | +LL | _ if let true = true && true => {} + | ^^^^^^^^^^^^^^^^^^^^^^^^^^ + | + = note: see issue #51114 <https://github.com/rust-lang/rust/issues/51114> for more information + = help: add `#![feature(if_let_guard)]` to the crate attributes to enable + = help: you can write `if matches!(<expr>, <pattern>)` instead of `if let <pattern> = <expr>` + +error[E0658]: `let` expressions in this position are unstable + --> $DIR/issue-93150.rs:3:14 + | +LL | _ if let true = true && true => {} + | ^^^^^^^^^^^^^^^ + | + = note: see issue #53667 <https://github.com/rust-lang/rust/issues/53667> for more information + = help: add `#![feature(let_chains)]` to the crate attributes to enable + +error: aborting due to 2 previous errors + +For more information about this error, try `rustc --explain E0658`. diff --git a/tests/ui/rfcs/rfc-2497-if-let-chains/issue-99938.rs b/tests/ui/rfcs/rfc-2497-if-let-chains/issue-99938.rs new file mode 100644 index 000000000..bd81ce0b1 --- /dev/null +++ b/tests/ui/rfcs/rfc-2497-if-let-chains/issue-99938.rs @@ -0,0 +1,31 @@ +// compile-flags: -Zvalidate-mir -C opt-level=3 +// build-pass +#![feature(let_chains)] +struct TupleIter<T, I: Iterator<Item = T>> { + inner: I, +} + +impl<T, I: Iterator<Item = T>> Iterator for TupleIter<T, I> { + type Item = (T, T, T); + + fn next(&mut self) -> Option<Self::Item> { + let inner = &mut self.inner; + + if let Some(first) = inner.next() + && let Some(second) = inner.next() + && let Some(third) = inner.next() + { + Some((first, second, third)) + } else { + None + } + } +} + +fn main() { + let vec: Vec<u8> = Vec::new(); + let mut tup_iter = TupleIter { + inner: vec.into_iter(), + }; + tup_iter.next(); +} diff --git a/tests/ui/rfcs/rfc-2497-if-let-chains/no-double-assigments.rs b/tests/ui/rfcs/rfc-2497-if-let-chains/no-double-assigments.rs new file mode 100644 index 000000000..6b91c455e --- /dev/null +++ b/tests/ui/rfcs/rfc-2497-if-let-chains/no-double-assigments.rs @@ -0,0 +1,9 @@ +// check-pass + +fn main() { + loop { + // [1][0] should leave top scope + if true && [1][0] == 1 && true { + } + } +} diff --git a/tests/ui/rfcs/rfc-2497-if-let-chains/protect-precedences.rs b/tests/ui/rfcs/rfc-2497-if-let-chains/protect-precedences.rs new file mode 100644 index 000000000..fcc09b159 --- /dev/null +++ b/tests/ui/rfcs/rfc-2497-if-let-chains/protect-precedences.rs @@ -0,0 +1,17 @@ +// run-pass + +#![allow(irrefutable_let_patterns)] + +fn main() { + let x: bool; + // This should associate as: `(x = (true && false));`. + x = true && false; + assert!(!x); + + fn _f1() -> bool { + // Should associate as `(let _ = (return (true && false)))`. + if let _ = return true && false {}; + //~^ WARNING unreachable block in `if` + } + assert!(!_f1()); +} diff --git a/tests/ui/rfcs/rfc-2497-if-let-chains/protect-precedences.stderr b/tests/ui/rfcs/rfc-2497-if-let-chains/protect-precedences.stderr new file mode 100644 index 000000000..24b35a2ab --- /dev/null +++ b/tests/ui/rfcs/rfc-2497-if-let-chains/protect-precedences.stderr @@ -0,0 +1,12 @@ +warning: unreachable block in `if` or `while` expression + --> $DIR/protect-precedences.rs:13:41 + | +LL | if let _ = return true && false {}; + | -------------------- ^^ unreachable block in `if` or `while` expression + | | + | any code following this expression is unreachable + | + = note: `#[warn(unreachable_code)]` on by default + +warning: 1 warning emitted + diff --git a/tests/ui/rfcs/rfc-2497-if-let-chains/then-else-blocks.rs b/tests/ui/rfcs/rfc-2497-if-let-chains/then-else-blocks.rs new file mode 100644 index 000000000..e061174f6 --- /dev/null +++ b/tests/ui/rfcs/rfc-2497-if-let-chains/then-else-blocks.rs @@ -0,0 +1,49 @@ +// run-pass + +#![feature(if_let_guard, let_chains)] + +fn check_if_let(opt: Option<Option<Option<i32>>>, value: i32) -> bool { + if let Some(first) = opt + && let Some(second) = first + && let Some(third) = second + && third == value + { + true + } + else { + false + } +} + +fn check_let_guard(opt: Option<Option<Option<i32>>>, value: i32) -> bool { + match opt { + Some(first) if let Some(second) = first && let Some(third) = second && third == value => { + true + } + _ => { + false + } + } +} + +fn check_while_let(opt: Option<Option<Option<i32>>>, value: i32) -> bool { + while let Some(first) = opt + && let Some(second) = first + && let Some(third) = second + && third == value + { + return true; + } + false +} + +fn main() { + assert_eq!(check_if_let(Some(Some(Some(1))), 1), true); + assert_eq!(check_if_let(Some(Some(Some(1))), 9), false); + + assert_eq!(check_let_guard(Some(Some(Some(1))), 1), true); + assert_eq!(check_let_guard(Some(Some(Some(1))), 9), false); + + assert_eq!(check_while_let(Some(Some(Some(1))), 1), true); + assert_eq!(check_while_let(Some(Some(Some(1))), 9), false); +} diff --git a/tests/ui/rfcs/rfc-2565-param-attrs/attr-without-param.rs b/tests/ui/rfcs/rfc-2565-param-attrs/attr-without-param.rs new file mode 100644 index 000000000..eeb2191ba --- /dev/null +++ b/tests/ui/rfcs/rfc-2565-param-attrs/attr-without-param.rs @@ -0,0 +1,16 @@ +#[cfg(FALSE)] +impl S { + fn f(#[attr]) {} //~ ERROR expected parameter name, found `)` +} + +#[cfg(FALSE)] +impl T for S { + fn f(#[attr]) {} //~ ERROR expected parameter name, found `)` +} + +#[cfg(FALSE)] +trait T { + fn f(#[attr]); //~ ERROR expected argument name, found `)` +} + +fn main() {} diff --git a/tests/ui/rfcs/rfc-2565-param-attrs/attr-without-param.stderr b/tests/ui/rfcs/rfc-2565-param-attrs/attr-without-param.stderr new file mode 100644 index 000000000..26dff4d4b --- /dev/null +++ b/tests/ui/rfcs/rfc-2565-param-attrs/attr-without-param.stderr @@ -0,0 +1,20 @@ +error: expected parameter name, found `)` + --> $DIR/attr-without-param.rs:3:17 + | +LL | fn f(#[attr]) {} + | ^ expected parameter name + +error: expected parameter name, found `)` + --> $DIR/attr-without-param.rs:8:17 + | +LL | fn f(#[attr]) {} + | ^ expected parameter name + +error: expected argument name, found `)` + --> $DIR/attr-without-param.rs:13:17 + | +LL | fn f(#[attr]); + | ^ expected argument name + +error: aborting due to 3 previous errors + diff --git a/tests/ui/rfcs/rfc-2565-param-attrs/auxiliary/ident-mac.rs b/tests/ui/rfcs/rfc-2565-param-attrs/auxiliary/ident-mac.rs new file mode 100644 index 000000000..b62cf3120 --- /dev/null +++ b/tests/ui/rfcs/rfc-2565-param-attrs/auxiliary/ident-mac.rs @@ -0,0 +1,11 @@ +// force-host +// no-prefer-dynamic + +#![crate_type = "proc-macro"] + +extern crate proc_macro; + +use proc_macro::TokenStream; + +#[proc_macro_attribute] +pub fn id(_: TokenStream, input: TokenStream) -> TokenStream { input } diff --git a/tests/ui/rfcs/rfc-2565-param-attrs/auxiliary/param-attrs.rs b/tests/ui/rfcs/rfc-2565-param-attrs/auxiliary/param-attrs.rs new file mode 100644 index 000000000..82c4120b4 --- /dev/null +++ b/tests/ui/rfcs/rfc-2565-param-attrs/auxiliary/param-attrs.rs @@ -0,0 +1,43 @@ +// force-host +// no-prefer-dynamic + +#![crate_type = "proc-macro"] + +extern crate proc_macro; + +use proc_macro::TokenStream; + +macro_rules! checker { + ($attr_name:ident, $expected:literal) => { + #[proc_macro_attribute] + pub fn $attr_name(attr: TokenStream, input: TokenStream) -> TokenStream { + assert_eq!(input.to_string(), $expected); + TokenStream::new() + } + } +} + +checker!(attr_extern, r#"extern "C" { fn ffi(#[a1] arg1 : i32, #[a2] ...) ; }"#); +checker!(attr_extern_cvar, r#"unsafe extern "C" fn cvar(arg1 : i32, #[a1] mut args : ...) {}"#); +checker!(attr_alias, "type Alias = fn(#[a1] u8, #[a2] ...) ;"); +checker!(attr_free, "fn free(#[a1] arg1 : u8) { let lam = | #[a2] W(x), #[a3] y | () ; }"); +checker!(attr_inherent_1, "fn inherent1(#[a1] self, #[a2] arg1 : u8) {}"); +checker!(attr_inherent_2, "fn inherent2(#[a1] & self, #[a2] arg1 : u8) {}"); +checker!(attr_inherent_3, "fn inherent3 < 'a > (#[a1] & 'a mut self, #[a2] arg1 : u8) {}"); +checker!(attr_inherent_4, "fn inherent4 < 'a > (#[a1] self : Box < Self >, #[a2] arg1 : u8) {}"); +checker!(attr_inherent_issue_64682, "fn inherent5(#[a1] #[a2] arg1 : u8, #[a3] arg2 : u8) {}"); +checker!(attr_trait_1, "fn trait1(#[a1] self, #[a2] arg1 : u8) ;"); +checker!(attr_trait_2, "fn trait2(#[a1] & self, #[a2] arg1 : u8) ;"); +checker!(attr_trait_3, "fn trait3 < 'a > (#[a1] & 'a mut self, #[a2] arg1 : u8) ;"); +checker!(attr_trait_4, r#"fn trait4 < 'a > +(#[a1] self : Box < Self >, #[a2] arg1 : u8, #[a3] Vec < u8 >) ;"#); +checker!(attr_trait_issue_64682, "fn trait5(#[a1] #[a2] arg1 : u8, #[a3] arg2 : u8) ;"); +checker!(rename_params, r#"impl Foo +{ + fn hello(#[angery(true)] a : i32, #[a2] b : i32, #[what = "how"] c : u32) + {} fn + hello2(#[a1] #[a2] a : i32, #[what = "how"] b : i32, #[angery(true)] c : + u32) {} fn + hello_self(#[a1] #[a2] & self, #[a1] #[a2] a : i32, #[what = "how"] b : + i32, #[angery(true)] c : u32) {} +}"#); diff --git a/tests/ui/rfcs/rfc-2565-param-attrs/issue-64682-dropping-first-attrs-in-impl-fns.rs b/tests/ui/rfcs/rfc-2565-param-attrs/issue-64682-dropping-first-attrs-in-impl-fns.rs new file mode 100644 index 000000000..670303906 --- /dev/null +++ b/tests/ui/rfcs/rfc-2565-param-attrs/issue-64682-dropping-first-attrs-in-impl-fns.rs @@ -0,0 +1,21 @@ +// aux-build:param-attrs.rs + +// check-pass + +extern crate param_attrs; + +use param_attrs::rename_params; + +#[rename_params(send_help)] +impl Foo { + fn hello(#[angery(true)] a: i32, #[a2] b: i32, #[what = "how"] c: u32) {} + fn hello2(#[a1] #[a2] a: i32, #[what = "how"] b: i32, #[angery(true)] c: u32) {} + fn hello_self( + #[a1] #[a2] &self, + #[a1] #[a2] a: i32, + #[what = "how"] b: i32, + #[angery(true)] c: u32 + ) {} +} + +fn main() {} diff --git a/tests/ui/rfcs/rfc-2565-param-attrs/param-attrs-2018.rs b/tests/ui/rfcs/rfc-2565-param-attrs/param-attrs-2018.rs new file mode 100644 index 000000000..a6f693bd5 --- /dev/null +++ b/tests/ui/rfcs/rfc-2565-param-attrs/param-attrs-2018.rs @@ -0,0 +1,6 @@ +// edition:2018 + +trait Trait2015 { fn foo(#[allow(C)] i32); } +//~^ ERROR expected one of `:`, `@`, or `|`, found `)` + +fn main() {} diff --git a/tests/ui/rfcs/rfc-2565-param-attrs/param-attrs-2018.stderr b/tests/ui/rfcs/rfc-2565-param-attrs/param-attrs-2018.stderr new file mode 100644 index 000000000..593821bf9 --- /dev/null +++ b/tests/ui/rfcs/rfc-2565-param-attrs/param-attrs-2018.stderr @@ -0,0 +1,22 @@ +error: expected one of `:`, `@`, or `|`, found `)` + --> $DIR/param-attrs-2018.rs:3:41 + | +LL | trait Trait2015 { fn foo(#[allow(C)] i32); } + | ^ expected one of `:`, `@`, or `|` + | + = note: anonymous parameters are removed in the 2018 edition (see RFC 1685) +help: if this is a `self` type, give it a parameter name + | +LL | trait Trait2015 { fn foo(#[allow(C)] self: i32); } + | +++++ +help: if this is a parameter name, give it a type + | +LL | trait Trait2015 { fn foo(#[allow(C)] i32: TypeName); } + | ++++++++++ +help: if this is a type, explicitly ignore the parameter name + | +LL | trait Trait2015 { fn foo(#[allow(C)] _: i32); } + | ++ + +error: aborting due to previous error + diff --git a/tests/ui/rfcs/rfc-2565-param-attrs/param-attrs-allowed.rs b/tests/ui/rfcs/rfc-2565-param-attrs/param-attrs-allowed.rs new file mode 100644 index 000000000..2de37c859 --- /dev/null +++ b/tests/ui/rfcs/rfc-2565-param-attrs/param-attrs-allowed.rs @@ -0,0 +1,101 @@ +// check-pass +// compile-flags: --cfg something + +#![deny(unused_mut)] + +extern "C" { + fn ffi( + #[allow(unused_mut)] a: i32, + #[cfg(something)] b: i32, + #[cfg_attr(something, cfg(nothing))] c: i32, + #[forbid(unused_mut)] d: i32, + #[deny(unused_mut)] #[warn(unused_mut)] ... + ); +} + +type FnType = fn( + #[allow(unused_mut)] a: i32, + #[cfg(something)] b: i32, + #[cfg_attr(something, cfg(nothing))] c: i32, + #[forbid(unused_mut)] d: i32, + #[deny(unused_mut)] #[warn(unused_mut)] e: i32 +); + +pub fn foo( + #[allow(unused_mut)] a: i32, + #[cfg(something)] b: i32, + #[cfg_attr(something, cfg(nothing))] c: i32, + #[forbid(unused_mut)] d: i32, + #[deny(unused_mut)] #[warn(unused_mut)] _e: i32 +) {} + +// self + +struct SelfStruct {} +impl SelfStruct { + fn foo( + #[allow(unused_mut)] self, + #[cfg(something)] a: i32, + #[cfg_attr(something, cfg(nothing))] + #[deny(unused_mut)] b: i32, + ) {} +} + +struct RefStruct {} +impl RefStruct { + fn foo( + #[allow(unused_mut)] &self, + #[cfg(something)] a: i32, + #[cfg_attr(something, cfg(nothing))] + #[deny(unused_mut)] b: i32, + ) {} +} +trait RefTrait { + fn foo( + #[forbid(unused_mut)] &self, + #[warn(unused_mut)] a: i32 + ) {} +} +impl RefTrait for RefStruct { + fn foo( + #[forbid(unused_mut)] &self, + #[warn(unused_mut)] a: i32 + ) {} +} + +// Box<Self> + +struct BoxSelfStruct {} +impl BoxSelfStruct { + fn foo( + #[allow(unused_mut)] self: Box<Self>, + #[cfg(something)] a: i32, + #[cfg_attr(something, cfg(nothing))] + #[deny(unused_mut)] b: i32, + ) {} +} +trait BoxSelfTrait { + fn foo( + #[forbid(unused_mut)] self: Box<Self>, + #[warn(unused_mut)] a: i32 + ) {} +} +impl BoxSelfTrait for BoxSelfStruct { + fn foo( + #[forbid(unused_mut)] self: Box<Self>, + #[warn(unused_mut)] a: i32 + ) {} +} + +fn main() { + let _: unsafe extern "C" fn(_, _, _, ...) = ffi; + let _: fn(_, _, _, _) = foo; + let _: FnType = |_, _, _, _| {}; + let c = | + #[allow(unused_mut)] a: u32, + #[cfg(something)] b: i32, + #[cfg_attr(something, cfg(nothing))] + #[deny(unused_mut)] c: i32, + | {}; + c(1, 2); +} diff --git a/tests/ui/rfcs/rfc-2565-param-attrs/param-attrs-builtin-attrs.rs b/tests/ui/rfcs/rfc-2565-param-attrs/param-attrs-builtin-attrs.rs new file mode 100644 index 000000000..151659e35 --- /dev/null +++ b/tests/ui/rfcs/rfc-2565-param-attrs/param-attrs-builtin-attrs.rs @@ -0,0 +1,174 @@ +extern "C" { + fn ffi( + /// Foo + //~^ ERROR documentation comments cannot be applied to function + #[test] a: i32, + //~^ ERROR expected non-macro attribute, found attribute macro + /// Bar + //~^ ERROR documentation comments cannot be applied to function + #[must_use] + //~^ ERROR allow, cfg, cfg_attr, deny, expect, forbid, and warn are the only allowed built-in attributes in function parameters + /// Baz + //~^ ERROR documentation comments cannot be applied to function + #[no_mangle] b: i32, + //~^ ERROR allow, cfg, cfg_attr, deny, expect, forbid, and warn are the only allowed built-in attributes in function parameters + ); +} + +type FnType = fn( + /// Foo + //~^ ERROR documentation comments cannot be applied to function + #[test] a: u32, + //~^ ERROR expected non-macro attribute, found attribute macro + /// Bar + //~^ ERROR documentation comments cannot be applied to function + #[must_use] + //~^ ERROR allow, cfg, cfg_attr, deny, expect, forbid, and warn are the only allowed built-in attributes in function parameters + /// Baz + //~^ ERROR documentation comments cannot be applied to function + #[no_mangle] b: i32, + //~^ ERROR allow, cfg, cfg_attr, deny, expect, forbid, and warn are the only allowed built-in attributes in function parameters +); + +pub fn foo( + /// Foo + //~^ ERROR documentation comments cannot be applied to function + #[test] a: u32, + //~^ ERROR expected non-macro attribute, found attribute macro + /// Bar + //~^ ERROR documentation comments cannot be applied to function + #[must_use] + //~^ ERROR allow, cfg, cfg_attr, deny, expect, forbid, and warn are the only allowed built-in attributes in function parameters + /// Baz + //~^ ERROR documentation comments cannot be applied to function + #[no_mangle] b: i32, + //~^ ERROR allow, cfg, cfg_attr, deny, expect, forbid, and warn are the only allowed built-in attributes in function parameters +) {} + +struct SelfStruct {} +impl SelfStruct { + fn foo( + /// Foo + //~^ ERROR documentation comments cannot be applied to function + self, + /// Bar + //~^ ERROR documentation comments cannot be applied to function + #[test] a: i32, + //~^ ERROR expected non-macro attribute, found attribute macro + /// Baz + //~^ ERROR documentation comments cannot be applied to function + #[must_use] + //~^ ERROR allow, cfg, cfg_attr, deny, expect, forbid, and warn are the only allowed built-in attributes in function parameters + /// Qux + //~^ ERROR documentation comments cannot be applied to function + #[no_mangle] b: i32, + //~^ ERROR allow, cfg, cfg_attr, deny, expect, forbid, and warn are the only allowed built-in attributes in function parameters + ) {} + + fn issue_64682_associated_fn( + /// Foo + //~^ ERROR documentation comments cannot be applied to function + #[test] a: i32, + //~^ ERROR expected non-macro attribute, found attribute macro + /// Baz + //~^ ERROR documentation comments cannot be applied to function + #[must_use] + //~^ ERROR allow, cfg, cfg_attr, deny, expect, forbid, and warn are the only allowed built-in attributes in function parameters + /// Qux + //~^ ERROR documentation comments cannot be applied to function + #[no_mangle] b: i32, + //~^ ERROR allow, cfg, cfg_attr, deny, expect, forbid, and warn are the only allowed built-in attributes in function parameters + ) {} +} + +struct RefStruct {} +impl RefStruct { + fn foo( + /// Foo + //~^ ERROR documentation comments cannot be applied to function + &self, + /// Bar + //~^ ERROR documentation comments cannot be applied to function + #[test] a: i32, + //~^ ERROR expected non-macro attribute, found attribute macro + /// Baz + //~^ ERROR documentation comments cannot be applied to function + #[must_use] + //~^ ERROR allow, cfg, cfg_attr, deny, expect, forbid, and warn are the only allowed built-in attributes in function parameters + /// Qux + //~^ ERROR documentation comments cannot be applied to function + #[no_mangle] b: i32, + //~^ ERROR allow, cfg, cfg_attr, deny, expect, forbid, and warn are the only allowed built-in attributes in function parameters + ) {} +} +trait RefTrait { + fn foo( + /// Foo + //~^ ERROR documentation comments cannot be applied to function + &self, + /// Bar + //~^ ERROR documentation comments cannot be applied to function + #[test] a: i32, + //~^ ERROR expected non-macro attribute, found attribute macro + /// Baz + //~^ ERROR documentation comments cannot be applied to function + #[must_use] + //~^ ERROR allow, cfg, cfg_attr, deny, expect, forbid, and warn are the only allowed built-in attributes in function parameters + /// Qux + //~^ ERROR documentation comments cannot be applied to function + #[no_mangle] b: i32, + //~^ ERROR allow, cfg, cfg_attr, deny, expect, forbid, and warn are the only allowed built-in attributes in function parameters + ) {} + + fn issue_64682_associated_fn( + /// Foo + //~^ ERROR documentation comments cannot be applied to function + #[test] a: i32, + //~^ ERROR expected non-macro attribute, found attribute macro + /// Baz + //~^ ERROR documentation comments cannot be applied to function + #[must_use] + //~^ ERROR allow, cfg, cfg_attr, deny, expect, forbid, and warn are the only allowed built-in attributes in function parameters + /// Qux + //~^ ERROR documentation comments cannot be applied to function + #[no_mangle] b: i32, + //~^ ERROR allow, cfg, cfg_attr, deny, expect, forbid, and warn are the only allowed built-in attributes in function parameters + ) {} +} + +impl RefTrait for RefStruct { + fn foo( + /// Foo + //~^ ERROR documentation comments cannot be applied to function + &self, + /// Bar + //~^ ERROR documentation comments cannot be applied to function + #[test] a: i32, + //~^ ERROR expected non-macro attribute, found attribute macro + /// Baz + //~^ ERROR documentation comments cannot be applied to function + #[must_use] + //~^ ERROR allow, cfg, cfg_attr, deny, expect, forbid, and warn are the only allowed built-in attributes in function parameters + /// Qux + //~^ ERROR documentation comments cannot be applied to function + #[no_mangle] b: i32, + //~^ ERROR allow, cfg, cfg_attr, deny, expect, forbid, and warn are the only allowed built-in attributes in function parameters + ) {} +} + +fn main() { + let _ = | + /// Foo + //~^ ERROR documentation comments cannot be applied to function + #[test] a: u32, + //~^ ERROR expected non-macro attribute, found attribute macro + /// Bar + //~^ ERROR documentation comments cannot be applied to function + #[must_use] + //~^ ERROR allow, cfg, cfg_attr, deny, expect, forbid, and warn are the only allowed built-in attributes in function parameters + /// Baz + //~^ ERROR documentation comments cannot be applied to function + #[no_mangle] b: i32 + //~^ ERROR allow, cfg, cfg_attr, deny, expect, forbid, and warn are the only allowed built-in attributes in function parameters + | {}; +} diff --git a/tests/ui/rfcs/rfc-2565-param-attrs/param-attrs-builtin-attrs.stderr b/tests/ui/rfcs/rfc-2565-param-attrs/param-attrs-builtin-attrs.stderr new file mode 100644 index 000000000..7573e39d8 --- /dev/null +++ b/tests/ui/rfcs/rfc-2565-param-attrs/param-attrs-builtin-attrs.stderr @@ -0,0 +1,386 @@ +error: expected non-macro attribute, found attribute macro `test` + --> $DIR/param-attrs-builtin-attrs.rs:5:11 + | +LL | #[test] a: i32, + | ^^^^ not a non-macro attribute + +error: expected non-macro attribute, found attribute macro `test` + --> $DIR/param-attrs-builtin-attrs.rs:21:7 + | +LL | #[test] a: u32, + | ^^^^ not a non-macro attribute + +error: expected non-macro attribute, found attribute macro `test` + --> $DIR/param-attrs-builtin-attrs.rs:36:7 + | +LL | #[test] a: u32, + | ^^^^ not a non-macro attribute + +error: expected non-macro attribute, found attribute macro `test` + --> $DIR/param-attrs-builtin-attrs.rs:56:11 + | +LL | #[test] a: i32, + | ^^^^ not a non-macro attribute + +error: expected non-macro attribute, found attribute macro `test` + --> $DIR/param-attrs-builtin-attrs.rs:71:11 + | +LL | #[test] a: i32, + | ^^^^ not a non-macro attribute + +error: expected non-macro attribute, found attribute macro `test` + --> $DIR/param-attrs-builtin-attrs.rs:92:11 + | +LL | #[test] a: i32, + | ^^^^ not a non-macro attribute + +error: expected non-macro attribute, found attribute macro `test` + --> $DIR/param-attrs-builtin-attrs.rs:111:11 + | +LL | #[test] a: i32, + | ^^^^ not a non-macro attribute + +error: expected non-macro attribute, found attribute macro `test` + --> $DIR/param-attrs-builtin-attrs.rs:126:11 + | +LL | #[test] a: i32, + | ^^^^ not a non-macro attribute + +error: expected non-macro attribute, found attribute macro `test` + --> $DIR/param-attrs-builtin-attrs.rs:146:11 + | +LL | #[test] a: i32, + | ^^^^ not a non-macro attribute + +error: expected non-macro attribute, found attribute macro `test` + --> $DIR/param-attrs-builtin-attrs.rs:163:11 + | +LL | #[test] a: u32, + | ^^^^ not a non-macro attribute + +error: documentation comments cannot be applied to function parameters + --> $DIR/param-attrs-builtin-attrs.rs:3:9 + | +LL | /// Foo + | ^^^^^^^ doc comments are not allowed here + +error: documentation comments cannot be applied to function parameters + --> $DIR/param-attrs-builtin-attrs.rs:7:9 + | +LL | /// Bar + | ^^^^^^^ doc comments are not allowed here + +error: allow, cfg, cfg_attr, deny, expect, forbid, and warn are the only allowed built-in attributes in function parameters + --> $DIR/param-attrs-builtin-attrs.rs:9:9 + | +LL | #[must_use] + | ^^^^^^^^^^^ + +error: documentation comments cannot be applied to function parameters + --> $DIR/param-attrs-builtin-attrs.rs:11:9 + | +LL | /// Baz + | ^^^^^^^ doc comments are not allowed here + +error: allow, cfg, cfg_attr, deny, expect, forbid, and warn are the only allowed built-in attributes in function parameters + --> $DIR/param-attrs-builtin-attrs.rs:13:9 + | +LL | #[no_mangle] b: i32, + | ^^^^^^^^^^^^ + +error: documentation comments cannot be applied to function parameters + --> $DIR/param-attrs-builtin-attrs.rs:19:5 + | +LL | /// Foo + | ^^^^^^^ doc comments are not allowed here + +error: documentation comments cannot be applied to function parameters + --> $DIR/param-attrs-builtin-attrs.rs:23:5 + | +LL | /// Bar + | ^^^^^^^ doc comments are not allowed here + +error: allow, cfg, cfg_attr, deny, expect, forbid, and warn are the only allowed built-in attributes in function parameters + --> $DIR/param-attrs-builtin-attrs.rs:25:5 + | +LL | #[must_use] + | ^^^^^^^^^^^ + +error: documentation comments cannot be applied to function parameters + --> $DIR/param-attrs-builtin-attrs.rs:27:5 + | +LL | /// Baz + | ^^^^^^^ doc comments are not allowed here + +error: allow, cfg, cfg_attr, deny, expect, forbid, and warn are the only allowed built-in attributes in function parameters + --> $DIR/param-attrs-builtin-attrs.rs:29:5 + | +LL | #[no_mangle] b: i32, + | ^^^^^^^^^^^^ + +error: documentation comments cannot be applied to function parameters + --> $DIR/param-attrs-builtin-attrs.rs:34:5 + | +LL | /// Foo + | ^^^^^^^ doc comments are not allowed here + +error: documentation comments cannot be applied to function parameters + --> $DIR/param-attrs-builtin-attrs.rs:38:5 + | +LL | /// Bar + | ^^^^^^^ doc comments are not allowed here + +error: allow, cfg, cfg_attr, deny, expect, forbid, and warn are the only allowed built-in attributes in function parameters + --> $DIR/param-attrs-builtin-attrs.rs:40:5 + | +LL | #[must_use] + | ^^^^^^^^^^^ + +error: documentation comments cannot be applied to function parameters + --> $DIR/param-attrs-builtin-attrs.rs:42:5 + | +LL | /// Baz + | ^^^^^^^ doc comments are not allowed here + +error: allow, cfg, cfg_attr, deny, expect, forbid, and warn are the only allowed built-in attributes in function parameters + --> $DIR/param-attrs-builtin-attrs.rs:44:5 + | +LL | #[no_mangle] b: i32, + | ^^^^^^^^^^^^ + +error: documentation comments cannot be applied to function parameters + --> $DIR/param-attrs-builtin-attrs.rs:51:9 + | +LL | /// Foo + | ^^^^^^^ doc comments are not allowed here + +error: documentation comments cannot be applied to function parameters + --> $DIR/param-attrs-builtin-attrs.rs:54:9 + | +LL | /// Bar + | ^^^^^^^ doc comments are not allowed here + +error: documentation comments cannot be applied to function parameters + --> $DIR/param-attrs-builtin-attrs.rs:58:9 + | +LL | /// Baz + | ^^^^^^^ doc comments are not allowed here + +error: allow, cfg, cfg_attr, deny, expect, forbid, and warn are the only allowed built-in attributes in function parameters + --> $DIR/param-attrs-builtin-attrs.rs:60:9 + | +LL | #[must_use] + | ^^^^^^^^^^^ + +error: documentation comments cannot be applied to function parameters + --> $DIR/param-attrs-builtin-attrs.rs:62:9 + | +LL | /// Qux + | ^^^^^^^ doc comments are not allowed here + +error: allow, cfg, cfg_attr, deny, expect, forbid, and warn are the only allowed built-in attributes in function parameters + --> $DIR/param-attrs-builtin-attrs.rs:64:9 + | +LL | #[no_mangle] b: i32, + | ^^^^^^^^^^^^ + +error: documentation comments cannot be applied to function parameters + --> $DIR/param-attrs-builtin-attrs.rs:69:9 + | +LL | /// Foo + | ^^^^^^^ doc comments are not allowed here + +error: documentation comments cannot be applied to function parameters + --> $DIR/param-attrs-builtin-attrs.rs:73:9 + | +LL | /// Baz + | ^^^^^^^ doc comments are not allowed here + +error: allow, cfg, cfg_attr, deny, expect, forbid, and warn are the only allowed built-in attributes in function parameters + --> $DIR/param-attrs-builtin-attrs.rs:75:9 + | +LL | #[must_use] + | ^^^^^^^^^^^ + +error: documentation comments cannot be applied to function parameters + --> $DIR/param-attrs-builtin-attrs.rs:77:9 + | +LL | /// Qux + | ^^^^^^^ doc comments are not allowed here + +error: allow, cfg, cfg_attr, deny, expect, forbid, and warn are the only allowed built-in attributes in function parameters + --> $DIR/param-attrs-builtin-attrs.rs:79:9 + | +LL | #[no_mangle] b: i32, + | ^^^^^^^^^^^^ + +error: documentation comments cannot be applied to function parameters + --> $DIR/param-attrs-builtin-attrs.rs:87:9 + | +LL | /// Foo + | ^^^^^^^ doc comments are not allowed here + +error: documentation comments cannot be applied to function parameters + --> $DIR/param-attrs-builtin-attrs.rs:90:9 + | +LL | /// Bar + | ^^^^^^^ doc comments are not allowed here + +error: documentation comments cannot be applied to function parameters + --> $DIR/param-attrs-builtin-attrs.rs:94:9 + | +LL | /// Baz + | ^^^^^^^ doc comments are not allowed here + +error: allow, cfg, cfg_attr, deny, expect, forbid, and warn are the only allowed built-in attributes in function parameters + --> $DIR/param-attrs-builtin-attrs.rs:96:9 + | +LL | #[must_use] + | ^^^^^^^^^^^ + +error: documentation comments cannot be applied to function parameters + --> $DIR/param-attrs-builtin-attrs.rs:98:9 + | +LL | /// Qux + | ^^^^^^^ doc comments are not allowed here + +error: allow, cfg, cfg_attr, deny, expect, forbid, and warn are the only allowed built-in attributes in function parameters + --> $DIR/param-attrs-builtin-attrs.rs:100:9 + | +LL | #[no_mangle] b: i32, + | ^^^^^^^^^^^^ + +error: documentation comments cannot be applied to function parameters + --> $DIR/param-attrs-builtin-attrs.rs:106:9 + | +LL | /// Foo + | ^^^^^^^ doc comments are not allowed here + +error: documentation comments cannot be applied to function parameters + --> $DIR/param-attrs-builtin-attrs.rs:109:9 + | +LL | /// Bar + | ^^^^^^^ doc comments are not allowed here + +error: documentation comments cannot be applied to function parameters + --> $DIR/param-attrs-builtin-attrs.rs:113:9 + | +LL | /// Baz + | ^^^^^^^ doc comments are not allowed here + +error: allow, cfg, cfg_attr, deny, expect, forbid, and warn are the only allowed built-in attributes in function parameters + --> $DIR/param-attrs-builtin-attrs.rs:115:9 + | +LL | #[must_use] + | ^^^^^^^^^^^ + +error: documentation comments cannot be applied to function parameters + --> $DIR/param-attrs-builtin-attrs.rs:117:9 + | +LL | /// Qux + | ^^^^^^^ doc comments are not allowed here + +error: allow, cfg, cfg_attr, deny, expect, forbid, and warn are the only allowed built-in attributes in function parameters + --> $DIR/param-attrs-builtin-attrs.rs:119:9 + | +LL | #[no_mangle] b: i32, + | ^^^^^^^^^^^^ + +error: documentation comments cannot be applied to function parameters + --> $DIR/param-attrs-builtin-attrs.rs:124:9 + | +LL | /// Foo + | ^^^^^^^ doc comments are not allowed here + +error: documentation comments cannot be applied to function parameters + --> $DIR/param-attrs-builtin-attrs.rs:128:9 + | +LL | /// Baz + | ^^^^^^^ doc comments are not allowed here + +error: allow, cfg, cfg_attr, deny, expect, forbid, and warn are the only allowed built-in attributes in function parameters + --> $DIR/param-attrs-builtin-attrs.rs:130:9 + | +LL | #[must_use] + | ^^^^^^^^^^^ + +error: documentation comments cannot be applied to function parameters + --> $DIR/param-attrs-builtin-attrs.rs:132:9 + | +LL | /// Qux + | ^^^^^^^ doc comments are not allowed here + +error: allow, cfg, cfg_attr, deny, expect, forbid, and warn are the only allowed built-in attributes in function parameters + --> $DIR/param-attrs-builtin-attrs.rs:134:9 + | +LL | #[no_mangle] b: i32, + | ^^^^^^^^^^^^ + +error: documentation comments cannot be applied to function parameters + --> $DIR/param-attrs-builtin-attrs.rs:141:9 + | +LL | /// Foo + | ^^^^^^^ doc comments are not allowed here + +error: documentation comments cannot be applied to function parameters + --> $DIR/param-attrs-builtin-attrs.rs:144:9 + | +LL | /// Bar + | ^^^^^^^ doc comments are not allowed here + +error: documentation comments cannot be applied to function parameters + --> $DIR/param-attrs-builtin-attrs.rs:148:9 + | +LL | /// Baz + | ^^^^^^^ doc comments are not allowed here + +error: allow, cfg, cfg_attr, deny, expect, forbid, and warn are the only allowed built-in attributes in function parameters + --> $DIR/param-attrs-builtin-attrs.rs:150:9 + | +LL | #[must_use] + | ^^^^^^^^^^^ + +error: documentation comments cannot be applied to function parameters + --> $DIR/param-attrs-builtin-attrs.rs:152:9 + | +LL | /// Qux + | ^^^^^^^ doc comments are not allowed here + +error: allow, cfg, cfg_attr, deny, expect, forbid, and warn are the only allowed built-in attributes in function parameters + --> $DIR/param-attrs-builtin-attrs.rs:154:9 + | +LL | #[no_mangle] b: i32, + | ^^^^^^^^^^^^ + +error: documentation comments cannot be applied to function parameters + --> $DIR/param-attrs-builtin-attrs.rs:161:9 + | +LL | /// Foo + | ^^^^^^^ doc comments are not allowed here + +error: documentation comments cannot be applied to function parameters + --> $DIR/param-attrs-builtin-attrs.rs:165:9 + | +LL | /// Bar + | ^^^^^^^ doc comments are not allowed here + +error: allow, cfg, cfg_attr, deny, expect, forbid, and warn are the only allowed built-in attributes in function parameters + --> $DIR/param-attrs-builtin-attrs.rs:167:9 + | +LL | #[must_use] + | ^^^^^^^^^^^ + +error: documentation comments cannot be applied to function parameters + --> $DIR/param-attrs-builtin-attrs.rs:169:9 + | +LL | /// Baz + | ^^^^^^^ doc comments are not allowed here + +error: allow, cfg, cfg_attr, deny, expect, forbid, and warn are the only allowed built-in attributes in function parameters + --> $DIR/param-attrs-builtin-attrs.rs:171:9 + | +LL | #[no_mangle] b: i32 + | ^^^^^^^^^^^^ + +error: aborting due to 64 previous errors + diff --git a/tests/ui/rfcs/rfc-2565-param-attrs/param-attrs-cfg.rs b/tests/ui/rfcs/rfc-2565-param-attrs/param-attrs-cfg.rs new file mode 100644 index 000000000..14539d4b6 --- /dev/null +++ b/tests/ui/rfcs/rfc-2565-param-attrs/param-attrs-cfg.rs @@ -0,0 +1,121 @@ +// compile-flags: --cfg something +// edition:2018 + +#![feature(async_closure)] +#![deny(unused_variables)] + +extern "C" { + fn ffi( + #[cfg(nothing)] a: i32, + #[cfg(something)] b: i32, + #[cfg_attr(something, cfg(nothing))] c: i32, + #[cfg_attr(nothing, cfg(nothing))] ... + ); +} + +type FnType = fn( + #[cfg(nothing)] a: i32, + #[cfg(something)] b: i32, + #[cfg_attr(nothing, cfg(nothing))] c: i32, + #[cfg_attr(something, cfg(nothing))] d: i32, +); + +async fn foo_async( + #[cfg(something)] a: i32, + //~^ ERROR unused variable: `a` + #[cfg(nothing)] b: i32, +) {} +fn foo( + #[cfg(nothing)] a: i32, + #[cfg(something)] b: i32, + //~^ ERROR unused variable: `b` + #[cfg_attr(nothing, cfg(nothing))] c: i32, + //~^ ERROR unused variable: `c` + #[cfg_attr(something, cfg(nothing))] d: i32, +) {} + +struct RefStruct {} +impl RefStruct { + async fn bar_async( + &self, + #[cfg(something)] a: i32, + //~^ ERROR unused variable: `a` + #[cfg(nothing)] b: i32, + ) {} + fn bar( + &self, + #[cfg(nothing)] a: i32, + #[cfg(something)] b: i32, + //~^ ERROR unused variable: `b` + #[cfg_attr(nothing, cfg(nothing))] c: i32, + //~^ ERROR unused variable: `c` + #[cfg_attr(something, cfg(nothing))] d: i32, + ) {} + fn issue_64682_associated_fn( + #[cfg(nothing)] a: i32, + #[cfg(something)] b: i32, + //~^ ERROR unused variable: `b` + #[cfg_attr(nothing, cfg(nothing))] c: i32, + //~^ ERROR unused variable: `c` + #[cfg_attr(something, cfg(nothing))] d: i32, + ) {} +} +trait RefTrait { + fn bar( + &self, + #[cfg(nothing)] a: i32, + #[cfg(something)] b: i32, + //~^ ERROR unused variable: `b` + #[cfg_attr(nothing, cfg(nothing))] c: i32, + //~^ ERROR unused variable: `c` + #[cfg_attr(something, cfg(nothing))] d: i32, + ) {} + fn issue_64682_associated_fn( + #[cfg(nothing)] a: i32, + #[cfg(something)] b: i32, + //~^ ERROR unused variable: `b` + #[cfg_attr(nothing, cfg(nothing))] c: i32, + //~^ ERROR unused variable: `c` + #[cfg_attr(something, cfg(nothing))] d: i32, + ) {} +} +impl RefTrait for RefStruct { + fn bar( + &self, + #[cfg(nothing)] a: i32, + #[cfg(something)] b: i32, + //~^ ERROR unused variable: `b` + #[cfg_attr(nothing, cfg(nothing))] c: i32, + //~^ ERROR unused variable: `c` + #[cfg_attr(something, cfg(nothing))] d: i32, + ) {} + fn issue_64682_associated_fn( + #[cfg(nothing)] a: i32, + #[cfg(something)] b: i32, + //~^ ERROR unused variable: `b` + #[cfg_attr(nothing, cfg(nothing))] c: i32, + //~^ ERROR unused variable: `c` + #[cfg_attr(something, cfg(nothing))] d: i32, + ) {} +} + +fn main() { + let _: unsafe extern "C" fn(_, ...) = ffi; + let _: fn(_, _) = foo; + let _: FnType = |_, _| {}; + let a = async move | + #[cfg(something)] a: i32, + //~^ ERROR unused variable: `a` + #[cfg(nothing)] b: i32, + | {}; + let c = | + #[cfg(nothing)] a: i32, + #[cfg(something)] b: i32, + //~^ ERROR unused variable: `b` + #[cfg_attr(nothing, cfg(nothing))] c: i32, + //~^ ERROR unused variable: `c` + #[cfg_attr(something, cfg(nothing))] d: i32, + | {}; + a(1); + c(1, 2); +} diff --git a/tests/ui/rfcs/rfc-2565-param-attrs/param-attrs-cfg.stderr b/tests/ui/rfcs/rfc-2565-param-attrs/param-attrs-cfg.stderr new file mode 100644 index 000000000..16e1af460 --- /dev/null +++ b/tests/ui/rfcs/rfc-2565-param-attrs/param-attrs-cfg.stderr @@ -0,0 +1,122 @@ +error: unused variable: `a` + --> $DIR/param-attrs-cfg.rs:24:23 + | +LL | #[cfg(something)] a: i32, + | ^ help: if this is intentional, prefix it with an underscore: `_a` + | +note: the lint level is defined here + --> $DIR/param-attrs-cfg.rs:5:9 + | +LL | #![deny(unused_variables)] + | ^^^^^^^^^^^^^^^^ + +error: unused variable: `a` + --> $DIR/param-attrs-cfg.rs:41:27 + | +LL | #[cfg(something)] a: i32, + | ^ help: if this is intentional, prefix it with an underscore: `_a` + +error: unused variable: `b` + --> $DIR/param-attrs-cfg.rs:30:23 + | +LL | #[cfg(something)] b: i32, + | ^ help: if this is intentional, prefix it with an underscore: `_b` + +error: unused variable: `c` + --> $DIR/param-attrs-cfg.rs:32:40 + | +LL | #[cfg_attr(nothing, cfg(nothing))] c: i32, + | ^ help: if this is intentional, prefix it with an underscore: `_c` + +error: unused variable: `b` + --> $DIR/param-attrs-cfg.rs:48:27 + | +LL | #[cfg(something)] b: i32, + | ^ help: if this is intentional, prefix it with an underscore: `_b` + +error: unused variable: `c` + --> $DIR/param-attrs-cfg.rs:50:44 + | +LL | #[cfg_attr(nothing, cfg(nothing))] c: i32, + | ^ help: if this is intentional, prefix it with an underscore: `_c` + +error: unused variable: `b` + --> $DIR/param-attrs-cfg.rs:56:27 + | +LL | #[cfg(something)] b: i32, + | ^ help: if this is intentional, prefix it with an underscore: `_b` + +error: unused variable: `c` + --> $DIR/param-attrs-cfg.rs:58:44 + | +LL | #[cfg_attr(nothing, cfg(nothing))] c: i32, + | ^ help: if this is intentional, prefix it with an underscore: `_c` + +error: unused variable: `b` + --> $DIR/param-attrs-cfg.rs:67:27 + | +LL | #[cfg(something)] b: i32, + | ^ help: if this is intentional, prefix it with an underscore: `_b` + +error: unused variable: `c` + --> $DIR/param-attrs-cfg.rs:69:44 + | +LL | #[cfg_attr(nothing, cfg(nothing))] c: i32, + | ^ help: if this is intentional, prefix it with an underscore: `_c` + +error: unused variable: `b` + --> $DIR/param-attrs-cfg.rs:75:27 + | +LL | #[cfg(something)] b: i32, + | ^ help: if this is intentional, prefix it with an underscore: `_b` + +error: unused variable: `c` + --> $DIR/param-attrs-cfg.rs:77:44 + | +LL | #[cfg_attr(nothing, cfg(nothing))] c: i32, + | ^ help: if this is intentional, prefix it with an underscore: `_c` + +error: unused variable: `b` + --> $DIR/param-attrs-cfg.rs:86:27 + | +LL | #[cfg(something)] b: i32, + | ^ help: if this is intentional, prefix it with an underscore: `_b` + +error: unused variable: `c` + --> $DIR/param-attrs-cfg.rs:88:44 + | +LL | #[cfg_attr(nothing, cfg(nothing))] c: i32, + | ^ help: if this is intentional, prefix it with an underscore: `_c` + +error: unused variable: `b` + --> $DIR/param-attrs-cfg.rs:94:27 + | +LL | #[cfg(something)] b: i32, + | ^ help: if this is intentional, prefix it with an underscore: `_b` + +error: unused variable: `c` + --> $DIR/param-attrs-cfg.rs:96:44 + | +LL | #[cfg_attr(nothing, cfg(nothing))] c: i32, + | ^ help: if this is intentional, prefix it with an underscore: `_c` + +error: unused variable: `a` + --> $DIR/param-attrs-cfg.rs:107:27 + | +LL | #[cfg(something)] a: i32, + | ^ help: if this is intentional, prefix it with an underscore: `_a` + +error: unused variable: `b` + --> $DIR/param-attrs-cfg.rs:113:27 + | +LL | #[cfg(something)] b: i32, + | ^ help: if this is intentional, prefix it with an underscore: `_b` + +error: unused variable: `c` + --> $DIR/param-attrs-cfg.rs:115:44 + | +LL | #[cfg_attr(nothing, cfg(nothing))] c: i32, + | ^ help: if this is intentional, prefix it with an underscore: `_c` + +error: aborting due to 19 previous errors + diff --git a/tests/ui/rfcs/rfc-2565-param-attrs/param-attrs-pretty.rs b/tests/ui/rfcs/rfc-2565-param-attrs/param-attrs-pretty.rs new file mode 100644 index 000000000..1183ac65b --- /dev/null +++ b/tests/ui/rfcs/rfc-2565-param-attrs/param-attrs-pretty.rs @@ -0,0 +1,61 @@ +// aux-build:param-attrs.rs + +// check-pass + +#![feature(c_variadic)] + +extern crate param_attrs; + +use param_attrs::*; + +struct W(u8); + +#[attr_extern] +extern "C" { fn ffi(#[a1] arg1: i32, #[a2] ...); } + +#[attr_extern_cvar] +unsafe extern "C" fn cvar(arg1: i32, #[a1] mut args: ...) {} + +#[attr_alias] +type Alias = fn(#[a1] u8, #[a2] ...); + +#[attr_free] +fn free(#[a1] arg1: u8) { + let lam = |#[a2] W(x), #[a3] y| (); +} + +impl W { + #[attr_inherent_1] + fn inherent1(#[a1] self, #[a2] arg1: u8) {} + + #[attr_inherent_2] + fn inherent2(#[a1] &self, #[a2] arg1: u8) {} + + #[attr_inherent_3] + fn inherent3<'a>(#[a1] &'a mut self, #[a2] arg1: u8) {} + + #[attr_inherent_4] + fn inherent4<'a>(#[a1] self: Box<Self>, #[a2] arg1: u8) {} + + #[attr_inherent_issue_64682] + fn inherent5(#[a1] #[a2] arg1: u8, #[a3] arg2: u8) {} +} + +trait A { + #[attr_trait_1] + fn trait1(#[a1] self, #[a2] arg1: u8); + + #[attr_trait_2] + fn trait2(#[a1] &self, #[a2] arg1: u8); + + #[attr_trait_3] + fn trait3<'a>(#[a1] &'a mut self, #[a2] arg1: u8); + + #[attr_trait_4] + fn trait4<'a>(#[a1] self: Box<Self>, #[a2] arg1: u8, #[a3] Vec<u8>); + + #[attr_trait_issue_64682] + fn trait5(#[a1] #[a2] arg1: u8, #[a3] arg2: u8); +} + +fn main() {} diff --git a/tests/ui/rfcs/rfc-2565-param-attrs/proc-macro-cannot-be-used.rs b/tests/ui/rfcs/rfc-2565-param-attrs/proc-macro-cannot-be-used.rs new file mode 100644 index 000000000..54f2f451b --- /dev/null +++ b/tests/ui/rfcs/rfc-2565-param-attrs/proc-macro-cannot-be-used.rs @@ -0,0 +1,66 @@ +// aux-build:ident-mac.rs + +#![feature(c_variadic)] +#![allow(anonymous_parameters)] + +extern crate ident_mac; +use ident_mac::id; + +struct W(u8); + +extern "C" { fn ffi(#[id] arg1: i32, #[id] ...); } +//~^ ERROR expected non-macro attribute, found attribute macro +//~| ERROR expected non-macro attribute, found attribute macro + +unsafe extern "C" fn cvar(arg1: i32, #[id] mut args: ...) {} +//~^ ERROR expected non-macro attribute, found attribute macro + +type Alias = extern "C" fn(#[id] u8, #[id] ...); + //~^ ERROR expected non-macro attribute, found attribute macro + //~| ERROR expected non-macro attribute, found attribute macro + +fn free(#[id] arg1: u8) { + //~^ ERROR expected non-macro attribute, found attribute macro + let lam = |#[id] W(x), #[id] y: usize| (); + //~^ ERROR expected non-macro attribute, found attribute macro + //~| ERROR expected non-macro attribute, found attribute macro +} + +impl W { + fn inherent1(#[id] self, #[id] arg1: u8) {} + //~^ ERROR expected non-macro attribute, found attribute macro + //~| ERROR expected non-macro attribute, found attribute macro + fn inherent2(#[id] &self, #[id] arg1: u8) {} + //~^ ERROR expected non-macro attribute, found attribute macro + //~| ERROR expected non-macro attribute, found attribute macro + fn inherent3<'a>(#[id] &'a mut self, #[id] arg1: u8) {} + //~^ ERROR expected non-macro attribute, found attribute macro + //~| ERROR expected non-macro attribute, found attribute macro + fn inherent4<'a>(#[id] self: Box<Self>, #[id] arg1: u8) {} + //~^ ERROR expected non-macro attribute, found attribute macro + //~| ERROR expected non-macro attribute, found attribute macro + fn issue_64682_associated_fn<'a>(#[id] arg1: u8, #[id] arg2: u8) {} + //~^ ERROR expected non-macro attribute, found attribute macro + //~| ERROR expected non-macro attribute, found attribute macro +} + +trait A { + fn trait1(#[id] self, #[id] arg1: u8); + //~^ ERROR expected non-macro attribute, found attribute macro + //~| ERROR expected non-macro attribute, found attribute macro + fn trait2(#[id] &self, #[id] arg1: u8); + //~^ ERROR expected non-macro attribute, found attribute macro + //~| ERROR expected non-macro attribute, found attribute macro + fn trait3<'a>(#[id] &'a mut self, #[id] arg1: u8); + //~^ ERROR expected non-macro attribute, found attribute macro + //~| ERROR expected non-macro attribute, found attribute macro + fn trait4<'a>(#[id] self: Box<Self>, #[id] arg1: u8, #[id] Vec<u8>); + //~^ ERROR expected non-macro attribute, found attribute macro + //~| ERROR expected non-macro attribute, found attribute macro + //~| ERROR expected non-macro attribute, found attribute macro + fn issue_64682_associated_fn<'a>(#[id] arg1: u8, #[id] arg2: u8); + //~^ ERROR expected non-macro attribute, found attribute macro + //~| ERROR expected non-macro attribute, found attribute macro +} + +fn main() {} diff --git a/tests/ui/rfcs/rfc-2565-param-attrs/proc-macro-cannot-be-used.stderr b/tests/ui/rfcs/rfc-2565-param-attrs/proc-macro-cannot-be-used.stderr new file mode 100644 index 000000000..e74d05d49 --- /dev/null +++ b/tests/ui/rfcs/rfc-2565-param-attrs/proc-macro-cannot-be-used.stderr @@ -0,0 +1,176 @@ +error: expected non-macro attribute, found attribute macro `id` + --> $DIR/proc-macro-cannot-be-used.rs:11:23 + | +LL | extern "C" { fn ffi(#[id] arg1: i32, #[id] ...); } + | ^^ not a non-macro attribute + +error: expected non-macro attribute, found attribute macro `id` + --> $DIR/proc-macro-cannot-be-used.rs:11:40 + | +LL | extern "C" { fn ffi(#[id] arg1: i32, #[id] ...); } + | ^^ not a non-macro attribute + +error: expected non-macro attribute, found attribute macro `id` + --> $DIR/proc-macro-cannot-be-used.rs:15:40 + | +LL | unsafe extern "C" fn cvar(arg1: i32, #[id] mut args: ...) {} + | ^^ not a non-macro attribute + +error: expected non-macro attribute, found attribute macro `id` + --> $DIR/proc-macro-cannot-be-used.rs:18:30 + | +LL | type Alias = extern "C" fn(#[id] u8, #[id] ...); + | ^^ not a non-macro attribute + +error: expected non-macro attribute, found attribute macro `id` + --> $DIR/proc-macro-cannot-be-used.rs:18:40 + | +LL | type Alias = extern "C" fn(#[id] u8, #[id] ...); + | ^^ not a non-macro attribute + +error: expected non-macro attribute, found attribute macro `id` + --> $DIR/proc-macro-cannot-be-used.rs:22:11 + | +LL | fn free(#[id] arg1: u8) { + | ^^ not a non-macro attribute + +error: expected non-macro attribute, found attribute macro `id` + --> $DIR/proc-macro-cannot-be-used.rs:24:18 + | +LL | let lam = |#[id] W(x), #[id] y: usize| (); + | ^^ not a non-macro attribute + +error: expected non-macro attribute, found attribute macro `id` + --> $DIR/proc-macro-cannot-be-used.rs:24:30 + | +LL | let lam = |#[id] W(x), #[id] y: usize| (); + | ^^ not a non-macro attribute + +error: expected non-macro attribute, found attribute macro `id` + --> $DIR/proc-macro-cannot-be-used.rs:30:20 + | +LL | fn inherent1(#[id] self, #[id] arg1: u8) {} + | ^^ not a non-macro attribute + +error: expected non-macro attribute, found attribute macro `id` + --> $DIR/proc-macro-cannot-be-used.rs:30:32 + | +LL | fn inherent1(#[id] self, #[id] arg1: u8) {} + | ^^ not a non-macro attribute + +error: expected non-macro attribute, found attribute macro `id` + --> $DIR/proc-macro-cannot-be-used.rs:33:20 + | +LL | fn inherent2(#[id] &self, #[id] arg1: u8) {} + | ^^ not a non-macro attribute + +error: expected non-macro attribute, found attribute macro `id` + --> $DIR/proc-macro-cannot-be-used.rs:33:33 + | +LL | fn inherent2(#[id] &self, #[id] arg1: u8) {} + | ^^ not a non-macro attribute + +error: expected non-macro attribute, found attribute macro `id` + --> $DIR/proc-macro-cannot-be-used.rs:36:24 + | +LL | fn inherent3<'a>(#[id] &'a mut self, #[id] arg1: u8) {} + | ^^ not a non-macro attribute + +error: expected non-macro attribute, found attribute macro `id` + --> $DIR/proc-macro-cannot-be-used.rs:36:44 + | +LL | fn inherent3<'a>(#[id] &'a mut self, #[id] arg1: u8) {} + | ^^ not a non-macro attribute + +error: expected non-macro attribute, found attribute macro `id` + --> $DIR/proc-macro-cannot-be-used.rs:39:24 + | +LL | fn inherent4<'a>(#[id] self: Box<Self>, #[id] arg1: u8) {} + | ^^ not a non-macro attribute + +error: expected non-macro attribute, found attribute macro `id` + --> $DIR/proc-macro-cannot-be-used.rs:39:47 + | +LL | fn inherent4<'a>(#[id] self: Box<Self>, #[id] arg1: u8) {} + | ^^ not a non-macro attribute + +error: expected non-macro attribute, found attribute macro `id` + --> $DIR/proc-macro-cannot-be-used.rs:42:40 + | +LL | fn issue_64682_associated_fn<'a>(#[id] arg1: u8, #[id] arg2: u8) {} + | ^^ not a non-macro attribute + +error: expected non-macro attribute, found attribute macro `id` + --> $DIR/proc-macro-cannot-be-used.rs:42:56 + | +LL | fn issue_64682_associated_fn<'a>(#[id] arg1: u8, #[id] arg2: u8) {} + | ^^ not a non-macro attribute + +error: expected non-macro attribute, found attribute macro `id` + --> $DIR/proc-macro-cannot-be-used.rs:48:17 + | +LL | fn trait1(#[id] self, #[id] arg1: u8); + | ^^ not a non-macro attribute + +error: expected non-macro attribute, found attribute macro `id` + --> $DIR/proc-macro-cannot-be-used.rs:48:29 + | +LL | fn trait1(#[id] self, #[id] arg1: u8); + | ^^ not a non-macro attribute + +error: expected non-macro attribute, found attribute macro `id` + --> $DIR/proc-macro-cannot-be-used.rs:51:17 + | +LL | fn trait2(#[id] &self, #[id] arg1: u8); + | ^^ not a non-macro attribute + +error: expected non-macro attribute, found attribute macro `id` + --> $DIR/proc-macro-cannot-be-used.rs:51:30 + | +LL | fn trait2(#[id] &self, #[id] arg1: u8); + | ^^ not a non-macro attribute + +error: expected non-macro attribute, found attribute macro `id` + --> $DIR/proc-macro-cannot-be-used.rs:54:21 + | +LL | fn trait3<'a>(#[id] &'a mut self, #[id] arg1: u8); + | ^^ not a non-macro attribute + +error: expected non-macro attribute, found attribute macro `id` + --> $DIR/proc-macro-cannot-be-used.rs:54:41 + | +LL | fn trait3<'a>(#[id] &'a mut self, #[id] arg1: u8); + | ^^ not a non-macro attribute + +error: expected non-macro attribute, found attribute macro `id` + --> $DIR/proc-macro-cannot-be-used.rs:57:21 + | +LL | fn trait4<'a>(#[id] self: Box<Self>, #[id] arg1: u8, #[id] Vec<u8>); + | ^^ not a non-macro attribute + +error: expected non-macro attribute, found attribute macro `id` + --> $DIR/proc-macro-cannot-be-used.rs:57:44 + | +LL | fn trait4<'a>(#[id] self: Box<Self>, #[id] arg1: u8, #[id] Vec<u8>); + | ^^ not a non-macro attribute + +error: expected non-macro attribute, found attribute macro `id` + --> $DIR/proc-macro-cannot-be-used.rs:57:60 + | +LL | fn trait4<'a>(#[id] self: Box<Self>, #[id] arg1: u8, #[id] Vec<u8>); + | ^^ not a non-macro attribute + +error: expected non-macro attribute, found attribute macro `id` + --> $DIR/proc-macro-cannot-be-used.rs:61:40 + | +LL | fn issue_64682_associated_fn<'a>(#[id] arg1: u8, #[id] arg2: u8); + | ^^ not a non-macro attribute + +error: expected non-macro attribute, found attribute macro `id` + --> $DIR/proc-macro-cannot-be-used.rs:61:56 + | +LL | fn issue_64682_associated_fn<'a>(#[id] arg1: u8, #[id] arg2: u8); + | ^^ not a non-macro attribute + +error: aborting due to 29 previous errors + diff --git a/tests/ui/rfcs/rfc-2627-raw-dylib/dlltool-failed.rs b/tests/ui/rfcs/rfc-2627-raw-dylib/dlltool-failed.rs new file mode 100644 index 000000000..d7a418959 --- /dev/null +++ b/tests/ui/rfcs/rfc-2627-raw-dylib/dlltool-failed.rs @@ -0,0 +1,19 @@ +// Tests that dlltool failing to generate an import library will raise an error. + +// only-gnu +// only-windows +// needs-dlltool +// compile-flags: --crate-type lib --emit link +// normalize-stderr-test: "[^ ']*/dlltool.exe" -> "$$DLLTOOL" +// normalize-stderr-test: "[^ ]*/foo.def" -> "$$DEF_FILE" +#[link(name = "foo", kind = "raw-dylib")] +extern "C" { + // `@1` is an invalid name to export, as it usually indicates that something + // is being exported via ordinal. + #[link_name = "@1"] + fn f(x: i32); +} + +pub fn lib_main() { + unsafe { f(42); } +} diff --git a/tests/ui/rfcs/rfc-2627-raw-dylib/dlltool-failed.stderr b/tests/ui/rfcs/rfc-2627-raw-dylib/dlltool-failed.stderr new file mode 100644 index 000000000..020ac6a2b --- /dev/null +++ b/tests/ui/rfcs/rfc-2627-raw-dylib/dlltool-failed.stderr @@ -0,0 +1,5 @@ +error: Dlltool could not create import library: + $DLLTOOL: Syntax error in def file $DEF_FILE:1 + +error: aborting due to previous error + diff --git a/tests/ui/rfcs/rfc-2627-raw-dylib/import-name-type-invalid-format.rs b/tests/ui/rfcs/rfc-2627-raw-dylib/import-name-type-invalid-format.rs new file mode 100644 index 000000000..7bc44d65b --- /dev/null +++ b/tests/ui/rfcs/rfc-2627-raw-dylib/import-name-type-invalid-format.rs @@ -0,0 +1,7 @@ +// only-windows +// only-x86 +#[link(name = "foo", kind = "raw-dylib", import_name_type = 6)] +//~^ ERROR import name type must be of the form `import_name_type = "string"` +extern "C" { } + +fn main() {} diff --git a/tests/ui/rfcs/rfc-2627-raw-dylib/import-name-type-invalid-format.stderr b/tests/ui/rfcs/rfc-2627-raw-dylib/import-name-type-invalid-format.stderr new file mode 100644 index 000000000..fb70b987f --- /dev/null +++ b/tests/ui/rfcs/rfc-2627-raw-dylib/import-name-type-invalid-format.stderr @@ -0,0 +1,8 @@ +error: import name type must be of the form `import_name_type = "string"` + --> $DIR/import-name-type-invalid-format.rs:3:42 + | +LL | #[link(name = "foo", kind = "raw-dylib", import_name_type = 6)] + | ^^^^^^^^^^^^^^^^^^^^ + +error: aborting due to previous error + diff --git a/tests/ui/rfcs/rfc-2627-raw-dylib/import-name-type-multiple.rs b/tests/ui/rfcs/rfc-2627-raw-dylib/import-name-type-multiple.rs new file mode 100644 index 000000000..b96f61a26 --- /dev/null +++ b/tests/ui/rfcs/rfc-2627-raw-dylib/import-name-type-multiple.rs @@ -0,0 +1,8 @@ +// ignore-tidy-linelength +// only-windows +// only-x86 +#[link(name = "foo", kind = "raw-dylib", import_name_type = "decorated", import_name_type = "decorated")] +//~^ ERROR multiple `import_name_type` arguments in a single `#[link]` attribute +extern "C" { } + +fn main() {} diff --git a/tests/ui/rfcs/rfc-2627-raw-dylib/import-name-type-multiple.stderr b/tests/ui/rfcs/rfc-2627-raw-dylib/import-name-type-multiple.stderr new file mode 100644 index 000000000..953306189 --- /dev/null +++ b/tests/ui/rfcs/rfc-2627-raw-dylib/import-name-type-multiple.stderr @@ -0,0 +1,8 @@ +error: multiple `import_name_type` arguments in a single `#[link]` attribute + --> $DIR/import-name-type-multiple.rs:4:74 + | +LL | #[link(name = "foo", kind = "raw-dylib", import_name_type = "decorated", import_name_type = "decorated")] + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + +error: aborting due to previous error + diff --git a/tests/ui/rfcs/rfc-2627-raw-dylib/import-name-type-unknown-value.rs b/tests/ui/rfcs/rfc-2627-raw-dylib/import-name-type-unknown-value.rs new file mode 100644 index 000000000..067e82a17 --- /dev/null +++ b/tests/ui/rfcs/rfc-2627-raw-dylib/import-name-type-unknown-value.rs @@ -0,0 +1,7 @@ +// only-windows +// only-x86 +#[link(name = "foo", kind = "raw-dylib", import_name_type = "unknown")] +//~^ ERROR unknown import name type `unknown`, expected one of: decorated, noprefix, undecorated +extern "C" { } + +fn main() {} diff --git a/tests/ui/rfcs/rfc-2627-raw-dylib/import-name-type-unknown-value.stderr b/tests/ui/rfcs/rfc-2627-raw-dylib/import-name-type-unknown-value.stderr new file mode 100644 index 000000000..2bce9758e --- /dev/null +++ b/tests/ui/rfcs/rfc-2627-raw-dylib/import-name-type-unknown-value.stderr @@ -0,0 +1,8 @@ +error: unknown import name type `unknown`, expected one of: decorated, noprefix, undecorated + --> $DIR/import-name-type-unknown-value.rs:3:42 + | +LL | #[link(name = "foo", kind = "raw-dylib", import_name_type = "unknown")] + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + +error: aborting due to previous error + diff --git a/tests/ui/rfcs/rfc-2627-raw-dylib/import-name-type-unsupported-link-kind.rs b/tests/ui/rfcs/rfc-2627-raw-dylib/import-name-type-unsupported-link-kind.rs new file mode 100644 index 000000000..34e907bde --- /dev/null +++ b/tests/ui/rfcs/rfc-2627-raw-dylib/import-name-type-unsupported-link-kind.rs @@ -0,0 +1,15 @@ +// only-windows +// only-x86 +#[link(name = "foo", import_name_type = "decorated")] +//~^ ERROR import name type can only be used with link kind `raw-dylib` +extern "C" { } + +#[link(name = "bar", kind = "static", import_name_type = "decorated")] +//~^ ERROR import name type can only be used with link kind `raw-dylib` +extern "C" { } + +// Specifying `import_name_type` before `kind` shouldn't raise an error. +#[link(name = "bar", import_name_type = "decorated", kind = "raw-dylib")] +extern "C" { } + +fn main() {} diff --git a/tests/ui/rfcs/rfc-2627-raw-dylib/import-name-type-unsupported-link-kind.stderr b/tests/ui/rfcs/rfc-2627-raw-dylib/import-name-type-unsupported-link-kind.stderr new file mode 100644 index 000000000..75cadc471 --- /dev/null +++ b/tests/ui/rfcs/rfc-2627-raw-dylib/import-name-type-unsupported-link-kind.stderr @@ -0,0 +1,14 @@ +error: import name type can only be used with link kind `raw-dylib` + --> $DIR/import-name-type-unsupported-link-kind.rs:3:22 + | +LL | #[link(name = "foo", import_name_type = "decorated")] + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + +error: import name type can only be used with link kind `raw-dylib` + --> $DIR/import-name-type-unsupported-link-kind.rs:7:39 + | +LL | #[link(name = "bar", kind = "static", import_name_type = "decorated")] + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + +error: aborting due to 2 previous errors + diff --git a/tests/ui/rfcs/rfc-2627-raw-dylib/import-name-type-x86-only.rs b/tests/ui/rfcs/rfc-2627-raw-dylib/import-name-type-x86-only.rs new file mode 100644 index 000000000..346ea18a8 --- /dev/null +++ b/tests/ui/rfcs/rfc-2627-raw-dylib/import-name-type-x86-only.rs @@ -0,0 +1,7 @@ +// only-windows +// ignore-x86 +#[link(name = "foo", kind = "raw-dylib", import_name_type = "decorated")] +//~^ ERROR import name type is only supported on x86 +extern "C" { } + +fn main() {} diff --git a/tests/ui/rfcs/rfc-2627-raw-dylib/import-name-type-x86-only.stderr b/tests/ui/rfcs/rfc-2627-raw-dylib/import-name-type-x86-only.stderr new file mode 100644 index 000000000..b56449299 --- /dev/null +++ b/tests/ui/rfcs/rfc-2627-raw-dylib/import-name-type-x86-only.stderr @@ -0,0 +1,8 @@ +error: import name type is only supported on x86 + --> $DIR/import-name-type-x86-only.rs:3:42 + | +LL | #[link(name = "foo", kind = "raw-dylib", import_name_type = "decorated")] + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + +error: aborting due to previous error + diff --git a/tests/ui/rfcs/rfc-2627-raw-dylib/invalid-dlltool.rs b/tests/ui/rfcs/rfc-2627-raw-dylib/invalid-dlltool.rs new file mode 100644 index 000000000..a07be9d92 --- /dev/null +++ b/tests/ui/rfcs/rfc-2627-raw-dylib/invalid-dlltool.rs @@ -0,0 +1,13 @@ +// Tests that failing to run dlltool will raise an error. + +// only-gnu +// only-windows +// compile-flags: --crate-type lib --emit link -Cdlltool=does_not_exit.exe +#[link(name = "foo", kind = "raw-dylib")] +extern "C" { + fn f(x: i32); +} + +pub fn lib_main() { + unsafe { f(42); } +} diff --git a/tests/ui/rfcs/rfc-2627-raw-dylib/invalid-dlltool.stderr b/tests/ui/rfcs/rfc-2627-raw-dylib/invalid-dlltool.stderr new file mode 100644 index 000000000..3ae901e0d --- /dev/null +++ b/tests/ui/rfcs/rfc-2627-raw-dylib/invalid-dlltool.stderr @@ -0,0 +1,4 @@ +error: Error calling dlltool 'does_not_exit.exe': program not found + +error: aborting due to previous error + diff --git a/tests/ui/rfcs/rfc-2627-raw-dylib/link-ordinal-and-name.rs b/tests/ui/rfcs/rfc-2627-raw-dylib/link-ordinal-and-name.rs new file mode 100644 index 000000000..b04c2facb --- /dev/null +++ b/tests/ui/rfcs/rfc-2627-raw-dylib/link-ordinal-and-name.rs @@ -0,0 +1,13 @@ +#[link(name="foo")] +extern "C" { + #[link_name="foo"] + #[link_ordinal(42)] + //~^ ERROR cannot use `#[link_name]` with `#[link_ordinal]` + fn foo(); + #[link_name="foo"] + #[link_ordinal(5)] + //~^ ERROR cannot use `#[link_name]` with `#[link_ordinal]` + static mut imported_variable: i32; +} + +fn main() {} diff --git a/tests/ui/rfcs/rfc-2627-raw-dylib/link-ordinal-and-name.stderr b/tests/ui/rfcs/rfc-2627-raw-dylib/link-ordinal-and-name.stderr new file mode 100644 index 000000000..f1e54d378 --- /dev/null +++ b/tests/ui/rfcs/rfc-2627-raw-dylib/link-ordinal-and-name.stderr @@ -0,0 +1,14 @@ +error: cannot use `#[link_name]` with `#[link_ordinal]` + --> $DIR/link-ordinal-and-name.rs:4:5 + | +LL | #[link_ordinal(42)] + | ^^^^^^^^^^^^^^^^^^^ + +error: cannot use `#[link_name]` with `#[link_ordinal]` + --> $DIR/link-ordinal-and-name.rs:8:5 + | +LL | #[link_ordinal(5)] + | ^^^^^^^^^^^^^^^^^^ + +error: aborting due to 2 previous errors + diff --git a/tests/ui/rfcs/rfc-2627-raw-dylib/link-ordinal-invalid-format.rs b/tests/ui/rfcs/rfc-2627-raw-dylib/link-ordinal-invalid-format.rs new file mode 100644 index 000000000..9b7e8d707 --- /dev/null +++ b/tests/ui/rfcs/rfc-2627-raw-dylib/link-ordinal-invalid-format.rs @@ -0,0 +1,11 @@ +#[link(name = "foo")] +extern "C" { + #[link_ordinal("JustMonika")] + //~^ ERROR illegal ordinal format in `link_ordinal` + fn foo(); + #[link_ordinal("JustMonika")] + //~^ ERROR illegal ordinal format in `link_ordinal` + static mut imported_variable: i32; +} + +fn main() {} diff --git a/tests/ui/rfcs/rfc-2627-raw-dylib/link-ordinal-invalid-format.stderr b/tests/ui/rfcs/rfc-2627-raw-dylib/link-ordinal-invalid-format.stderr new file mode 100644 index 000000000..6341e57a0 --- /dev/null +++ b/tests/ui/rfcs/rfc-2627-raw-dylib/link-ordinal-invalid-format.stderr @@ -0,0 +1,18 @@ +error: illegal ordinal format in `link_ordinal` + --> $DIR/link-ordinal-invalid-format.rs:3:5 + | +LL | #[link_ordinal("JustMonika")] + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + | + = note: an unsuffixed integer value, e.g., `1`, is expected + +error: illegal ordinal format in `link_ordinal` + --> $DIR/link-ordinal-invalid-format.rs:6:5 + | +LL | #[link_ordinal("JustMonika")] + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + | + = note: an unsuffixed integer value, e.g., `1`, is expected + +error: aborting due to 2 previous errors + diff --git a/tests/ui/rfcs/rfc-2627-raw-dylib/link-ordinal-missing-argument.rs b/tests/ui/rfcs/rfc-2627-raw-dylib/link-ordinal-missing-argument.rs new file mode 100644 index 000000000..6b8cd4956 --- /dev/null +++ b/tests/ui/rfcs/rfc-2627-raw-dylib/link-ordinal-missing-argument.rs @@ -0,0 +1,11 @@ +#[link(name = "foo")] +extern "C" { + #[link_ordinal()] + //~^ ERROR incorrect number of arguments to `#[link_ordinal]` + fn foo(); + #[link_ordinal()] + //~^ ERROR incorrect number of arguments to `#[link_ordinal]` + static mut imported_variable: i32; +} + +fn main() {} diff --git a/tests/ui/rfcs/rfc-2627-raw-dylib/link-ordinal-missing-argument.stderr b/tests/ui/rfcs/rfc-2627-raw-dylib/link-ordinal-missing-argument.stderr new file mode 100644 index 000000000..1b04bb228 --- /dev/null +++ b/tests/ui/rfcs/rfc-2627-raw-dylib/link-ordinal-missing-argument.stderr @@ -0,0 +1,18 @@ +error: incorrect number of arguments to `#[link_ordinal]` + --> $DIR/link-ordinal-missing-argument.rs:3:5 + | +LL | #[link_ordinal()] + | ^^^^^^^^^^^^^^^^^ + | + = note: the attribute requires exactly one argument + +error: incorrect number of arguments to `#[link_ordinal]` + --> $DIR/link-ordinal-missing-argument.rs:6:5 + | +LL | #[link_ordinal()] + | ^^^^^^^^^^^^^^^^^ + | + = note: the attribute requires exactly one argument + +error: aborting due to 2 previous errors + diff --git a/tests/ui/rfcs/rfc-2627-raw-dylib/link-ordinal-multiple.rs b/tests/ui/rfcs/rfc-2627-raw-dylib/link-ordinal-multiple.rs new file mode 100644 index 000000000..8842cb944 --- /dev/null +++ b/tests/ui/rfcs/rfc-2627-raw-dylib/link-ordinal-multiple.rs @@ -0,0 +1,12 @@ +// only-windows +#[link(name = "foo", kind = "raw-dylib")] +extern "C" { + #[link_ordinal(1)] //~ ERROR multiple `link_ordinal` attributes + #[link_ordinal(2)] + fn foo(); + #[link_ordinal(1)] //~ ERROR multiple `link_ordinal` attributes + #[link_ordinal(2)] + static mut imported_variable: i32; +} + +fn main() {} diff --git a/tests/ui/rfcs/rfc-2627-raw-dylib/link-ordinal-multiple.stderr b/tests/ui/rfcs/rfc-2627-raw-dylib/link-ordinal-multiple.stderr new file mode 100644 index 000000000..2e6cf3761 --- /dev/null +++ b/tests/ui/rfcs/rfc-2627-raw-dylib/link-ordinal-multiple.stderr @@ -0,0 +1,26 @@ +error: multiple `link_ordinal` attributes + --> $DIR/link-ordinal-multiple.rs:4:5 + | +LL | #[link_ordinal(1)] + | ^^^^^^^^^^^^^^^^^^ help: remove this attribute + | +note: attribute also specified here + --> $DIR/link-ordinal-multiple.rs:5:5 + | +LL | #[link_ordinal(2)] + | ^^^^^^^^^^^^^^^^^^ + +error: multiple `link_ordinal` attributes + --> $DIR/link-ordinal-multiple.rs:7:5 + | +LL | #[link_ordinal(1)] + | ^^^^^^^^^^^^^^^^^^ help: remove this attribute + | +note: attribute also specified here + --> $DIR/link-ordinal-multiple.rs:8:5 + | +LL | #[link_ordinal(2)] + | ^^^^^^^^^^^^^^^^^^ + +error: aborting due to 2 previous errors + diff --git a/tests/ui/rfcs/rfc-2627-raw-dylib/link-ordinal-not-foreign-fn.rs b/tests/ui/rfcs/rfc-2627-raw-dylib/link-ordinal-not-foreign-fn.rs new file mode 100644 index 000000000..f33a3d62e --- /dev/null +++ b/tests/ui/rfcs/rfc-2627-raw-dylib/link-ordinal-not-foreign-fn.rs @@ -0,0 +1,22 @@ +#[link_ordinal(123)] +//~^ ERROR attribute should be applied to a foreign function or static +struct Foo {} + +#[link_ordinal(123)] +//~^ ERROR attribute should be applied to a foreign function or static +fn test() {} + +#[link_ordinal(42)] +//~^ ERROR attribute should be applied to a foreign function or static +static mut imported_val: i32 = 123; + +#[link(name = "exporter", kind = "raw-dylib")] +extern { + #[link_ordinal(13)] + fn imported_function(); + + #[link_ordinal(42)] + static mut imported_variable: i32; +} + +fn main() {} diff --git a/tests/ui/rfcs/rfc-2627-raw-dylib/link-ordinal-not-foreign-fn.stderr b/tests/ui/rfcs/rfc-2627-raw-dylib/link-ordinal-not-foreign-fn.stderr new file mode 100644 index 000000000..8f2795087 --- /dev/null +++ b/tests/ui/rfcs/rfc-2627-raw-dylib/link-ordinal-not-foreign-fn.stderr @@ -0,0 +1,20 @@ +error: attribute should be applied to a foreign function or static + --> $DIR/link-ordinal-not-foreign-fn.rs:1:1 + | +LL | #[link_ordinal(123)] + | ^^^^^^^^^^^^^^^^^^^^ + +error: attribute should be applied to a foreign function or static + --> $DIR/link-ordinal-not-foreign-fn.rs:5:1 + | +LL | #[link_ordinal(123)] + | ^^^^^^^^^^^^^^^^^^^^ + +error: attribute should be applied to a foreign function or static + --> $DIR/link-ordinal-not-foreign-fn.rs:9:1 + | +LL | #[link_ordinal(42)] + | ^^^^^^^^^^^^^^^^^^^ + +error: aborting due to 3 previous errors + diff --git a/tests/ui/rfcs/rfc-2627-raw-dylib/link-ordinal-too-large.rs b/tests/ui/rfcs/rfc-2627-raw-dylib/link-ordinal-too-large.rs new file mode 100644 index 000000000..9d741630f --- /dev/null +++ b/tests/ui/rfcs/rfc-2627-raw-dylib/link-ordinal-too-large.rs @@ -0,0 +1,11 @@ +#[link(name = "foo")] +extern "C" { + #[link_ordinal(72436)] + //~^ ERROR ordinal value in `link_ordinal` is too large: `72436` + fn foo(); + #[link_ordinal(72436)] + //~^ ERROR ordinal value in `link_ordinal` is too large: `72436` + static mut imported_variable: i32; +} + +fn main() {} diff --git a/tests/ui/rfcs/rfc-2627-raw-dylib/link-ordinal-too-large.stderr b/tests/ui/rfcs/rfc-2627-raw-dylib/link-ordinal-too-large.stderr new file mode 100644 index 000000000..811145e77 --- /dev/null +++ b/tests/ui/rfcs/rfc-2627-raw-dylib/link-ordinal-too-large.stderr @@ -0,0 +1,18 @@ +error: ordinal value in `link_ordinal` is too large: `72436` + --> $DIR/link-ordinal-too-large.rs:3:5 + | +LL | #[link_ordinal(72436)] + | ^^^^^^^^^^^^^^^^^^^^^^ + | + = note: the value may not exceed `u16::MAX` + +error: ordinal value in `link_ordinal` is too large: `72436` + --> $DIR/link-ordinal-too-large.rs:6:5 + | +LL | #[link_ordinal(72436)] + | ^^^^^^^^^^^^^^^^^^^^^^ + | + = note: the value may not exceed `u16::MAX` + +error: aborting due to 2 previous errors + diff --git a/tests/ui/rfcs/rfc-2627-raw-dylib/link-ordinal-too-many-arguments.rs b/tests/ui/rfcs/rfc-2627-raw-dylib/link-ordinal-too-many-arguments.rs new file mode 100644 index 000000000..9988115fd --- /dev/null +++ b/tests/ui/rfcs/rfc-2627-raw-dylib/link-ordinal-too-many-arguments.rs @@ -0,0 +1,11 @@ +#[link(name = "foo")] +extern "C" { + #[link_ordinal(3, 4)] + //~^ ERROR incorrect number of arguments to `#[link_ordinal]` + fn foo(); + #[link_ordinal(3, 4)] + //~^ ERROR incorrect number of arguments to `#[link_ordinal]` + static mut imported_variable: i32; +} + +fn main() {} diff --git a/tests/ui/rfcs/rfc-2627-raw-dylib/link-ordinal-too-many-arguments.stderr b/tests/ui/rfcs/rfc-2627-raw-dylib/link-ordinal-too-many-arguments.stderr new file mode 100644 index 000000000..d5ce8aff3 --- /dev/null +++ b/tests/ui/rfcs/rfc-2627-raw-dylib/link-ordinal-too-many-arguments.stderr @@ -0,0 +1,18 @@ +error: incorrect number of arguments to `#[link_ordinal]` + --> $DIR/link-ordinal-too-many-arguments.rs:3:5 + | +LL | #[link_ordinal(3, 4)] + | ^^^^^^^^^^^^^^^^^^^^^ + | + = note: the attribute requires exactly one argument + +error: incorrect number of arguments to `#[link_ordinal]` + --> $DIR/link-ordinal-too-many-arguments.rs:6:5 + | +LL | #[link_ordinal(3, 4)] + | ^^^^^^^^^^^^^^^^^^^^^ + | + = note: the attribute requires exactly one argument + +error: aborting due to 2 previous errors + diff --git a/tests/ui/rfcs/rfc-2627-raw-dylib/link-ordinal-unsupported-link-kind.rs b/tests/ui/rfcs/rfc-2627-raw-dylib/link-ordinal-unsupported-link-kind.rs new file mode 100644 index 000000000..14e915d60 --- /dev/null +++ b/tests/ui/rfcs/rfc-2627-raw-dylib/link-ordinal-unsupported-link-kind.rs @@ -0,0 +1,15 @@ +#[link(name = "foo")] +extern "C" { + #[link_ordinal(3)] + //~^ ERROR `#[link_ordinal]` is only supported if link kind is `raw-dylib` + fn foo(); +} + +#[link(name = "bar", kind = "static")] +extern "C" { + #[link_ordinal(3)] + //~^ ERROR `#[link_ordinal]` is only supported if link kind is `raw-dylib` + fn bar(); +} + +fn main() {} diff --git a/tests/ui/rfcs/rfc-2627-raw-dylib/link-ordinal-unsupported-link-kind.stderr b/tests/ui/rfcs/rfc-2627-raw-dylib/link-ordinal-unsupported-link-kind.stderr new file mode 100644 index 000000000..200b8f628 --- /dev/null +++ b/tests/ui/rfcs/rfc-2627-raw-dylib/link-ordinal-unsupported-link-kind.stderr @@ -0,0 +1,14 @@ +error: `#[link_ordinal]` is only supported if link kind is `raw-dylib` + --> $DIR/link-ordinal-unsupported-link-kind.rs:3:5 + | +LL | #[link_ordinal(3)] + | ^^^^^^^^^^^^^^^^^^ + +error: `#[link_ordinal]` is only supported if link kind is `raw-dylib` + --> $DIR/link-ordinal-unsupported-link-kind.rs:10:5 + | +LL | #[link_ordinal(3)] + | ^^^^^^^^^^^^^^^^^^ + +error: aborting due to 2 previous errors + diff --git a/tests/ui/rfcs/rfc-2627-raw-dylib/multiple-declarations.rs b/tests/ui/rfcs/rfc-2627-raw-dylib/multiple-declarations.rs new file mode 100644 index 000000000..b4173f3b6 --- /dev/null +++ b/tests/ui/rfcs/rfc-2627-raw-dylib/multiple-declarations.rs @@ -0,0 +1,18 @@ +// only-x86 +// only-windows +// compile-flags: --crate-type lib --emit link +#![allow(clashing_extern_declarations)] +#[link(name = "foo", kind = "raw-dylib")] +extern "C" { + fn f(x: i32); +} + +pub fn lib_main() { + #[link(name = "foo", kind = "raw-dylib")] + extern "stdcall" { + fn f(x: i32); + //~^ ERROR multiple declarations of external function `f` from library `foo.dll` have different calling conventions + } + + unsafe { f(42); } +} diff --git a/tests/ui/rfcs/rfc-2627-raw-dylib/multiple-declarations.stderr b/tests/ui/rfcs/rfc-2627-raw-dylib/multiple-declarations.stderr new file mode 100644 index 000000000..510108405 --- /dev/null +++ b/tests/ui/rfcs/rfc-2627-raw-dylib/multiple-declarations.stderr @@ -0,0 +1,8 @@ +error: multiple declarations of external function `f` from library `foo.dll` have different calling conventions + --> $DIR/multiple-declarations.rs:13:9 + | +LL | fn f(x: i32); + | ^^^^^^^^^^^^^ + +error: aborting due to previous error + diff --git a/tests/ui/rfcs/rfc-2627-raw-dylib/raw-dylib-windows-only.rs b/tests/ui/rfcs/rfc-2627-raw-dylib/raw-dylib-windows-only.rs new file mode 100644 index 000000000..d4c6658a3 --- /dev/null +++ b/tests/ui/rfcs/rfc-2627-raw-dylib/raw-dylib-windows-only.rs @@ -0,0 +1,5 @@ +// ignore-windows +// compile-flags: --crate-type lib +#[link(name = "foo", kind = "raw-dylib")] +//~^ ERROR: link kind `raw-dylib` is only supported on Windows targets +extern "C" {} diff --git a/tests/ui/rfcs/rfc-2627-raw-dylib/raw-dylib-windows-only.stderr b/tests/ui/rfcs/rfc-2627-raw-dylib/raw-dylib-windows-only.stderr new file mode 100644 index 000000000..b635a09af --- /dev/null +++ b/tests/ui/rfcs/rfc-2627-raw-dylib/raw-dylib-windows-only.stderr @@ -0,0 +1,9 @@ +error[E0455]: link kind `raw-dylib` is only supported on Windows targets + --> $DIR/raw-dylib-windows-only.rs:3:29 + | +LL | #[link(name = "foo", kind = "raw-dylib")] + | ^^^^^^^^^^^ + +error: aborting due to previous error + +For more information about this error, try `rustc --explain E0455`. diff --git a/tests/ui/rfcs/rfc-2627-raw-dylib/unsupported-abi.rs b/tests/ui/rfcs/rfc-2627-raw-dylib/unsupported-abi.rs new file mode 100644 index 000000000..2f5a23e47 --- /dev/null +++ b/tests/ui/rfcs/rfc-2627-raw-dylib/unsupported-abi.rs @@ -0,0 +1,12 @@ +// only-x86_64 +// only-windows +// compile-flags: --crate-type lib --emit link +#[link(name = "foo", kind = "raw-dylib")] +extern "stdcall" { + fn f(x: i32); + //~^ ERROR ABI not supported by `#[link(kind = "raw-dylib")]` on this architecture +} + +pub fn lib_main() { + unsafe { f(42); } +} diff --git a/tests/ui/rfcs/rfc-2627-raw-dylib/unsupported-abi.stderr b/tests/ui/rfcs/rfc-2627-raw-dylib/unsupported-abi.stderr new file mode 100644 index 000000000..f8265ae69 --- /dev/null +++ b/tests/ui/rfcs/rfc-2627-raw-dylib/unsupported-abi.stderr @@ -0,0 +1,8 @@ +error: ABI not supported by `#[link(kind = "raw-dylib")]` on this architecture + --> $DIR/unsupported-abi.rs:6:5 + | +LL | fn f(x: i32); + | ^^^^^^^^^^^^^ + +error: aborting due to previous error + diff --git a/tests/ui/rfcs/rfc-2632-const-trait-impl/assoc-type-const-bound-usage.rs b/tests/ui/rfcs/rfc-2632-const-trait-impl/assoc-type-const-bound-usage.rs new file mode 100644 index 000000000..780a510c5 --- /dev/null +++ b/tests/ui/rfcs/rfc-2632-const-trait-impl/assoc-type-const-bound-usage.rs @@ -0,0 +1,14 @@ +// check-pass +#![feature(const_trait_impl)] + +#[const_trait] +trait Foo { + type Assoc: ~const Foo; + fn foo() {} +} + +const fn foo<T: ~const Foo>() { + <T as Foo>::Assoc::foo(); +} + +fn main() {} diff --git a/tests/ui/rfcs/rfc-2632-const-trait-impl/assoc-type.rs b/tests/ui/rfcs/rfc-2632-const-trait-impl/assoc-type.rs new file mode 100644 index 000000000..96790a873 --- /dev/null +++ b/tests/ui/rfcs/rfc-2632-const-trait-impl/assoc-type.rs @@ -0,0 +1,33 @@ +// known-bug: #110395 + +#![feature(const_trait_impl)] + +struct NonConstAdd(i32); + +impl std::ops::Add for NonConstAdd { + type Output = Self; + + fn add(self, rhs: Self) -> Self { + NonConstAdd(self.0 + rhs.0) + } +} + +#[const_trait] +trait Foo { + type Bar: ~const std::ops::Add; +} + +impl const Foo for NonConstAdd { + type Bar = NonConstAdd; +} + +#[const_trait] +trait Baz { + type Qux: std::ops::Add; +} + +impl const Baz for NonConstAdd { + type Qux = NonConstAdd; // OK +} + +fn main() {} diff --git a/tests/ui/rfcs/rfc-2632-const-trait-impl/assoc-type.stderr b/tests/ui/rfcs/rfc-2632-const-trait-impl/assoc-type.stderr new file mode 100644 index 000000000..0cffae1da --- /dev/null +++ b/tests/ui/rfcs/rfc-2632-const-trait-impl/assoc-type.stderr @@ -0,0 +1,8 @@ +error: ~const can only be applied to `#[const_trait]` traits + --> $DIR/assoc-type.rs:17:22 + | +LL | type Bar: ~const std::ops::Add; + | ^^^^^^^^^^^^^ + +error: aborting due to previous error + diff --git a/tests/ui/rfcs/rfc-2632-const-trait-impl/attr-misuse.rs b/tests/ui/rfcs/rfc-2632-const-trait-impl/attr-misuse.rs new file mode 100644 index 000000000..01ac74fef --- /dev/null +++ b/tests/ui/rfcs/rfc-2632-const-trait-impl/attr-misuse.rs @@ -0,0 +1,10 @@ +#![feature(const_trait_impl)] + +#[const_trait] +trait A { + #[const_trait] //~ ERROR attribute should be applied + fn foo(self); +} + +#[const_trait] //~ ERROR attribute should be applied +fn main() {} diff --git a/tests/ui/rfcs/rfc-2632-const-trait-impl/attr-misuse.stderr b/tests/ui/rfcs/rfc-2632-const-trait-impl/attr-misuse.stderr new file mode 100644 index 000000000..998958ced --- /dev/null +++ b/tests/ui/rfcs/rfc-2632-const-trait-impl/attr-misuse.stderr @@ -0,0 +1,18 @@ +error: attribute should be applied to a trait + --> $DIR/attr-misuse.rs:9:1 + | +LL | #[const_trait] + | ^^^^^^^^^^^^^^ +LL | fn main() {} + | ------------ not a trait + +error: attribute should be applied to a trait + --> $DIR/attr-misuse.rs:5:5 + | +LL | #[const_trait] + | ^^^^^^^^^^^^^^ +LL | fn foo(self); + | ------------- not a trait + +error: aborting due to 2 previous errors + diff --git a/tests/ui/rfcs/rfc-2632-const-trait-impl/auxiliary/cross-crate.rs b/tests/ui/rfcs/rfc-2632-const-trait-impl/auxiliary/cross-crate.rs new file mode 100644 index 000000000..e73082c11 --- /dev/null +++ b/tests/ui/rfcs/rfc-2632-const-trait-impl/auxiliary/cross-crate.rs @@ -0,0 +1,23 @@ +#![feature(const_trait_impl)] + +#[const_trait] +pub trait MyTrait { + fn defaulted_func(&self) {} + fn func(self); +} + +pub struct NonConst; + +impl MyTrait for NonConst { + fn func(self) { + + } +} + +pub struct Const; + +impl const MyTrait for Const { + fn func(self) { + + } +} diff --git a/tests/ui/rfcs/rfc-2632-const-trait-impl/auxiliary/staged-api.rs b/tests/ui/rfcs/rfc-2632-const-trait-impl/auxiliary/staged-api.rs new file mode 100644 index 000000000..589e3f024 --- /dev/null +++ b/tests/ui/rfcs/rfc-2632-const-trait-impl/auxiliary/staged-api.rs @@ -0,0 +1,19 @@ +#![feature(const_trait_impl)] +#![feature(staged_api)] +#![stable(feature = "rust1", since = "1.0.0")] + +#[stable(feature = "rust1", since = "1.0.0")] +#[const_trait] +pub trait MyTrait { + #[stable(feature = "rust1", since = "1.0.0")] + fn func(); +} + +#[stable(feature = "rust1", since = "1.0.0")] +pub struct Unstable; + +#[stable(feature = "rust1", since = "1.0.0")] +#[rustc_const_unstable(feature = "unstable", issue = "none")] +impl const MyTrait for Unstable { + fn func() {} +} diff --git a/tests/ui/rfcs/rfc-2632-const-trait-impl/call-const-trait-method-fail.rs b/tests/ui/rfcs/rfc-2632-const-trait-impl/call-const-trait-method-fail.rs new file mode 100644 index 000000000..dd9933974 --- /dev/null +++ b/tests/ui/rfcs/rfc-2632-const-trait-impl/call-const-trait-method-fail.rs @@ -0,0 +1,29 @@ +#![feature(const_trait_impl)] + +#[const_trait] +pub trait Plus { + fn plus(self, rhs: Self) -> Self; +} + +impl const Plus for i32 { + fn plus(self, rhs: Self) -> Self { + self + rhs + } +} + +impl Plus for u32 { + fn plus(self, rhs: Self) -> Self { + self + rhs + } +} + +pub const fn add_i32(a: i32, b: i32) -> i32 { + a.plus(b) // ok +} + +pub const fn add_u32(a: u32, b: u32) -> u32 { + a.plus(b) + //~^ ERROR the trait bound +} + +fn main() {} diff --git a/tests/ui/rfcs/rfc-2632-const-trait-impl/call-const-trait-method-fail.stderr b/tests/ui/rfcs/rfc-2632-const-trait-impl/call-const-trait-method-fail.stderr new file mode 100644 index 000000000..7350909ba --- /dev/null +++ b/tests/ui/rfcs/rfc-2632-const-trait-impl/call-const-trait-method-fail.stderr @@ -0,0 +1,15 @@ +error[E0277]: the trait bound `u32: ~const Plus` is not satisfied + --> $DIR/call-const-trait-method-fail.rs:25:7 + | +LL | a.plus(b) + | ^^^^ the trait `~const Plus` is not implemented for `u32` + | +note: the trait `Plus` is implemented for `u32`, but that implementation is not `const` + --> $DIR/call-const-trait-method-fail.rs:25:7 + | +LL | a.plus(b) + | ^^^^ + +error: aborting due to previous error + +For more information about this error, try `rustc --explain E0277`. diff --git a/tests/ui/rfcs/rfc-2632-const-trait-impl/call-const-trait-method-pass.rs b/tests/ui/rfcs/rfc-2632-const-trait-impl/call-const-trait-method-pass.rs new file mode 100644 index 000000000..ae0c2e6bc --- /dev/null +++ b/tests/ui/rfcs/rfc-2632-const-trait-impl/call-const-trait-method-pass.rs @@ -0,0 +1,43 @@ +// known-bug: #110395 + +#![feature(const_trait_impl)] + +struct Int(i32); + +impl const std::ops::Add for Int { + type Output = Int; + + fn add(self, rhs: Self) -> Self { + Int(self.0.plus(rhs.0)) + } +} + +impl const PartialEq for Int { + fn eq(&self, rhs: &Self) -> bool { + self.0 == rhs.0 + } + fn ne(&self, other: &Self) -> bool { + !self.eq(other) + } +} + +#[const_trait] +pub trait Plus { + fn plus(self, rhs: Self) -> Self; +} + +impl const Plus for i32 { + fn plus(self, rhs: Self) -> Self { + self + rhs + } +} + +pub const fn add_i32(a: i32, b: i32) -> i32 { + a.plus(b) +} + +const ADD_INT: Int = Int(1i32) + Int(2i32); + +fn main() { + assert!(ADD_INT == Int(3i32)); +} diff --git a/tests/ui/rfcs/rfc-2632-const-trait-impl/call-const-trait-method-pass.stderr b/tests/ui/rfcs/rfc-2632-const-trait-impl/call-const-trait-method-pass.stderr new file mode 100644 index 000000000..ff53eea11 --- /dev/null +++ b/tests/ui/rfcs/rfc-2632-const-trait-impl/call-const-trait-method-pass.stderr @@ -0,0 +1,20 @@ +error: const `impl` for trait `Add` which is not marked with `#[const_trait]` + --> $DIR/call-const-trait-method-pass.rs:7:12 + | +LL | impl const std::ops::Add for Int { + | ^^^^^^^^^^^^^ + | + = note: marking a trait with `#[const_trait]` ensures all default method bodies are `const` + = note: adding a non-const method body in the future would be a breaking change + +error: const `impl` for trait `PartialEq` which is not marked with `#[const_trait]` + --> $DIR/call-const-trait-method-pass.rs:15:12 + | +LL | impl const PartialEq for Int { + | ^^^^^^^^^ + | + = note: marking a trait with `#[const_trait]` ensures all default method bodies are `const` + = note: adding a non-const method body in the future would be a breaking change + +error: aborting due to 2 previous errors + diff --git a/tests/ui/rfcs/rfc-2632-const-trait-impl/call-generic-in-impl.rs b/tests/ui/rfcs/rfc-2632-const-trait-impl/call-generic-in-impl.rs new file mode 100644 index 000000000..5120e6bfb --- /dev/null +++ b/tests/ui/rfcs/rfc-2632-const-trait-impl/call-generic-in-impl.rs @@ -0,0 +1,15 @@ +// known-bug: #110395 +#![feature(const_trait_impl)] + +#[const_trait] +trait MyPartialEq { + fn eq(&self, other: &Self) -> bool; +} + +impl<T: ~const PartialEq> const MyPartialEq for T { + fn eq(&self, other: &Self) -> bool { + PartialEq::eq(self, other) + } +} + +fn main() {} diff --git a/tests/ui/rfcs/rfc-2632-const-trait-impl/call-generic-in-impl.stderr b/tests/ui/rfcs/rfc-2632-const-trait-impl/call-generic-in-impl.stderr new file mode 100644 index 000000000..02d53cc78 --- /dev/null +++ b/tests/ui/rfcs/rfc-2632-const-trait-impl/call-generic-in-impl.stderr @@ -0,0 +1,8 @@ +error: ~const can only be applied to `#[const_trait]` traits + --> $DIR/call-generic-in-impl.rs:9:16 + | +LL | impl<T: ~const PartialEq> const MyPartialEq for T { + | ^^^^^^^^^ + +error: aborting due to previous error + diff --git a/tests/ui/rfcs/rfc-2632-const-trait-impl/call-generic-method-chain.rs b/tests/ui/rfcs/rfc-2632-const-trait-impl/call-generic-method-chain.rs new file mode 100644 index 000000000..3febb328a --- /dev/null +++ b/tests/ui/rfcs/rfc-2632-const-trait-impl/call-generic-method-chain.rs @@ -0,0 +1,28 @@ +//! Basic test for calling methods on generic type parameters in `const fn`. + +// known-bug: #110395 + +#![feature(const_trait_impl)] + +struct S; + +impl const PartialEq for S { + fn eq(&self, _: &S) -> bool { + true + } + fn ne(&self, other: &S) -> bool { + !self.eq(other) + } +} + +const fn equals_self<T: ~const PartialEq>(t: &T) -> bool { + *t == *t +} + +const fn equals_self_wrapper<T: ~const PartialEq>(t: &T) -> bool { + equals_self(t) +} + +pub const EQ: bool = equals_self_wrapper(&S); + +fn main() {} diff --git a/tests/ui/rfcs/rfc-2632-const-trait-impl/call-generic-method-chain.stderr b/tests/ui/rfcs/rfc-2632-const-trait-impl/call-generic-method-chain.stderr new file mode 100644 index 000000000..529a472e0 --- /dev/null +++ b/tests/ui/rfcs/rfc-2632-const-trait-impl/call-generic-method-chain.stderr @@ -0,0 +1,23 @@ +error: const `impl` for trait `PartialEq` which is not marked with `#[const_trait]` + --> $DIR/call-generic-method-chain.rs:9:12 + | +LL | impl const PartialEq for S { + | ^^^^^^^^^ + | + = note: marking a trait with `#[const_trait]` ensures all default method bodies are `const` + = note: adding a non-const method body in the future would be a breaking change + +error: ~const can only be applied to `#[const_trait]` traits + --> $DIR/call-generic-method-chain.rs:18:32 + | +LL | const fn equals_self<T: ~const PartialEq>(t: &T) -> bool { + | ^^^^^^^^^ + +error: ~const can only be applied to `#[const_trait]` traits + --> $DIR/call-generic-method-chain.rs:22:40 + | +LL | const fn equals_self_wrapper<T: ~const PartialEq>(t: &T) -> bool { + | ^^^^^^^^^ + +error: aborting due to 3 previous errors + diff --git a/tests/ui/rfcs/rfc-2632-const-trait-impl/call-generic-method-dup-bound.rs b/tests/ui/rfcs/rfc-2632-const-trait-impl/call-generic-method-dup-bound.rs new file mode 100644 index 000000000..e618160d3 --- /dev/null +++ b/tests/ui/rfcs/rfc-2632-const-trait-impl/call-generic-method-dup-bound.rs @@ -0,0 +1,31 @@ +// known-bug: #110395 + +#![feature(const_trait_impl)] + +struct S; + +impl const PartialEq for S { + fn eq(&self, _: &S) -> bool { + true + } + fn ne(&self, other: &S) -> bool { + !self.eq(other) + } +} + +// This duplicate bound should not result in ambiguities. It should be equivalent to a single ~const +// bound. +const fn equals_self<T: PartialEq + ~const PartialEq>(t: &T) -> bool { + *t == *t +} + +trait A: PartialEq {} +impl<T: PartialEq> A for T {} + +const fn equals_self2<T: A + ~const PartialEq>(t: &T) -> bool { + *t == *t +} + +pub const EQ: bool = equals_self(&S) && equals_self2(&S); + +fn main() {} diff --git a/tests/ui/rfcs/rfc-2632-const-trait-impl/call-generic-method-dup-bound.stderr b/tests/ui/rfcs/rfc-2632-const-trait-impl/call-generic-method-dup-bound.stderr new file mode 100644 index 000000000..bdc6ccc8a --- /dev/null +++ b/tests/ui/rfcs/rfc-2632-const-trait-impl/call-generic-method-dup-bound.stderr @@ -0,0 +1,23 @@ +error: const `impl` for trait `PartialEq` which is not marked with `#[const_trait]` + --> $DIR/call-generic-method-dup-bound.rs:7:12 + | +LL | impl const PartialEq for S { + | ^^^^^^^^^ + | + = note: marking a trait with `#[const_trait]` ensures all default method bodies are `const` + = note: adding a non-const method body in the future would be a breaking change + +error: ~const can only be applied to `#[const_trait]` traits + --> $DIR/call-generic-method-dup-bound.rs:18:44 + | +LL | const fn equals_self<T: PartialEq + ~const PartialEq>(t: &T) -> bool { + | ^^^^^^^^^ + +error: ~const can only be applied to `#[const_trait]` traits + --> $DIR/call-generic-method-dup-bound.rs:25:37 + | +LL | const fn equals_self2<T: A + ~const PartialEq>(t: &T) -> bool { + | ^^^^^^^^^ + +error: aborting due to 3 previous errors + diff --git a/tests/ui/rfcs/rfc-2632-const-trait-impl/call-generic-method-fail.rs b/tests/ui/rfcs/rfc-2632-const-trait-impl/call-generic-method-fail.rs new file mode 100644 index 000000000..fe1abbf42 --- /dev/null +++ b/tests/ui/rfcs/rfc-2632-const-trait-impl/call-generic-method-fail.rs @@ -0,0 +1,9 @@ +// known-bug: #110395 +#![feature(const_trait_impl)] + +pub const fn equals_self<T: PartialEq>(t: &T) -> bool { + *t == *t + // (remove this) ~^ ERROR can't compare +} + +fn main() {} diff --git a/tests/ui/rfcs/rfc-2632-const-trait-impl/call-generic-method-fail.stderr b/tests/ui/rfcs/rfc-2632-const-trait-impl/call-generic-method-fail.stderr new file mode 100644 index 000000000..3963f64ad --- /dev/null +++ b/tests/ui/rfcs/rfc-2632-const-trait-impl/call-generic-method-fail.stderr @@ -0,0 +1,28 @@ +error[E0277]: can't compare `T` with `T` in const contexts + --> $DIR/call-generic-method-fail.rs:5:5 + | +LL | *t == *t + | ^^^^^^^^ no implementation for `T == T` + | +note: the trait `PartialEq` is implemented for `T`, but that implementation is not `const` + --> $DIR/call-generic-method-fail.rs:5:5 + | +LL | *t == *t + | ^^^^^^^^ + +error[E0015]: cannot call non-const operator in constant functions + --> $DIR/call-generic-method-fail.rs:5:5 + | +LL | *t == *t + | ^^^^^^^^ + | + = note: calls in constant functions are limited to constant functions, tuple structs and tuple variants +help: consider further restricting this bound + | +LL | pub const fn equals_self<T: PartialEq + ~const std::cmp::PartialEq>(t: &T) -> bool { + | ++++++++++++++++++++++++++++ + +error: aborting due to 2 previous errors + +Some errors have detailed explanations: E0015, E0277. +For more information about an error, try `rustc --explain E0015`. diff --git a/tests/ui/rfcs/rfc-2632-const-trait-impl/call-generic-method-nonconst-bound.rs b/tests/ui/rfcs/rfc-2632-const-trait-impl/call-generic-method-nonconst-bound.rs new file mode 100644 index 000000000..e197c8b73 --- /dev/null +++ b/tests/ui/rfcs/rfc-2632-const-trait-impl/call-generic-method-nonconst-bound.rs @@ -0,0 +1,17 @@ +// check-pass + +struct S; + +impl PartialEq for S { + fn eq(&self, _: &S) -> bool { + true + } +} + +const fn equals_self<T: PartialEq>(t: &T) -> bool { + true +} + +pub const EQ: bool = equals_self(&S); + +fn main() {} diff --git a/tests/ui/rfcs/rfc-2632-const-trait-impl/call-generic-method-nonconst.rs b/tests/ui/rfcs/rfc-2632-const-trait-impl/call-generic-method-nonconst.rs new file mode 100644 index 000000000..414a8c87d --- /dev/null +++ b/tests/ui/rfcs/rfc-2632-const-trait-impl/call-generic-method-nonconst.rs @@ -0,0 +1,26 @@ +#![feature(const_trait_impl)] + +struct S; + +#[const_trait] +trait Foo { + fn eq(&self, _: &Self) -> bool; +} + +impl Foo for S { + fn eq(&self, _: &S) -> bool { + true + } +} + +const fn equals_self<T: ~const Foo>(t: &T) -> bool { + true +} + +// Calling `equals_self` with something that has a non-const impl should throw an error, despite +// it not using the impl. + +pub const EQ: bool = equals_self(&S); +//~^ ERROR + +fn main() {} diff --git a/tests/ui/rfcs/rfc-2632-const-trait-impl/call-generic-method-nonconst.stderr b/tests/ui/rfcs/rfc-2632-const-trait-impl/call-generic-method-nonconst.stderr new file mode 100644 index 000000000..a28d6ce05 --- /dev/null +++ b/tests/ui/rfcs/rfc-2632-const-trait-impl/call-generic-method-nonconst.stderr @@ -0,0 +1,15 @@ +error[E0277]: the trait bound `S: ~const Foo` is not satisfied + --> $DIR/call-generic-method-nonconst.rs:23:22 + | +LL | pub const EQ: bool = equals_self(&S); + | ^^^^^^^^^^^^^^^ the trait `~const Foo` is not implemented for `S` + | +note: the trait `Foo` is implemented for `S`, but that implementation is not `const` + --> $DIR/call-generic-method-nonconst.rs:23:22 + | +LL | pub const EQ: bool = equals_self(&S); + | ^^^^^^^^^^^^^^^ + +error: aborting due to previous error + +For more information about this error, try `rustc --explain E0277`. diff --git a/tests/ui/rfcs/rfc-2632-const-trait-impl/call-generic-method-pass.rs b/tests/ui/rfcs/rfc-2632-const-trait-impl/call-generic-method-pass.rs new file mode 100644 index 000000000..09f35a277 --- /dev/null +++ b/tests/ui/rfcs/rfc-2632-const-trait-impl/call-generic-method-pass.rs @@ -0,0 +1,24 @@ +//! Basic test for calling methods on generic type parameters in `const fn`. + +// known-bug: #110395 + +#![feature(const_trait_impl)] + +struct S; + +impl const PartialEq for S { + fn eq(&self, _: &S) -> bool { + true + } + fn ne(&self, other: &S) -> bool { + !self.eq(other) + } +} + +const fn equals_self<T: ~const PartialEq>(t: &T) -> bool { + *t == *t +} + +pub const EQ: bool = equals_self(&S); + +fn main() {} diff --git a/tests/ui/rfcs/rfc-2632-const-trait-impl/call-generic-method-pass.stderr b/tests/ui/rfcs/rfc-2632-const-trait-impl/call-generic-method-pass.stderr new file mode 100644 index 000000000..7fbe89dba --- /dev/null +++ b/tests/ui/rfcs/rfc-2632-const-trait-impl/call-generic-method-pass.stderr @@ -0,0 +1,17 @@ +error: const `impl` for trait `PartialEq` which is not marked with `#[const_trait]` + --> $DIR/call-generic-method-pass.rs:9:12 + | +LL | impl const PartialEq for S { + | ^^^^^^^^^ + | + = note: marking a trait with `#[const_trait]` ensures all default method bodies are `const` + = note: adding a non-const method body in the future would be a breaking change + +error: ~const can only be applied to `#[const_trait]` traits + --> $DIR/call-generic-method-pass.rs:18:32 + | +LL | const fn equals_self<T: ~const PartialEq>(t: &T) -> bool { + | ^^^^^^^^^ + +error: aborting due to 2 previous errors + diff --git a/tests/ui/rfcs/rfc-2632-const-trait-impl/call.rs b/tests/ui/rfcs/rfc-2632-const-trait-impl/call.rs new file mode 100644 index 000000000..5f48c2353 --- /dev/null +++ b/tests/ui/rfcs/rfc-2632-const-trait-impl/call.rs @@ -0,0 +1,10 @@ +// check-pass + +#![feature(const_closures, const_trait_impl)] +#![allow(incomplete_features)] + +pub const _: () = { + assert!((const || true)()); +}; + +fn main() {} diff --git a/tests/ui/rfcs/rfc-2632-const-trait-impl/const-and-non-const-impl.rs b/tests/ui/rfcs/rfc-2632-const-trait-impl/const-and-non-const-impl.rs new file mode 100644 index 000000000..9ba19e800 --- /dev/null +++ b/tests/ui/rfcs/rfc-2632-const-trait-impl/const-and-non-const-impl.rs @@ -0,0 +1,31 @@ +// known-bug: #110395 + +#![feature(const_trait_impl)] + +pub struct Int(i32); + +impl const std::ops::Add for i32 { + type Output = Self; + + fn add(self, rhs: Self) -> Self { + self + rhs + } +} + +impl std::ops::Add for Int { + type Output = Self; + + fn add(self, rhs: Self) -> Self { + Int(self.0 + rhs.0) + } +} + +impl const std::ops::Add for Int { + type Output = Self; + + fn add(self, rhs: Self) -> Self { + Int(self.0 + rhs.0) + } +} + +fn main() {} diff --git a/tests/ui/rfcs/rfc-2632-const-trait-impl/const-and-non-const-impl.stderr b/tests/ui/rfcs/rfc-2632-const-trait-impl/const-and-non-const-impl.stderr new file mode 100644 index 000000000..4f858d61e --- /dev/null +++ b/tests/ui/rfcs/rfc-2632-const-trait-impl/const-and-non-const-impl.stderr @@ -0,0 +1,20 @@ +error: const `impl` for trait `Add` which is not marked with `#[const_trait]` + --> $DIR/const-and-non-const-impl.rs:7:12 + | +LL | impl const std::ops::Add for i32 { + | ^^^^^^^^^^^^^ + | + = note: marking a trait with `#[const_trait]` ensures all default method bodies are `const` + = note: adding a non-const method body in the future would be a breaking change + +error: const `impl` for trait `Add` which is not marked with `#[const_trait]` + --> $DIR/const-and-non-const-impl.rs:23:12 + | +LL | impl const std::ops::Add for Int { + | ^^^^^^^^^^^^^ + | + = note: marking a trait with `#[const_trait]` ensures all default method bodies are `const` + = note: adding a non-const method body in the future would be a breaking change + +error: aborting due to 2 previous errors + diff --git a/tests/ui/rfcs/rfc-2632-const-trait-impl/const-check-fns-in-const-impl.rs b/tests/ui/rfcs/rfc-2632-const-trait-impl/const-check-fns-in-const-impl.rs new file mode 100644 index 000000000..52984fb6b --- /dev/null +++ b/tests/ui/rfcs/rfc-2632-const-trait-impl/const-check-fns-in-const-impl.rs @@ -0,0 +1,16 @@ +#![feature(const_trait_impl)] + +struct S; +#[const_trait] +trait T { + fn foo(); +} + +fn non_const() {} + +impl const T for S { + fn foo() { non_const() } + //~^ ERROR cannot call non-const fn +} + +fn main() {} diff --git a/tests/ui/rfcs/rfc-2632-const-trait-impl/const-check-fns-in-const-impl.stderr b/tests/ui/rfcs/rfc-2632-const-trait-impl/const-check-fns-in-const-impl.stderr new file mode 100644 index 000000000..c8783de4c --- /dev/null +++ b/tests/ui/rfcs/rfc-2632-const-trait-impl/const-check-fns-in-const-impl.stderr @@ -0,0 +1,11 @@ +error[E0015]: cannot call non-const fn `non_const` in constant functions + --> $DIR/const-check-fns-in-const-impl.rs:12:16 + | +LL | fn foo() { non_const() } + | ^^^^^^^^^^^ + | + = note: calls in constant functions are limited to constant functions, tuple structs and tuple variants + +error: aborting due to previous error + +For more information about this error, try `rustc --explain E0015`. diff --git a/tests/ui/rfcs/rfc-2632-const-trait-impl/const-closure-parse-not-item.rs b/tests/ui/rfcs/rfc-2632-const-trait-impl/const-closure-parse-not-item.rs new file mode 100644 index 000000000..2c99d8bf1 --- /dev/null +++ b/tests/ui/rfcs/rfc-2632-const-trait-impl/const-closure-parse-not-item.rs @@ -0,0 +1,10 @@ +// check-pass + +#![feature(const_trait_impl, const_closures)] +#![allow(incomplete_features)] + +const fn test() -> impl ~const Fn() { + const move || {} +} + +fn main() {} diff --git a/tests/ui/rfcs/rfc-2632-const-trait-impl/const-closure-trait-method-fail.rs b/tests/ui/rfcs/rfc-2632-const-trait-impl/const-closure-trait-method-fail.rs new file mode 100644 index 000000000..b4cc7a9e1 --- /dev/null +++ b/tests/ui/rfcs/rfc-2632-const-trait-impl/const-closure-trait-method-fail.rs @@ -0,0 +1,20 @@ +// known-bug: #110395 + +#![feature(const_trait_impl)] + +#[const_trait] +trait Tr { + fn a(self) -> i32; +} + +impl Tr for () { + fn a(self) -> i32 { 42 } +} + +const fn need_const_closure<T: ~const FnOnce(()) -> i32>(x: T) -> i32 { + x(()) +} + +const _: () = assert!(need_const_closure(Tr::a) == 42); + +fn main() {} diff --git a/tests/ui/rfcs/rfc-2632-const-trait-impl/const-closure-trait-method-fail.stderr b/tests/ui/rfcs/rfc-2632-const-trait-impl/const-closure-trait-method-fail.stderr new file mode 100644 index 000000000..112416a35 --- /dev/null +++ b/tests/ui/rfcs/rfc-2632-const-trait-impl/const-closure-trait-method-fail.stderr @@ -0,0 +1,16 @@ +error[E0277]: the trait bound `(): ~const Tr` is not satisfied in `fn(()) -> i32 {<() as Tr>::a}` + --> $DIR/const-closure-trait-method-fail.rs:18:23 + | +LL | const _: () = assert!(need_const_closure(Tr::a) == 42); + | ^^^^^^^^^^^^^^^^^^^^^^^^^ within `fn(()) -> i32 {<() as Tr>::a}`, the trait `~const Tr` is not implemented for `()` + | +note: the trait `Tr` is implemented for `()`, but that implementation is not `const` + --> $DIR/const-closure-trait-method-fail.rs:18:23 + | +LL | const _: () = assert!(need_const_closure(Tr::a) == 42); + | ^^^^^^^^^^^^^^^^^^^^^^^^^ + = note: required because it appears within the type `fn(()) -> i32 {<() as Tr>::a}` + +error: aborting due to previous error + +For more information about this error, try `rustc --explain E0277`. diff --git a/tests/ui/rfcs/rfc-2632-const-trait-impl/const-closure-trait-method.rs b/tests/ui/rfcs/rfc-2632-const-trait-impl/const-closure-trait-method.rs new file mode 100644 index 000000000..3e6d19088 --- /dev/null +++ b/tests/ui/rfcs/rfc-2632-const-trait-impl/const-closure-trait-method.rs @@ -0,0 +1,19 @@ +// check-pass +#![feature(const_trait_impl)] + +#[const_trait] +trait Tr { + fn a(self) -> i32; +} + +impl const Tr for () { + fn a(self) -> i32 { 42 } +} + +const fn need_const_closure<T: ~const FnOnce(()) -> i32>(x: T) -> i32 { + x(()) +} + +const _: () = assert!(need_const_closure(Tr::a) == 42); + +fn main() {} diff --git a/tests/ui/rfcs/rfc-2632-const-trait-impl/const-closures.rs b/tests/ui/rfcs/rfc-2632-const-trait-impl/const-closures.rs new file mode 100644 index 000000000..7c55b51c8 --- /dev/null +++ b/tests/ui/rfcs/rfc-2632-const-trait-impl/const-closures.rs @@ -0,0 +1,30 @@ +// check-pass + +#![feature(const_trait_impl)] + +const fn answer_p1<F>(f: &F) -> u8 + where + F: ~const FnOnce() -> u8, + F: ~const FnMut() -> u8, + F: ~const Fn() -> u8, +{ + f() * 7 +} + +const fn three() -> u8 { + 3 +} + +const fn answer_p2() -> u8 { + answer_p1(&three) +} + +const fn answer<F: ~const Fn() -> u8>(f: &F) -> u8 { + f() + f() +} + +const ANSWER: u8 = answer(&answer_p2); + +fn main() { + assert_eq!(ANSWER, 42) +} diff --git a/tests/ui/rfcs/rfc-2632-const-trait-impl/const-default-method-bodies.rs b/tests/ui/rfcs/rfc-2632-const-trait-impl/const-default-method-bodies.rs new file mode 100644 index 000000000..140a06a73 --- /dev/null +++ b/tests/ui/rfcs/rfc-2632-const-trait-impl/const-default-method-bodies.rs @@ -0,0 +1,29 @@ +#![feature(const_trait_impl)] + +#[const_trait] +trait ConstDefaultFn: Sized { + fn b(self); + + fn a(self) { + self.b(); + } +} + +struct NonConstImpl; +struct ConstImpl; + +impl ConstDefaultFn for NonConstImpl { + fn b(self) {} +} + +impl const ConstDefaultFn for ConstImpl { + fn b(self) {} +} + +const fn test() { + NonConstImpl.a(); + //~^ ERROR the trait bound + ConstImpl.a(); +} + +fn main() {} diff --git a/tests/ui/rfcs/rfc-2632-const-trait-impl/const-default-method-bodies.stderr b/tests/ui/rfcs/rfc-2632-const-trait-impl/const-default-method-bodies.stderr new file mode 100644 index 000000000..f9d0d1f78 --- /dev/null +++ b/tests/ui/rfcs/rfc-2632-const-trait-impl/const-default-method-bodies.stderr @@ -0,0 +1,15 @@ +error[E0277]: the trait bound `NonConstImpl: ~const ConstDefaultFn` is not satisfied + --> $DIR/const-default-method-bodies.rs:24:18 + | +LL | NonConstImpl.a(); + | ^ the trait `~const ConstDefaultFn` is not implemented for `NonConstImpl` + | +note: the trait `ConstDefaultFn` is implemented for `NonConstImpl`, but that implementation is not `const` + --> $DIR/const-default-method-bodies.rs:24:5 + | +LL | NonConstImpl.a(); + | ^^^^^^^^^^^^ + +error: aborting due to previous error + +For more information about this error, try `rustc --explain E0277`. diff --git a/tests/ui/rfcs/rfc-2632-const-trait-impl/const-drop-bound.rs b/tests/ui/rfcs/rfc-2632-const-trait-impl/const-drop-bound.rs new file mode 100644 index 000000000..948f0efbc --- /dev/null +++ b/tests/ui/rfcs/rfc-2632-const-trait-impl/const-drop-bound.rs @@ -0,0 +1,25 @@ +// check-pass + +#![feature(const_trait_impl)] +#![feature(const_precise_live_drops)] + +use std::marker::Destruct; + +const fn foo<T, E>(res: Result<T, E>) -> Option<T> where E: ~const Destruct { + match res { + Ok(t) => Some(t), + Err(_e) => None, + } +} + +pub struct Foo<T>(T); + +const fn baz<T, E>(res: Result<Foo<T>, Foo<E>>) -> Option<Foo<T>> +where + T: ~const Destruct, + E: ~const Destruct, +{ + foo(res) +} + +fn main() {} diff --git a/tests/ui/rfcs/rfc-2632-const-trait-impl/const-drop-fail-2.precise.stderr b/tests/ui/rfcs/rfc-2632-const-trait-impl/const-drop-fail-2.precise.stderr new file mode 100644 index 000000000..13350a6d1 --- /dev/null +++ b/tests/ui/rfcs/rfc-2632-const-trait-impl/const-drop-fail-2.precise.stderr @@ -0,0 +1,26 @@ +error: const `impl` for trait `Drop` which is not marked with `#[const_trait]` + --> $DIR/const-drop-fail-2.rs:23:25 + | +LL | impl<T: ~const A> const Drop for ConstDropImplWithBounds<T> { + | ^^^^ + | + = note: marking a trait with `#[const_trait]` ensures all default method bodies are `const` + = note: adding a non-const method body in the future would be a breaking change + +error: ~const can only be applied to `#[const_trait]` traits + --> $DIR/const-drop-fail-2.rs:29:26 + | +LL | const fn check<T: ~const Destruct>(_: T) {} + | ^^^^^^^^ + +error: const `impl` for trait `Drop` which is not marked with `#[const_trait]` + --> $DIR/const-drop-fail-2.rs:39:25 + | +LL | impl<T: ~const A> const Drop for ConstDropImplWithNonConstBounds<T> { + | ^^^^ + | + = note: marking a trait with `#[const_trait]` ensures all default method bodies are `const` + = note: adding a non-const method body in the future would be a breaking change + +error: aborting due to 3 previous errors + diff --git a/tests/ui/rfcs/rfc-2632-const-trait-impl/const-drop-fail-2.rs b/tests/ui/rfcs/rfc-2632-const-trait-impl/const-drop-fail-2.rs new file mode 100644 index 000000000..3de9d37d4 --- /dev/null +++ b/tests/ui/rfcs/rfc-2632-const-trait-impl/const-drop-fail-2.rs @@ -0,0 +1,43 @@ +// known-bug: #110395 +#![feature(const_trait_impl)] +#![feature(const_mut_refs)] +#![cfg_attr(precise, feature(const_precise_live_drops))] + +use std::marker::{Destruct, PhantomData}; + +struct NonTrivialDrop; + +impl Drop for NonTrivialDrop { + fn drop(&mut self) { + println!("Non trivial drop"); + } +} + +#[const_trait] +trait A { fn a() { } } + +impl A for NonTrivialDrop {} + +struct ConstDropImplWithBounds<T: ~const A>(PhantomData<T>); + +impl<T: ~const A> const Drop for ConstDropImplWithBounds<T> { + fn drop(&mut self) { + T::a(); + } +} + +const fn check<T: ~const Destruct>(_: T) {} + +const _: () = check::<ConstDropImplWithBounds<NonTrivialDrop>>( + ConstDropImplWithBounds(PhantomData) +); + +struct ConstDropImplWithNonConstBounds<T: A>(PhantomData<T>); + +impl<T: ~const A> const Drop for ConstDropImplWithNonConstBounds<T> { + fn drop(&mut self) { + T::a(); + } +} + +fn main() {} diff --git a/tests/ui/rfcs/rfc-2632-const-trait-impl/const-drop-fail-2.stderr b/tests/ui/rfcs/rfc-2632-const-trait-impl/const-drop-fail-2.stderr new file mode 100644 index 000000000..375f5d2c5 --- /dev/null +++ b/tests/ui/rfcs/rfc-2632-const-trait-impl/const-drop-fail-2.stderr @@ -0,0 +1,50 @@ +error[E0277]: the trait bound `NonTrivialDrop: ~const A` is not satisfied + --> $DIR/const-drop-fail-2.rs:31:23 + | +LL | const _: () = check::<ConstDropImplWithBounds<NonTrivialDrop>>( + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ the trait `~const A` is not implemented for `NonTrivialDrop` + | +note: the trait `A` is implemented for `NonTrivialDrop`, but that implementation is not `const` + --> $DIR/const-drop-fail-2.rs:31:23 + | +LL | const _: () = check::<ConstDropImplWithBounds<NonTrivialDrop>>( + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ +note: required by a bound in `ConstDropImplWithBounds` + --> $DIR/const-drop-fail-2.rs:21:35 + | +LL | struct ConstDropImplWithBounds<T: ~const A>(PhantomData<T>); + | ^^^^^^^^ required by this bound in `ConstDropImplWithBounds` + +error[E0277]: the trait bound `NonTrivialDrop: ~const A` is not satisfied + --> $DIR/const-drop-fail-2.rs:32:5 + | +LL | ConstDropImplWithBounds(PhantomData) + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ the trait `~const A` is not implemented for `NonTrivialDrop` + | +note: the trait `A` is implemented for `NonTrivialDrop`, but that implementation is not `const` + --> $DIR/const-drop-fail-2.rs:32:5 + | +LL | ConstDropImplWithBounds(PhantomData) + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ +note: required by a bound in `ConstDropImplWithBounds` + --> $DIR/const-drop-fail-2.rs:21:35 + | +LL | struct ConstDropImplWithBounds<T: ~const A>(PhantomData<T>); + | ^^^^^^^^ required by this bound in `ConstDropImplWithBounds` + +error[E0367]: `Drop` impl requires `T: ~const A` but the struct it is implemented for does not + --> $DIR/const-drop-fail-2.rs:37:9 + | +LL | impl<T: ~const A> const Drop for ConstDropImplWithNonConstBounds<T> { + | ^^^^^^^^ + | +note: the implementor must specify the same requirement + --> $DIR/const-drop-fail-2.rs:35:1 + | +LL | struct ConstDropImplWithNonConstBounds<T: A>(PhantomData<T>); + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + +error: aborting due to 3 previous errors + +Some errors have detailed explanations: E0277, E0367. +For more information about an error, try `rustc --explain E0277`. diff --git a/tests/ui/rfcs/rfc-2632-const-trait-impl/const-drop-fail-2.stock.stderr b/tests/ui/rfcs/rfc-2632-const-trait-impl/const-drop-fail-2.stock.stderr new file mode 100644 index 000000000..13350a6d1 --- /dev/null +++ b/tests/ui/rfcs/rfc-2632-const-trait-impl/const-drop-fail-2.stock.stderr @@ -0,0 +1,26 @@ +error: const `impl` for trait `Drop` which is not marked with `#[const_trait]` + --> $DIR/const-drop-fail-2.rs:23:25 + | +LL | impl<T: ~const A> const Drop for ConstDropImplWithBounds<T> { + | ^^^^ + | + = note: marking a trait with `#[const_trait]` ensures all default method bodies are `const` + = note: adding a non-const method body in the future would be a breaking change + +error: ~const can only be applied to `#[const_trait]` traits + --> $DIR/const-drop-fail-2.rs:29:26 + | +LL | const fn check<T: ~const Destruct>(_: T) {} + | ^^^^^^^^ + +error: const `impl` for trait `Drop` which is not marked with `#[const_trait]` + --> $DIR/const-drop-fail-2.rs:39:25 + | +LL | impl<T: ~const A> const Drop for ConstDropImplWithNonConstBounds<T> { + | ^^^^ + | + = note: marking a trait with `#[const_trait]` ensures all default method bodies are `const` + = note: adding a non-const method body in the future would be a breaking change + +error: aborting due to 3 previous errors + diff --git a/tests/ui/rfcs/rfc-2632-const-trait-impl/const-drop-fail.precise.stderr b/tests/ui/rfcs/rfc-2632-const-trait-impl/const-drop-fail.precise.stderr new file mode 100644 index 000000000..e745cbd24 --- /dev/null +++ b/tests/ui/rfcs/rfc-2632-const-trait-impl/const-drop-fail.precise.stderr @@ -0,0 +1,58 @@ +error[E0277]: can't drop `NonTrivialDrop` in const contexts + --> $DIR/const-drop-fail.rs:28:23 + | +LL | const _: () = check($exp); + | ^^^^^^^^^^^ the trait `~const Destruct` is not implemented for `NonTrivialDrop` +... +LL | / check_all! { +LL | | NonTrivialDrop, +LL | | ConstImplWithDropGlue(NonTrivialDrop), +LL | | } + | |_- in this macro invocation + | +note: the trait `Destruct` is implemented for `NonTrivialDrop`, but that implementation is not `const` + --> $DIR/const-drop-fail.rs:28:23 + | +LL | const _: () = check($exp); + | ^^^^^^^^^^^ +... +LL | / check_all! { +LL | | NonTrivialDrop, +LL | | ConstImplWithDropGlue(NonTrivialDrop), +LL | | } + | |_- in this macro invocation + = note: this error originates in the macro `check_all` (in Nightly builds, run with -Z macro-backtrace for more info) + +error[E0277]: can't drop `NonTrivialDrop` in const contexts + --> $DIR/const-drop-fail.rs:28:23 + | +LL | const _: () = check($exp); + | ^^^^^^^^^^^ within `ConstImplWithDropGlue`, the trait `~const Destruct` is not implemented for `NonTrivialDrop` +... +LL | / check_all! { +LL | | NonTrivialDrop, +LL | | ConstImplWithDropGlue(NonTrivialDrop), +LL | | } + | |_- in this macro invocation + | +note: the trait `Destruct` is implemented for `NonTrivialDrop`, but that implementation is not `const` + --> $DIR/const-drop-fail.rs:28:23 + | +LL | const _: () = check($exp); + | ^^^^^^^^^^^ +... +LL | / check_all! { +LL | | NonTrivialDrop, +LL | | ConstImplWithDropGlue(NonTrivialDrop), +LL | | } + | |_- in this macro invocation +note: required because it appears within the type `ConstImplWithDropGlue` + --> $DIR/const-drop-fail.rs:18:8 + | +LL | struct ConstImplWithDropGlue(NonTrivialDrop); + | ^^^^^^^^^^^^^^^^^^^^^ + = note: this error originates in the macro `check_all` (in Nightly builds, run with -Z macro-backtrace for more info) + +error: aborting due to 2 previous errors + +For more information about this error, try `rustc --explain E0277`. diff --git a/tests/ui/rfcs/rfc-2632-const-trait-impl/const-drop-fail.rs b/tests/ui/rfcs/rfc-2632-const-trait-impl/const-drop-fail.rs new file mode 100644 index 000000000..1c37648ff --- /dev/null +++ b/tests/ui/rfcs/rfc-2632-const-trait-impl/const-drop-fail.rs @@ -0,0 +1,37 @@ +// known-bug: #110395 + +// revisions: stock precise +#![feature(const_trait_impl)] +#![feature(const_mut_refs)] +#![cfg_attr(precise, feature(const_precise_live_drops))] + +use std::marker::{Destruct, PhantomData}; + +struct NonTrivialDrop; + +impl Drop for NonTrivialDrop { + fn drop(&mut self) { + println!("Non trivial drop"); + } +} + +struct ConstImplWithDropGlue(NonTrivialDrop); + +impl const Drop for ConstImplWithDropGlue { + fn drop(&mut self) {} +} + +const fn check<T: ~const Destruct>(_: T) {} + +macro_rules! check_all { + ($($exp:expr),*$(,)?) => {$( + const _: () = check($exp); + )*}; +} + +check_all! { + NonTrivialDrop, + ConstImplWithDropGlue(NonTrivialDrop), +} + +fn main() {} diff --git a/tests/ui/rfcs/rfc-2632-const-trait-impl/const-drop-fail.stock.stderr b/tests/ui/rfcs/rfc-2632-const-trait-impl/const-drop-fail.stock.stderr new file mode 100644 index 000000000..e745cbd24 --- /dev/null +++ b/tests/ui/rfcs/rfc-2632-const-trait-impl/const-drop-fail.stock.stderr @@ -0,0 +1,58 @@ +error[E0277]: can't drop `NonTrivialDrop` in const contexts + --> $DIR/const-drop-fail.rs:28:23 + | +LL | const _: () = check($exp); + | ^^^^^^^^^^^ the trait `~const Destruct` is not implemented for `NonTrivialDrop` +... +LL | / check_all! { +LL | | NonTrivialDrop, +LL | | ConstImplWithDropGlue(NonTrivialDrop), +LL | | } + | |_- in this macro invocation + | +note: the trait `Destruct` is implemented for `NonTrivialDrop`, but that implementation is not `const` + --> $DIR/const-drop-fail.rs:28:23 + | +LL | const _: () = check($exp); + | ^^^^^^^^^^^ +... +LL | / check_all! { +LL | | NonTrivialDrop, +LL | | ConstImplWithDropGlue(NonTrivialDrop), +LL | | } + | |_- in this macro invocation + = note: this error originates in the macro `check_all` (in Nightly builds, run with -Z macro-backtrace for more info) + +error[E0277]: can't drop `NonTrivialDrop` in const contexts + --> $DIR/const-drop-fail.rs:28:23 + | +LL | const _: () = check($exp); + | ^^^^^^^^^^^ within `ConstImplWithDropGlue`, the trait `~const Destruct` is not implemented for `NonTrivialDrop` +... +LL | / check_all! { +LL | | NonTrivialDrop, +LL | | ConstImplWithDropGlue(NonTrivialDrop), +LL | | } + | |_- in this macro invocation + | +note: the trait `Destruct` is implemented for `NonTrivialDrop`, but that implementation is not `const` + --> $DIR/const-drop-fail.rs:28:23 + | +LL | const _: () = check($exp); + | ^^^^^^^^^^^ +... +LL | / check_all! { +LL | | NonTrivialDrop, +LL | | ConstImplWithDropGlue(NonTrivialDrop), +LL | | } + | |_- in this macro invocation +note: required because it appears within the type `ConstImplWithDropGlue` + --> $DIR/const-drop-fail.rs:18:8 + | +LL | struct ConstImplWithDropGlue(NonTrivialDrop); + | ^^^^^^^^^^^^^^^^^^^^^ + = note: this error originates in the macro `check_all` (in Nightly builds, run with -Z macro-backtrace for more info) + +error: aborting due to 2 previous errors + +For more information about this error, try `rustc --explain E0277`. diff --git a/tests/ui/rfcs/rfc-2632-const-trait-impl/const-drop.rs b/tests/ui/rfcs/rfc-2632-const-trait-impl/const-drop.rs new file mode 100644 index 000000000..b0fc3adf9 --- /dev/null +++ b/tests/ui/rfcs/rfc-2632-const-trait-impl/const-drop.rs @@ -0,0 +1,113 @@ +// run-pass +// revisions: stock precise +#![feature(const_trait_impl)] +#![feature(const_mut_refs)] +#![feature(never_type)] +#![cfg_attr(precise, feature(const_precise_live_drops))] + +use std::marker::Destruct; + +struct S<'a>(&'a mut u8); + +impl<'a> const Drop for S<'a> { + fn drop(&mut self) { + *self.0 += 1; + } +} + +const fn a<T: ~const Destruct>(_: T) {} + +const fn b() -> u8 { + let mut c = 0; + let _ = S(&mut c); + a(S(&mut c)); + c +} + +const C: u8 = b(); + +macro_rules! implements_const_drop { + ($($exp:expr),*$(,)?) => { + $( + const _: () = a($exp); + )* + } +} + +#[allow(dead_code)] +mod t { + pub struct Foo; + pub enum Bar { A } + pub fn foo() {} + pub struct ConstDrop; + + impl const Drop for ConstDrop { + fn drop(&mut self) {} + } + + pub struct HasConstDrop(pub ConstDrop); + pub struct TrivialFields(pub u8, pub i8, pub usize, pub isize); + + #[const_trait] + pub trait SomeTrait { + fn foo(); + } + impl const SomeTrait for () { + fn foo() {} + } + // non-const impl + impl SomeTrait for i32 { + fn foo() {} + } + + pub struct ConstDropWithBound<T: ~const SomeTrait>(pub core::marker::PhantomData<T>); + + impl<T: ~const SomeTrait> const Drop for ConstDropWithBound<T> { + fn drop(&mut self) { + T::foo(); + } + } + + pub struct ConstDropWithNonconstBound<T: SomeTrait>(pub core::marker::PhantomData<T>); + + impl<T: SomeTrait> const Drop for ConstDropWithNonconstBound<T> { + fn drop(&mut self) { + // Note: we DON'T use the `T: SomeTrait` bound + } + } +} + +use t::*; + +implements_const_drop! { + 1u8, + 2, + 3.0, + Foo, + Bar::A, + foo, + ConstDrop, + HasConstDrop(ConstDrop), + TrivialFields(1, 2, 3, 4), + &1, + &1 as *const i32, + ConstDropWithBound::<()>, + ConstDropWithNonconstBound::<i32>, + Result::<i32, !>::Ok(1), +} + +fn main() { + struct HasDropGlue(#[allow(unused_tuple_struct_fields)] Box<u8>); + struct HasDropImpl; + impl Drop for HasDropImpl { + fn drop(&mut self) { + println!("not trivial drop"); + } + } + + // These types should pass because ~const in a non-const context should have no effect. + a(HasDropGlue(Box::new(0))); + a(HasDropImpl); + + assert_eq!(C, 2); +} diff --git a/tests/ui/rfcs/rfc-2632-const-trait-impl/const-impl-norecover.rs b/tests/ui/rfcs/rfc-2632-const-trait-impl/const-impl-norecover.rs new file mode 100644 index 000000000..bed4e9fd1 --- /dev/null +++ b/tests/ui/rfcs/rfc-2632-const-trait-impl/const-impl-norecover.rs @@ -0,0 +1,12 @@ +#![feature(const_trait_impl)] + +struct Foo; + +const impl Foo { //~ ERROR: expected identifier, found keyword + fn bar() {} +} + +fn main() { + // shouldn't error here because we shouldn't have been able to recover above + Foo::bar(); +} diff --git a/tests/ui/rfcs/rfc-2632-const-trait-impl/const-impl-norecover.stderr b/tests/ui/rfcs/rfc-2632-const-trait-impl/const-impl-norecover.stderr new file mode 100644 index 000000000..603f6b7d2 --- /dev/null +++ b/tests/ui/rfcs/rfc-2632-const-trait-impl/const-impl-norecover.stderr @@ -0,0 +1,8 @@ +error: expected identifier, found keyword `impl` + --> $DIR/const-impl-norecover.rs:5:7 + | +LL | const impl Foo { + | ^^^^ expected identifier, found keyword + +error: aborting due to previous error + diff --git a/tests/ui/rfcs/rfc-2632-const-trait-impl/const-impl-recovery.rs b/tests/ui/rfcs/rfc-2632-const-trait-impl/const-impl-recovery.rs new file mode 100644 index 000000000..837124db0 --- /dev/null +++ b/tests/ui/rfcs/rfc-2632-const-trait-impl/const-impl-recovery.rs @@ -0,0 +1,17 @@ +#![feature(const_trait_impl)] + +#[const_trait] +trait Foo {} + +const impl Foo for i32 {} //~ ERROR: expected identifier, found keyword + +#[const_trait] +trait Bar {} + +const impl<T: Foo> Bar for T {} //~ ERROR: expected identifier, found keyword + +const fn still_implements<T: Bar>() {} + +const _: () = still_implements::<i32>(); + +fn main() {} diff --git a/tests/ui/rfcs/rfc-2632-const-trait-impl/const-impl-recovery.stderr b/tests/ui/rfcs/rfc-2632-const-trait-impl/const-impl-recovery.stderr new file mode 100644 index 000000000..7217fc855 --- /dev/null +++ b/tests/ui/rfcs/rfc-2632-const-trait-impl/const-impl-recovery.stderr @@ -0,0 +1,26 @@ +error: expected identifier, found keyword `impl` + --> $DIR/const-impl-recovery.rs:6:7 + | +LL | const impl Foo for i32 {} + | ^^^^ expected identifier, found keyword + | +help: you might have meant to write a const trait impl + | +LL - const impl Foo for i32 {} +LL + impl const Foo for i32 {} + | + +error: expected identifier, found keyword `impl` + --> $DIR/const-impl-recovery.rs:11:7 + | +LL | const impl<T: Foo> Bar for T {} + | ^^^^ expected identifier, found keyword + | +help: you might have meant to write a const trait impl + | +LL - const impl<T: Foo> Bar for T {} +LL + impl<T: Foo> const Bar for T {} + | + +error: aborting due to 2 previous errors + diff --git a/tests/ui/rfcs/rfc-2632-const-trait-impl/const-impl-requires-const-trait.rs b/tests/ui/rfcs/rfc-2632-const-trait-impl/const-impl-requires-const-trait.rs new file mode 100644 index 000000000..2b4963991 --- /dev/null +++ b/tests/ui/rfcs/rfc-2632-const-trait-impl/const-impl-requires-const-trait.rs @@ -0,0 +1,9 @@ +#![feature(const_trait_impl)] + +pub trait A {} +//~^ HELP: mark `A` as const + +impl const A for () {} +//~^ ERROR: const `impl` for trait `A` which is not marked with `#[const_trait]` + +fn main() {} diff --git a/tests/ui/rfcs/rfc-2632-const-trait-impl/const-impl-requires-const-trait.stderr b/tests/ui/rfcs/rfc-2632-const-trait-impl/const-impl-requires-const-trait.stderr new file mode 100644 index 000000000..478adcf3e --- /dev/null +++ b/tests/ui/rfcs/rfc-2632-const-trait-impl/const-impl-requires-const-trait.stderr @@ -0,0 +1,14 @@ +error: const `impl` for trait `A` which is not marked with `#[const_trait]` + --> $DIR/const-impl-requires-const-trait.rs:6:12 + | +LL | pub trait A {} + | - help: mark `A` as const: `#[const_trait]` +... +LL | impl const A for () {} + | ^ + | + = note: marking a trait with `#[const_trait]` ensures all default method bodies are `const` + = note: adding a non-const method body in the future would be a breaking change + +error: aborting due to previous error + diff --git a/tests/ui/rfcs/rfc-2632-const-trait-impl/const-impl-trait.rs b/tests/ui/rfcs/rfc-2632-const-trait-impl/const-impl-trait.rs new file mode 100644 index 000000000..f396deff4 --- /dev/null +++ b/tests/ui/rfcs/rfc-2632-const-trait-impl/const-impl-trait.rs @@ -0,0 +1,55 @@ +// known-bug: #110395 +#![allow(incomplete_features)] +#![feature( + associated_type_bounds, + const_trait_impl, + const_cmp, + return_position_impl_trait_in_trait, +)] + +use std::marker::Destruct; + +const fn cmp(a: &impl ~const PartialEq) -> bool { + a == a +} + +const fn wrap(x: impl ~const PartialEq + ~const Destruct) + -> impl ~const PartialEq + ~const Destruct +{ + x +} + +#[const_trait] +trait Foo { + fn huh() -> impl ~const PartialEq + ~const Destruct + Copy; +} + +impl const Foo for () { + fn huh() -> impl ~const PartialEq + ~const Destruct + Copy { + 123 + } +} + +const _: () = { + assert!(cmp(&0xDEADBEEFu32)); + assert!(cmp(&())); + assert!(wrap(123) == wrap(123)); + assert!(wrap(123) != wrap(456)); + let x = <() as Foo>::huh(); + assert!(x == x); +}; + +#[const_trait] +trait T {} +struct S; +impl const T for S {} + +const fn rpit() -> impl ~const T { S } + +const fn apit(_: impl ~const T + ~const Destruct) {} + +const fn rpit_assoc_bound() -> impl IntoIterator<Item: ~const T> { Some(S) } + +const fn apit_assoc_bound(_: impl IntoIterator<Item: ~const T> + ~const Destruct) {} + +fn main() {} diff --git a/tests/ui/rfcs/rfc-2632-const-trait-impl/const-impl-trait.stderr b/tests/ui/rfcs/rfc-2632-const-trait-impl/const-impl-trait.stderr new file mode 100644 index 000000000..f9078e227 --- /dev/null +++ b/tests/ui/rfcs/rfc-2632-const-trait-impl/const-impl-trait.stderr @@ -0,0 +1,39 @@ +error[E0635]: unknown feature `const_cmp` + --> $DIR/const-impl-trait.rs:6:5 + | +LL | const_cmp, + | ^^^^^^^^^ + +error: ~const can only be applied to `#[const_trait]` traits + --> $DIR/const-impl-trait.rs:12:30 + | +LL | const fn cmp(a: &impl ~const PartialEq) -> bool { + | ^^^^^^^^^ + +error: ~const can only be applied to `#[const_trait]` traits + --> $DIR/const-impl-trait.rs:16:30 + | +LL | const fn wrap(x: impl ~const PartialEq + ~const Destruct) + | ^^^^^^^^^ + +error: ~const can only be applied to `#[const_trait]` traits + --> $DIR/const-impl-trait.rs:17:20 + | +LL | -> impl ~const PartialEq + ~const Destruct + | ^^^^^^^^^ + +error: ~const can only be applied to `#[const_trait]` traits + --> $DIR/const-impl-trait.rs:24:29 + | +LL | fn huh() -> impl ~const PartialEq + ~const Destruct + Copy; + | ^^^^^^^^^ + +error: ~const can only be applied to `#[const_trait]` traits + --> $DIR/const-impl-trait.rs:28:29 + | +LL | fn huh() -> impl ~const PartialEq + ~const Destruct + Copy { + | ^^^^^^^^^ + +error: aborting due to 6 previous errors + +For more information about this error, try `rustc --explain E0635`. diff --git a/tests/ui/rfcs/rfc-2632-const-trait-impl/const_derives/derive-const-gate.rs b/tests/ui/rfcs/rfc-2632-const-trait-impl/const_derives/derive-const-gate.rs new file mode 100644 index 000000000..dba3ad7f8 --- /dev/null +++ b/tests/ui/rfcs/rfc-2632-const-trait-impl/const_derives/derive-const-gate.rs @@ -0,0 +1,5 @@ +#[derive_const(Default)] //~ ERROR use of unstable library feature +//~^ ERROR not marked with `#[const_trait]` +pub struct S; + +fn main() {} diff --git a/tests/ui/rfcs/rfc-2632-const-trait-impl/const_derives/derive-const-gate.stderr b/tests/ui/rfcs/rfc-2632-const-trait-impl/const_derives/derive-const-gate.stderr new file mode 100644 index 000000000..6a81f96d8 --- /dev/null +++ b/tests/ui/rfcs/rfc-2632-const-trait-impl/const_derives/derive-const-gate.stderr @@ -0,0 +1,21 @@ +error[E0658]: use of unstable library feature 'derive_const' + --> $DIR/derive-const-gate.rs:1:3 + | +LL | #[derive_const(Default)] + | ^^^^^^^^^^^^ + | + = help: add `#![feature(derive_const)]` to the crate attributes to enable + +error: const `impl` for trait `Default` which is not marked with `#[const_trait]` + --> $DIR/derive-const-gate.rs:1:16 + | +LL | #[derive_const(Default)] + | ^^^^^^^ + | + = note: marking a trait with `#[const_trait]` ensures all default method bodies are `const` + = note: adding a non-const method body in the future would be a breaking change + = note: this error originates in the derive macro `Default` (in Nightly builds, run with -Z macro-backtrace for more info) + +error: aborting due to 2 previous errors + +For more information about this error, try `rustc --explain E0658`. diff --git a/tests/ui/rfcs/rfc-2632-const-trait-impl/const_derives/derive-const-non-const-type.rs b/tests/ui/rfcs/rfc-2632-const-trait-impl/const_derives/derive-const-non-const-type.rs new file mode 100644 index 000000000..b575ea8da --- /dev/null +++ b/tests/ui/rfcs/rfc-2632-const-trait-impl/const_derives/derive-const-non-const-type.rs @@ -0,0 +1,13 @@ +// known-bug: #110395 +#![feature(derive_const)] + +pub struct A; + +impl Default for A { + fn default() -> A { A } +} + +#[derive_const(Default)] +pub struct S(A); + +fn main() {} diff --git a/tests/ui/rfcs/rfc-2632-const-trait-impl/const_derives/derive-const-non-const-type.stderr b/tests/ui/rfcs/rfc-2632-const-trait-impl/const_derives/derive-const-non-const-type.stderr new file mode 100644 index 000000000..1c69ad431 --- /dev/null +++ b/tests/ui/rfcs/rfc-2632-const-trait-impl/const_derives/derive-const-non-const-type.stderr @@ -0,0 +1,12 @@ +error: const `impl` for trait `Default` which is not marked with `#[const_trait]` + --> $DIR/derive-const-non-const-type.rs:10:16 + | +LL | #[derive_const(Default)] + | ^^^^^^^ + | + = note: marking a trait with `#[const_trait]` ensures all default method bodies are `const` + = note: adding a non-const method body in the future would be a breaking change + = note: this error originates in the derive macro `Default` (in Nightly builds, run with -Z macro-backtrace for more info) + +error: aborting due to previous error + diff --git a/tests/ui/rfcs/rfc-2632-const-trait-impl/const_derives/derive-const-use.rs b/tests/ui/rfcs/rfc-2632-const-trait-impl/const_derives/derive-const-use.rs new file mode 100644 index 000000000..69098542b --- /dev/null +++ b/tests/ui/rfcs/rfc-2632-const-trait-impl/const_derives/derive-const-use.rs @@ -0,0 +1,19 @@ +// known-bug: #110395 +#![feature(const_trait_impl, const_cmp, const_default_impls, derive_const)] + +pub struct A; + +impl const Default for A { + fn default() -> A { A } +} + +impl const PartialEq for A { + fn eq(&self, _: &A) -> bool { true } +} + +#[derive_const(Default, PartialEq)] +pub struct S((), A); + +const _: () = assert!(S((), A) == S::default()); + +fn main() {} diff --git a/tests/ui/rfcs/rfc-2632-const-trait-impl/const_derives/derive-const-use.stderr b/tests/ui/rfcs/rfc-2632-const-trait-impl/const_derives/derive-const-use.stderr new file mode 100644 index 000000000..88054096e --- /dev/null +++ b/tests/ui/rfcs/rfc-2632-const-trait-impl/const_derives/derive-const-use.stderr @@ -0,0 +1,53 @@ +error[E0635]: unknown feature `const_cmp` + --> $DIR/derive-const-use.rs:2:30 + | +LL | #![feature(const_trait_impl, const_cmp, const_default_impls, derive_const)] + | ^^^^^^^^^ + +error[E0635]: unknown feature `const_default_impls` + --> $DIR/derive-const-use.rs:2:41 + | +LL | #![feature(const_trait_impl, const_cmp, const_default_impls, derive_const)] + | ^^^^^^^^^^^^^^^^^^^ + +error: const `impl` for trait `Default` which is not marked with `#[const_trait]` + --> $DIR/derive-const-use.rs:6:12 + | +LL | impl const Default for A { + | ^^^^^^^ + | + = note: marking a trait with `#[const_trait]` ensures all default method bodies are `const` + = note: adding a non-const method body in the future would be a breaking change + +error: const `impl` for trait `PartialEq` which is not marked with `#[const_trait]` + --> $DIR/derive-const-use.rs:10:12 + | +LL | impl const PartialEq for A { + | ^^^^^^^^^ + | + = note: marking a trait with `#[const_trait]` ensures all default method bodies are `const` + = note: adding a non-const method body in the future would be a breaking change + +error: const `impl` for trait `Default` which is not marked with `#[const_trait]` + --> $DIR/derive-const-use.rs:14:16 + | +LL | #[derive_const(Default, PartialEq)] + | ^^^^^^^ + | + = note: marking a trait with `#[const_trait]` ensures all default method bodies are `const` + = note: adding a non-const method body in the future would be a breaking change + = note: this error originates in the derive macro `Default` (in Nightly builds, run with -Z macro-backtrace for more info) + +error: const `impl` for trait `PartialEq` which is not marked with `#[const_trait]` + --> $DIR/derive-const-use.rs:14:25 + | +LL | #[derive_const(Default, PartialEq)] + | ^^^^^^^^^ + | + = note: marking a trait with `#[const_trait]` ensures all default method bodies are `const` + = note: adding a non-const method body in the future would be a breaking change + = note: this error originates in the derive macro `PartialEq` (in Nightly builds, run with -Z macro-backtrace for more info) + +error: aborting due to 6 previous errors + +For more information about this error, try `rustc --explain E0635`. diff --git a/tests/ui/rfcs/rfc-2632-const-trait-impl/const_derives/derive-const-with-params.rs b/tests/ui/rfcs/rfc-2632-const-trait-impl/const_derives/derive-const-with-params.rs new file mode 100644 index 000000000..2a5d0176b --- /dev/null +++ b/tests/ui/rfcs/rfc-2632-const-trait-impl/const_derives/derive-const-with-params.rs @@ -0,0 +1,13 @@ +// known-bug: #110395 + +#![feature(derive_const)] +#![feature(const_trait_impl)] + +#[derive_const(PartialEq)] +pub struct Reverse<T>(T); + +const fn foo(a: Reverse<i32>, b: Reverse<i32>) -> bool { + a == b +} + +fn main() {} diff --git a/tests/ui/rfcs/rfc-2632-const-trait-impl/const_derives/derive-const-with-params.stderr b/tests/ui/rfcs/rfc-2632-const-trait-impl/const_derives/derive-const-with-params.stderr new file mode 100644 index 000000000..fa7832658 --- /dev/null +++ b/tests/ui/rfcs/rfc-2632-const-trait-impl/const_derives/derive-const-with-params.stderr @@ -0,0 +1,20 @@ +error: const `impl` for trait `PartialEq` which is not marked with `#[const_trait]` + --> $DIR/derive-const-with-params.rs:6:16 + | +LL | #[derive_const(PartialEq)] + | ^^^^^^^^^ + | + = note: marking a trait with `#[const_trait]` ensures all default method bodies are `const` + = note: adding a non-const method body in the future would be a breaking change + = note: this error originates in the derive macro `PartialEq` (in Nightly builds, run with -Z macro-backtrace for more info) + +error: ~const can only be applied to `#[const_trait]` traits + --> $DIR/derive-const-with-params.rs:6:16 + | +LL | #[derive_const(PartialEq)] + | ^^^^^^^^^ + | + = note: this error originates in the derive macro `PartialEq` (in Nightly builds, run with -Z macro-backtrace for more info) + +error: aborting due to 2 previous errors + diff --git a/tests/ui/rfcs/rfc-2632-const-trait-impl/cross-crate-default-method-body-is-const.rs b/tests/ui/rfcs/rfc-2632-const-trait-impl/cross-crate-default-method-body-is-const.rs new file mode 100644 index 000000000..bde8bf20f --- /dev/null +++ b/tests/ui/rfcs/rfc-2632-const-trait-impl/cross-crate-default-method-body-is-const.rs @@ -0,0 +1,18 @@ +// This tests that `const_trait` default methods can +// be called from a const context when used across crates. +// +// check-pass + +#![feature(const_trait_impl)] + +// aux-build: cross-crate.rs +extern crate cross_crate; + +use cross_crate::*; + +const _: () = { + Const.func(); + Const.defaulted_func(); +}; + +fn main() {} diff --git a/tests/ui/rfcs/rfc-2632-const-trait-impl/cross-crate.gatednc.stderr b/tests/ui/rfcs/rfc-2632-const-trait-impl/cross-crate.gatednc.stderr new file mode 100644 index 000000000..633b7cc25 --- /dev/null +++ b/tests/ui/rfcs/rfc-2632-const-trait-impl/cross-crate.gatednc.stderr @@ -0,0 +1,15 @@ +error[E0277]: the trait bound `cross_crate::NonConst: ~const cross_crate::MyTrait` is not satisfied + --> $DIR/cross-crate.rs:17:14 + | +LL | NonConst.func(); + | ^^^^ the trait `~const cross_crate::MyTrait` is not implemented for `cross_crate::NonConst` + | +note: the trait `cross_crate::MyTrait` is implemented for `cross_crate::NonConst`, but that implementation is not `const` + --> $DIR/cross-crate.rs:17:5 + | +LL | NonConst.func(); + | ^^^^^^^^ + +error: aborting due to previous error + +For more information about this error, try `rustc --explain E0277`. diff --git a/tests/ui/rfcs/rfc-2632-const-trait-impl/cross-crate.rs b/tests/ui/rfcs/rfc-2632-const-trait-impl/cross-crate.rs new file mode 100644 index 000000000..6df47022c --- /dev/null +++ b/tests/ui/rfcs/rfc-2632-const-trait-impl/cross-crate.rs @@ -0,0 +1,24 @@ +// revisions: stock gated stocknc gatednc +// [gated] check-pass +#![cfg_attr(any(gated, gatednc), feature(const_trait_impl))] + +// aux-build: cross-crate.rs +extern crate cross_crate; + +use cross_crate::*; + +fn non_const_context() { + NonConst.func(); + Const.func(); +} + +const fn const_context() { + #[cfg(any(stocknc, gatednc))] + NonConst.func(); + //[stocknc]~^ ERROR: the trait bound + //[gatednc]~^^ ERROR: the trait bound + Const.func(); + //[stock]~^ ERROR: cannot call +} + +fn main() {} diff --git a/tests/ui/rfcs/rfc-2632-const-trait-impl/cross-crate.stock.stderr b/tests/ui/rfcs/rfc-2632-const-trait-impl/cross-crate.stock.stderr new file mode 100644 index 000000000..22f13a741 --- /dev/null +++ b/tests/ui/rfcs/rfc-2632-const-trait-impl/cross-crate.stock.stderr @@ -0,0 +1,12 @@ +error[E0015]: cannot call non-const fn `<cross_crate::Const as cross_crate::MyTrait>::func` in constant functions + --> $DIR/cross-crate.rs:20:11 + | +LL | Const.func(); + | ^^^^^^ + | + = note: calls in constant functions are limited to constant functions, tuple structs and tuple variants + = help: add `#![feature(const_trait_impl)]` to the crate attributes to enable + +error: aborting due to previous error + +For more information about this error, try `rustc --explain E0015`. diff --git a/tests/ui/rfcs/rfc-2632-const-trait-impl/cross-crate.stocknc.stderr b/tests/ui/rfcs/rfc-2632-const-trait-impl/cross-crate.stocknc.stderr new file mode 100644 index 000000000..9e97d3f11 --- /dev/null +++ b/tests/ui/rfcs/rfc-2632-const-trait-impl/cross-crate.stocknc.stderr @@ -0,0 +1,15 @@ +error[E0277]: the trait bound `cross_crate::NonConst: cross_crate::MyTrait` is not satisfied + --> $DIR/cross-crate.rs:17:14 + | +LL | NonConst.func(); + | ^^^^ the trait `~const cross_crate::MyTrait` is not implemented for `cross_crate::NonConst` + | +note: the trait `cross_crate::MyTrait` is implemented for `cross_crate::NonConst`, but that implementation is not `const` + --> $DIR/cross-crate.rs:17:5 + | +LL | NonConst.func(); + | ^^^^^^^^ + +error: aborting due to previous error + +For more information about this error, try `rustc --explain E0277`. diff --git a/tests/ui/rfcs/rfc-2632-const-trait-impl/default-method-body-is-const-body-checking.rs b/tests/ui/rfcs/rfc-2632-const-trait-impl/default-method-body-is-const-body-checking.rs new file mode 100644 index 000000000..96acdc300 --- /dev/null +++ b/tests/ui/rfcs/rfc-2632-const-trait-impl/default-method-body-is-const-body-checking.rs @@ -0,0 +1,17 @@ +#![feature(const_trait_impl)] + +#[const_trait] +trait Tr {} +impl Tr for () {} + +const fn foo<T>() where T: ~const Tr {} + +#[const_trait] +pub trait Foo { + fn foo() { + foo::<()>(); + //~^ ERROR the trait bound `(): ~const Tr` is not satisfied + } +} + +fn main() {} diff --git a/tests/ui/rfcs/rfc-2632-const-trait-impl/default-method-body-is-const-body-checking.stderr b/tests/ui/rfcs/rfc-2632-const-trait-impl/default-method-body-is-const-body-checking.stderr new file mode 100644 index 000000000..26644f72c --- /dev/null +++ b/tests/ui/rfcs/rfc-2632-const-trait-impl/default-method-body-is-const-body-checking.stderr @@ -0,0 +1,15 @@ +error[E0277]: the trait bound `(): ~const Tr` is not satisfied + --> $DIR/default-method-body-is-const-body-checking.rs:12:9 + | +LL | foo::<()>(); + | ^^^^^^^^^^^ the trait `~const Tr` is not implemented for `()` + | +note: the trait `Tr` is implemented for `()`, but that implementation is not `const` + --> $DIR/default-method-body-is-const-body-checking.rs:12:9 + | +LL | foo::<()>(); + | ^^^^^^^^^^^ + +error: aborting due to previous error + +For more information about this error, try `rustc --explain E0277`. diff --git a/tests/ui/rfcs/rfc-2632-const-trait-impl/default-method-body-is-const-same-trait-ck.rs b/tests/ui/rfcs/rfc-2632-const-trait-impl/default-method-body-is-const-same-trait-ck.rs new file mode 100644 index 000000000..f70ecbc37 --- /dev/null +++ b/tests/ui/rfcs/rfc-2632-const-trait-impl/default-method-body-is-const-same-trait-ck.rs @@ -0,0 +1,15 @@ +#![feature(const_trait_impl)] + +#[const_trait] +pub trait Tr { + fn a(&self) {} + + fn b(&self) { + ().a() + //~^ ERROR the trait bound + } +} + +impl Tr for () {} + +fn main() {} diff --git a/tests/ui/rfcs/rfc-2632-const-trait-impl/default-method-body-is-const-same-trait-ck.stderr b/tests/ui/rfcs/rfc-2632-const-trait-impl/default-method-body-is-const-same-trait-ck.stderr new file mode 100644 index 000000000..21ecddaff --- /dev/null +++ b/tests/ui/rfcs/rfc-2632-const-trait-impl/default-method-body-is-const-same-trait-ck.stderr @@ -0,0 +1,15 @@ +error[E0277]: the trait bound `(): ~const Tr` is not satisfied + --> $DIR/default-method-body-is-const-same-trait-ck.rs:8:12 + | +LL | ().a() + | ^ the trait `~const Tr` is not implemented for `()` + | +note: the trait `Tr` is implemented for `()`, but that implementation is not `const` + --> $DIR/default-method-body-is-const-same-trait-ck.rs:8:9 + | +LL | ().a() + | ^^ + +error: aborting due to previous error + +For more information about this error, try `rustc --explain E0277`. diff --git a/tests/ui/rfcs/rfc-2632-const-trait-impl/default-method-body-is-const-with-staged-api.rs b/tests/ui/rfcs/rfc-2632-const-trait-impl/default-method-body-is-const-with-staged-api.rs new file mode 100644 index 000000000..1b45cd9aa --- /dev/null +++ b/tests/ui/rfcs/rfc-2632-const-trait-impl/default-method-body-is-const-with-staged-api.rs @@ -0,0 +1,17 @@ +// check-pass + +// This was an ICE, because the compiler ensures the +// function to be const when performing const checking, +// but functions marked with the attribute are not const +// *and* subject to const checking. + +#![feature(staged_api)] +#![feature(const_trait_impl)] +#![stable(since = "1", feature = "foo")] + +#[const_trait] +trait Tr { + fn a() {} +} + +fn main() {} diff --git a/tests/ui/rfcs/rfc-2632-const-trait-impl/do-not-const-check-override.rs b/tests/ui/rfcs/rfc-2632-const-trait-impl/do-not-const-check-override.rs new file mode 100644 index 000000000..730e268c0 --- /dev/null +++ b/tests/ui/rfcs/rfc-2632-const-trait-impl/do-not-const-check-override.rs @@ -0,0 +1,19 @@ +// check-pass +#![feature(const_trait_impl, rustc_attrs)] + +#[const_trait] +trait Foo { + #[rustc_do_not_const_check] + fn into_iter(&self) { println!("FEAR ME!") } +} + + +impl const Foo for () { + fn into_iter(&self) { + // ^_^ + } +} + +const _: () = Foo::into_iter(&()); + +fn main() {} diff --git a/tests/ui/rfcs/rfc-2632-const-trait-impl/do-not-const-check.rs b/tests/ui/rfcs/rfc-2632-const-trait-impl/do-not-const-check.rs new file mode 100644 index 000000000..3c39c53de --- /dev/null +++ b/tests/ui/rfcs/rfc-2632-const-trait-impl/do-not-const-check.rs @@ -0,0 +1,18 @@ +// check-pass +#![feature(const_trait_impl, rustc_attrs)] + +#[const_trait] +trait IntoIter { + fn into_iter(self); +} + +#[const_trait] +trait Hmm: Sized { + #[rustc_do_not_const_check] + fn chain<U>(self, other: U) where U: IntoIter, + { + other.into_iter() + } +} + +fn main() {} diff --git a/tests/ui/rfcs/rfc-2632-const-trait-impl/effects/helloworld.rs b/tests/ui/rfcs/rfc-2632-const-trait-impl/effects/helloworld.rs new file mode 100644 index 000000000..49457354c --- /dev/null +++ b/tests/ui/rfcs/rfc-2632-const-trait-impl/effects/helloworld.rs @@ -0,0 +1,29 @@ +// check-pass + +// gate-test-effects +// ^ effects doesn't have a gate so we will trick tidy into thinking this is a gate test + +#![feature(const_trait_impl, effects, rustc_attrs)] + +// ensure we are passing in the correct host effect in always const contexts. + +pub const fn hmm</* T, */ #[rustc_host] const host: bool = true>() -> usize { + if host { + 1 + } else { + 0 + } +} + +const _: () = { + let x = hmm(); + assert!(0 == x); +}; + +/* FIXME(effects) +pub const fn uwu(x: [u8; hmm::<()>()]) { + let [] = x; +} +*/ + +fn main() {} diff --git a/tests/ui/rfcs/rfc-2632-const-trait-impl/feature-gate.gated.stderr b/tests/ui/rfcs/rfc-2632-const-trait-impl/feature-gate.gated.stderr new file mode 100644 index 000000000..4c630d33c --- /dev/null +++ b/tests/ui/rfcs/rfc-2632-const-trait-impl/feature-gate.gated.stderr @@ -0,0 +1,8 @@ +error: fatal error triggered by #[rustc_error] + --> $DIR/feature-gate.rs:14:1 + | +LL | fn main() {} + | ^^^^^^^^^ + +error: aborting due to previous error + diff --git a/tests/ui/rfcs/rfc-2632-const-trait-impl/feature-gate.rs b/tests/ui/rfcs/rfc-2632-const-trait-impl/feature-gate.rs new file mode 100644 index 000000000..0b409fbaa --- /dev/null +++ b/tests/ui/rfcs/rfc-2632-const-trait-impl/feature-gate.rs @@ -0,0 +1,14 @@ +// revisions: stock gated +// gate-test-const_trait_impl + +#![cfg_attr(gated, feature(const_trait_impl))] +#![feature(rustc_attrs)] + +struct S; +#[const_trait] //[stock]~ ERROR `const_trait` is a temporary placeholder +trait T {} +impl const T for S {} +//[stock]~^ ERROR const trait impls are experimental + +#[rustc_error] +fn main() {} //[gated]~ ERROR fatal error triggered by #[rustc_error] diff --git a/tests/ui/rfcs/rfc-2632-const-trait-impl/feature-gate.stock.stderr b/tests/ui/rfcs/rfc-2632-const-trait-impl/feature-gate.stock.stderr new file mode 100644 index 000000000..0e938c1c5 --- /dev/null +++ b/tests/ui/rfcs/rfc-2632-const-trait-impl/feature-gate.stock.stderr @@ -0,0 +1,21 @@ +error[E0658]: const trait impls are experimental + --> $DIR/feature-gate.rs:10:6 + | +LL | impl const T for S {} + | ^^^^^ + | + = note: see issue #67792 <https://github.com/rust-lang/rust/issues/67792> for more information + = help: add `#![feature(const_trait_impl)]` to the crate attributes to enable + +error[E0658]: `const_trait` is a temporary placeholder for marking a trait that is suitable for `const` `impls` and all default bodies as `const`, which may be removed or renamed in the future. + --> $DIR/feature-gate.rs:8:1 + | +LL | #[const_trait] + | ^^^^^^^^^^^^^^ + | + = note: see issue #67792 <https://github.com/rust-lang/rust/issues/67792> for more information + = help: add `#![feature(const_trait_impl)]` to the crate attributes to enable + +error: aborting due to 2 previous errors + +For more information about this error, try `rustc --explain E0658`. diff --git a/tests/ui/rfcs/rfc-2632-const-trait-impl/function-pointer-does-not-require-const.rs b/tests/ui/rfcs/rfc-2632-const-trait-impl/function-pointer-does-not-require-const.rs new file mode 100644 index 000000000..60790e297 --- /dev/null +++ b/tests/ui/rfcs/rfc-2632-const-trait-impl/function-pointer-does-not-require-const.rs @@ -0,0 +1,15 @@ +// check-pass +#![feature(const_trait_impl)] + +#[const_trait] +pub trait Test {} + +impl Test for () {} + +pub const fn test<T: ~const Test>() {} + +pub const fn min_by_i32() -> fn() { + test::<()> +} + +fn main() {} diff --git a/tests/ui/rfcs/rfc-2632-const-trait-impl/gate.rs b/tests/ui/rfcs/rfc-2632-const-trait-impl/gate.rs new file mode 100644 index 000000000..d1c93ab9f --- /dev/null +++ b/tests/ui/rfcs/rfc-2632-const-trait-impl/gate.rs @@ -0,0 +1,13 @@ +// gate-test-const_closures + +fn main() { + (const || {})(); + //~^ ERROR: const closures are experimental +} + +macro_rules! e { + ($e:expr) => {} +} + +e!((const || {})); +//~^ ERROR const closures are experimental diff --git a/tests/ui/rfcs/rfc-2632-const-trait-impl/gate.stderr b/tests/ui/rfcs/rfc-2632-const-trait-impl/gate.stderr new file mode 100644 index 000000000..11cc2cd56 --- /dev/null +++ b/tests/ui/rfcs/rfc-2632-const-trait-impl/gate.stderr @@ -0,0 +1,21 @@ +error[E0658]: const closures are experimental + --> $DIR/gate.rs:4:6 + | +LL | (const || {})(); + | ^^^^^ + | + = note: see issue #106003 <https://github.com/rust-lang/rust/issues/106003> for more information + = help: add `#![feature(const_closures)]` to the crate attributes to enable + +error[E0658]: const closures are experimental + --> $DIR/gate.rs:12:5 + | +LL | e!((const || {})); + | ^^^^^ + | + = note: see issue #106003 <https://github.com/rust-lang/rust/issues/106003> for more information + = help: add `#![feature(const_closures)]` to the crate attributes to enable + +error: aborting due to 2 previous errors + +For more information about this error, try `rustc --explain E0658`. diff --git a/tests/ui/rfcs/rfc-2632-const-trait-impl/generic-bound.rs b/tests/ui/rfcs/rfc-2632-const-trait-impl/generic-bound.rs new file mode 100644 index 000000000..d665c4479 --- /dev/null +++ b/tests/ui/rfcs/rfc-2632-const-trait-impl/generic-bound.rs @@ -0,0 +1,30 @@ +// known-bug: #110395 + +#![feature(const_trait_impl)] + +use std::marker::PhantomData; + +struct S<T>(PhantomData<T>); + +impl<T> Copy for S<T> {} +impl<T> Clone for S<T> { + fn clone(&self) -> Self { + S(PhantomData) + } +} + +impl<T> const std::ops::Add for S<T> { + type Output = Self; + + fn add(self, _: Self) -> Self { + S(std::marker::PhantomData) + } +} + +const fn twice<T: std::ops::Add>(arg: S<T>) -> S<T> { + arg + arg +} + +fn main() { + let _ = twice(S(PhantomData::<i32>)); +} diff --git a/tests/ui/rfcs/rfc-2632-const-trait-impl/generic-bound.stderr b/tests/ui/rfcs/rfc-2632-const-trait-impl/generic-bound.stderr new file mode 100644 index 000000000..1b21d7c0e --- /dev/null +++ b/tests/ui/rfcs/rfc-2632-const-trait-impl/generic-bound.stderr @@ -0,0 +1,11 @@ +error: const `impl` for trait `Add` which is not marked with `#[const_trait]` + --> $DIR/generic-bound.rs:16:15 + | +LL | impl<T> const std::ops::Add for S<T> { + | ^^^^^^^^^^^^^ + | + = note: marking a trait with `#[const_trait]` ensures all default method bodies are `const` + = note: adding a non-const method body in the future would be a breaking change + +error: aborting due to previous error + diff --git a/tests/ui/rfcs/rfc-2632-const-trait-impl/hir-const-check.rs b/tests/ui/rfcs/rfc-2632-const-trait-impl/hir-const-check.rs new file mode 100644 index 000000000..337c73340 --- /dev/null +++ b/tests/ui/rfcs/rfc-2632-const-trait-impl/hir-const-check.rs @@ -0,0 +1,17 @@ +// Regression test for #69615. + +#![feature(const_trait_impl)] + +#[const_trait] +pub trait MyTrait { + fn method(&self) -> Option<()>; +} + +impl const MyTrait for () { + fn method(&self) -> Option<()> { + Some(())?; //~ ERROR `?` is not allowed in a `const fn` + None + } +} + +fn main() {} diff --git a/tests/ui/rfcs/rfc-2632-const-trait-impl/hir-const-check.stderr b/tests/ui/rfcs/rfc-2632-const-trait-impl/hir-const-check.stderr new file mode 100644 index 000000000..6d2be1daa --- /dev/null +++ b/tests/ui/rfcs/rfc-2632-const-trait-impl/hir-const-check.stderr @@ -0,0 +1,12 @@ +error[E0658]: `?` is not allowed in a `const fn` + --> $DIR/hir-const-check.rs:12:9 + | +LL | Some(())?; + | ^^^^^^^^^ + | + = note: see issue #74935 <https://github.com/rust-lang/rust/issues/74935> for more information + = help: add `#![feature(const_try)]` 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/tests/ui/rfcs/rfc-2632-const-trait-impl/impl-tilde-const-trait.rs b/tests/ui/rfcs/rfc-2632-const-trait-impl/impl-tilde-const-trait.rs new file mode 100644 index 000000000..05b26465c --- /dev/null +++ b/tests/ui/rfcs/rfc-2632-const-trait-impl/impl-tilde-const-trait.rs @@ -0,0 +1,9 @@ +#![feature(const_trait_impl)] + +struct S; +trait T {} + +impl ~const T for S {} +//~^ ERROR expected a trait, found type + +fn main() {} diff --git a/tests/ui/rfcs/rfc-2632-const-trait-impl/impl-tilde-const-trait.stderr b/tests/ui/rfcs/rfc-2632-const-trait-impl/impl-tilde-const-trait.stderr new file mode 100644 index 000000000..0a91719e1 --- /dev/null +++ b/tests/ui/rfcs/rfc-2632-const-trait-impl/impl-tilde-const-trait.stderr @@ -0,0 +1,8 @@ +error: expected a trait, found type + --> $DIR/impl-tilde-const-trait.rs:6:6 + | +LL | impl ~const T for S {} + | ^^^^^^^^ + +error: aborting due to previous error + diff --git a/tests/ui/rfcs/rfc-2632-const-trait-impl/impl-with-default-fn-fail.rs b/tests/ui/rfcs/rfc-2632-const-trait-impl/impl-with-default-fn-fail.rs new file mode 100644 index 000000000..6df9696f2 --- /dev/null +++ b/tests/ui/rfcs/rfc-2632-const-trait-impl/impl-with-default-fn-fail.rs @@ -0,0 +1,17 @@ +#![feature(const_trait_impl)] + +#[const_trait] +trait Tr { + fn req(&self); + + fn default() {} +} + +struct S; + +impl const Tr for u16 { + fn default() {} +} //~^^ ERROR not all trait items implemented + + +fn main() {} diff --git a/tests/ui/rfcs/rfc-2632-const-trait-impl/impl-with-default-fn-fail.stderr b/tests/ui/rfcs/rfc-2632-const-trait-impl/impl-with-default-fn-fail.stderr new file mode 100644 index 000000000..6c6ca9f5d --- /dev/null +++ b/tests/ui/rfcs/rfc-2632-const-trait-impl/impl-with-default-fn-fail.stderr @@ -0,0 +1,12 @@ +error[E0046]: not all trait items implemented, missing: `req` + --> $DIR/impl-with-default-fn-fail.rs:12:1 + | +LL | fn req(&self); + | -------------- `req` from trait +... +LL | impl const Tr for u16 { + | ^^^^^^^^^^^^^^^^^^^^^ missing `req` in implementation + +error: aborting due to previous error + +For more information about this error, try `rustc --explain E0046`. diff --git a/tests/ui/rfcs/rfc-2632-const-trait-impl/impl-with-default-fn-pass.rs b/tests/ui/rfcs/rfc-2632-const-trait-impl/impl-with-default-fn-pass.rs new file mode 100644 index 000000000..ae81421e9 --- /dev/null +++ b/tests/ui/rfcs/rfc-2632-const-trait-impl/impl-with-default-fn-pass.rs @@ -0,0 +1,26 @@ +// check-pass + +#![feature(const_trait_impl)] + +#[const_trait] +trait Tr { + fn req(&self); + + fn default() {} +} + +impl const Tr for u8 { + fn req(&self) {} +} + +macro_rules! impl_tr { + ($ty: ty) => { + impl const Tr for $ty { + fn req(&self) {} + } + } +} + +impl_tr!(u64); + +fn main() {} diff --git a/tests/ui/rfcs/rfc-2632-const-trait-impl/inherent-impl-const-bounds.rs b/tests/ui/rfcs/rfc-2632-const-trait-impl/inherent-impl-const-bounds.rs new file mode 100644 index 000000000..f8ac793e4 --- /dev/null +++ b/tests/ui/rfcs/rfc-2632-const-trait-impl/inherent-impl-const-bounds.rs @@ -0,0 +1,22 @@ +// check-pass +#![feature(const_trait_impl)] + +struct S; + +#[const_trait] +trait A {} +#[const_trait] +trait B {} + +impl const A for S {} +impl const B for S {} + +impl S { + const fn a<T: ~const A>() where T: ~const B { + + } +} + +const _: () = S::a::<S>(); + +fn main() {} diff --git a/tests/ui/rfcs/rfc-2632-const-trait-impl/inherent-impl.rs b/tests/ui/rfcs/rfc-2632-const-trait-impl/inherent-impl.rs new file mode 100644 index 000000000..afd0d137b --- /dev/null +++ b/tests/ui/rfcs/rfc-2632-const-trait-impl/inherent-impl.rs @@ -0,0 +1,13 @@ +#![feature(const_trait_impl)] +#![allow(bare_trait_objects)] + +struct S; +trait T {} + +impl const S {} +//~^ ERROR inherent impls cannot be `const` + +impl const T {} +//~^ ERROR inherent impls cannot be `const` + +fn main() {} diff --git a/tests/ui/rfcs/rfc-2632-const-trait-impl/inherent-impl.stderr b/tests/ui/rfcs/rfc-2632-const-trait-impl/inherent-impl.stderr new file mode 100644 index 000000000..8c5562703 --- /dev/null +++ b/tests/ui/rfcs/rfc-2632-const-trait-impl/inherent-impl.stderr @@ -0,0 +1,22 @@ +error: inherent impls cannot be `const` + --> $DIR/inherent-impl.rs:7:12 + | +LL | impl const S {} + | ----- ^ inherent impl for this type + | | + | `const` because of this + | + = note: only trait implementations may be annotated with `const` + +error: inherent impls cannot be `const` + --> $DIR/inherent-impl.rs:10:12 + | +LL | impl const T {} + | ----- ^ inherent impl for this type + | | + | `const` because of this + | + = note: only trait implementations may be annotated with `const` + +error: aborting due to 2 previous errors + diff --git a/tests/ui/rfcs/rfc-2632-const-trait-impl/issue-100222.rs b/tests/ui/rfcs/rfc-2632-const-trait-impl/issue-100222.rs new file mode 100644 index 000000000..9f3f38ad4 --- /dev/null +++ b/tests/ui/rfcs/rfc-2632-const-trait-impl/issue-100222.rs @@ -0,0 +1,39 @@ +// revisions: nn ny yn yy +// check-pass +#![feature(const_trait_impl, associated_type_defaults, const_mut_refs)] + +#[cfg_attr(any(yn, yy), const_trait)] +pub trait Index { + type Output; +} + +#[cfg_attr(any(ny, yy), const_trait)] +pub trait IndexMut where Self: Index { + const C: <Self as Index>::Output; + type Assoc = <Self as Index>::Output; + fn foo(&mut self, x: <Self as Index>::Output) -> <Self as Index>::Output; +} + +impl Index for () { type Output = (); } + +#[cfg(not(any(nn, yn)))] +impl const IndexMut for <() as Index>::Output { + const C: <Self as Index>::Output = (); + type Assoc = <Self as Index>::Output; + fn foo(&mut self, x: <Self as Index>::Output) -> <Self as Index>::Output + where <Self as Index>::Output:, + {} +} + +#[cfg(any(nn, yn))] +impl IndexMut for <() as Index>::Output { + const C: <Self as Index>::Output = (); + type Assoc = <Self as Index>::Output; + fn foo(&mut self, x: <Self as Index>::Output) -> <Self as Index>::Output + where <Self as Index>::Output:, + {} +} + +const C: <() as Index>::Output = (); + +fn main() {} diff --git a/tests/ui/rfcs/rfc-2632-const-trait-impl/issue-102156.rs b/tests/ui/rfcs/rfc-2632-const-trait-impl/issue-102156.rs new file mode 100644 index 000000000..fe4e91081 --- /dev/null +++ b/tests/ui/rfcs/rfc-2632-const-trait-impl/issue-102156.rs @@ -0,0 +1,15 @@ +#![feature(allocator_api)] +#![feature(const_trait_impl)] + +use core::convert::{From, TryFrom}; +//~^ ERROR +//~| ERROR + +use std::pin::Pin; +use std::alloc::Allocator; +impl<T: ?Sized, A: Allocator> const From<Box<T, A>> for Pin<Box<T, A>> +where + A: 'static, +{} + +pub fn main() {} diff --git a/tests/ui/rfcs/rfc-2632-const-trait-impl/issue-102156.stderr b/tests/ui/rfcs/rfc-2632-const-trait-impl/issue-102156.stderr new file mode 100644 index 000000000..8bf00eaff --- /dev/null +++ b/tests/ui/rfcs/rfc-2632-const-trait-impl/issue-102156.stderr @@ -0,0 +1,19 @@ +error[E0433]: failed to resolve: maybe a missing crate `core`? + --> $DIR/issue-102156.rs:4:5 + | +LL | use core::convert::{From, TryFrom}; + | ^^^^ maybe a missing crate `core`? + | + = help: consider adding `extern crate core` to use the `core` crate + +error[E0433]: failed to resolve: maybe a missing crate `core`? + --> $DIR/issue-102156.rs:4:5 + | +LL | use core::convert::{From, TryFrom}; + | ^^^^ maybe a missing crate `core`? + | + = help: consider adding `extern crate core` to use the `core` crate + +error: aborting due to 2 previous errors + +For more information about this error, try `rustc --explain E0433`. diff --git a/tests/ui/rfcs/rfc-2632-const-trait-impl/issue-102985.rs b/tests/ui/rfcs/rfc-2632-const-trait-impl/issue-102985.rs new file mode 100644 index 000000000..07d3f51ed --- /dev/null +++ b/tests/ui/rfcs/rfc-2632-const-trait-impl/issue-102985.rs @@ -0,0 +1,12 @@ +#![feature(const_trait_impl)] + +struct Bug { + inner: [(); match || 1 { + n => n(), + //~^ ERROR the trait bound + //~| ERROR the trait bound + //~| ERROR cannot call non-const closure in constants + }], +} + +fn main() {} diff --git a/tests/ui/rfcs/rfc-2632-const-trait-impl/issue-102985.stderr b/tests/ui/rfcs/rfc-2632-const-trait-impl/issue-102985.stderr new file mode 100644 index 000000000..b98ccbe5d --- /dev/null +++ b/tests/ui/rfcs/rfc-2632-const-trait-impl/issue-102985.stderr @@ -0,0 +1,41 @@ +error[E0277]: the trait bound `[closure@$DIR/issue-102985.rs:4:23: 4:25]: ~const Fn<()>` is not satisfied + --> $DIR/issue-102985.rs:5:14 + | +LL | n => n(), + | ^^^ expected an `Fn<()>` closure, found `[closure@$DIR/issue-102985.rs:4:23: 4:25]` + | + = help: the trait `~const Fn<()>` is not implemented for closure `[closure@$DIR/issue-102985.rs:4:23: 4:25]` +note: the trait `Fn<()>` is implemented for `[closure@$DIR/issue-102985.rs:4:23: 4:25]`, but that implementation is not `const` + --> $DIR/issue-102985.rs:5:14 + | +LL | n => n(), + | ^^^ + = note: wrap the `[closure@$DIR/issue-102985.rs:4:23: 4:25]` in a closure with no arguments: `|| { /* code */ }` + +error[E0277]: the trait bound `[closure@$DIR/issue-102985.rs:4:23: 4:25]: ~const Fn<()>` is not satisfied + --> $DIR/issue-102985.rs:5:14 + | +LL | n => n(), + | ^^^ expected an `Fn<()>` closure, found `[closure@$DIR/issue-102985.rs:4:23: 4:25]` + | + = help: the trait `~const Fn<()>` is not implemented for closure `[closure@$DIR/issue-102985.rs:4:23: 4:25]` +note: the trait `Fn<()>` is implemented for `[closure@$DIR/issue-102985.rs:4:23: 4:25]`, but that implementation is not `const` + --> $DIR/issue-102985.rs:5:14 + | +LL | n => n(), + | ^^^ + = note: wrap the `[closure@$DIR/issue-102985.rs:4:23: 4:25]` in a closure with no arguments: `|| { /* code */ }` + +error[E0015]: cannot call non-const closure in constants + --> $DIR/issue-102985.rs:5:14 + | +LL | n => n(), + | ^^^ + | + = note: closures need an RFC before allowed to be called in constants + = note: calls in constants are limited to constant functions, tuple structs and tuple variants + +error: aborting due to 3 previous errors + +Some errors have detailed explanations: E0015, E0277. +For more information about an error, try `rustc --explain E0015`. diff --git a/tests/ui/rfcs/rfc-2632-const-trait-impl/issue-103677.rs b/tests/ui/rfcs/rfc-2632-const-trait-impl/issue-103677.rs new file mode 100644 index 000000000..d81724a36 --- /dev/null +++ b/tests/ui/rfcs/rfc-2632-const-trait-impl/issue-103677.rs @@ -0,0 +1,5 @@ +// check-pass + +const _: fn(&String) = |s| { &*s as &str; }; + +fn main() {} diff --git a/tests/ui/rfcs/rfc-2632-const-trait-impl/issue-79450.rs b/tests/ui/rfcs/rfc-2632-const-trait-impl/issue-79450.rs new file mode 100644 index 000000000..b604c65d7 --- /dev/null +++ b/tests/ui/rfcs/rfc-2632-const-trait-impl/issue-79450.rs @@ -0,0 +1,20 @@ +#![feature(const_fmt_arguments_new)] +#![feature(const_trait_impl)] + +#[const_trait] +trait Tr { + fn req(&self); + + fn prov(&self) { + println!("lul"); //~ ERROR: cannot call non-const fn `_print` in constant functions + self.req(); + } +} + +struct S; + +impl const Tr for S { + fn req(&self) {} +} + +fn main() {} diff --git a/tests/ui/rfcs/rfc-2632-const-trait-impl/issue-79450.stderr b/tests/ui/rfcs/rfc-2632-const-trait-impl/issue-79450.stderr new file mode 100644 index 000000000..082c0333f --- /dev/null +++ b/tests/ui/rfcs/rfc-2632-const-trait-impl/issue-79450.stderr @@ -0,0 +1,12 @@ +error[E0015]: cannot call non-const fn `_print` in constant functions + --> $DIR/issue-79450.rs:9:9 + | +LL | println!("lul"); + | ^^^^^^^^^^^^^^^ + | + = note: calls in constant functions are limited to constant functions, tuple structs and tuple variants + = note: this error originates in the macro `println` (in Nightly builds, run with -Z macro-backtrace for more info) + +error: aborting due to previous error + +For more information about this error, try `rustc --explain E0015`. diff --git a/tests/ui/rfcs/rfc-2632-const-trait-impl/issue-88155.rs b/tests/ui/rfcs/rfc-2632-const-trait-impl/issue-88155.rs new file mode 100644 index 000000000..b132c395a --- /dev/null +++ b/tests/ui/rfcs/rfc-2632-const-trait-impl/issue-88155.rs @@ -0,0 +1,13 @@ +#![feature(const_trait_impl)] + +pub trait A { + fn assoc() -> bool; +} + +pub const fn foo<T: A>() -> bool { + T::assoc() + //~^ ERROR the trait bound + //~| ERROR cannot call non-const fn +} + +fn main() {} diff --git a/tests/ui/rfcs/rfc-2632-const-trait-impl/issue-88155.stderr b/tests/ui/rfcs/rfc-2632-const-trait-impl/issue-88155.stderr new file mode 100644 index 000000000..955923505 --- /dev/null +++ b/tests/ui/rfcs/rfc-2632-const-trait-impl/issue-88155.stderr @@ -0,0 +1,24 @@ +error[E0277]: the trait bound `T: ~const A` is not satisfied + --> $DIR/issue-88155.rs:8:5 + | +LL | T::assoc() + | ^^^^^^^^^^ the trait `~const A` is not implemented for `T` + | +note: the trait `A` is implemented for `T`, but that implementation is not `const` + --> $DIR/issue-88155.rs:8:5 + | +LL | T::assoc() + | ^^^^^^^^^^ + +error[E0015]: cannot call non-const fn `<T as A>::assoc` in constant functions + --> $DIR/issue-88155.rs:8:5 + | +LL | T::assoc() + | ^^^^^^^^^^ + | + = note: calls in constant functions are limited to constant functions, tuple structs and tuple variants + +error: aborting due to 2 previous errors + +Some errors have detailed explanations: E0015, E0277. +For more information about an error, try `rustc --explain E0015`. diff --git a/tests/ui/rfcs/rfc-2632-const-trait-impl/issue-90052.rs b/tests/ui/rfcs/rfc-2632-const-trait-impl/issue-90052.rs new file mode 100644 index 000000000..21ddf4ab4 --- /dev/null +++ b/tests/ui/rfcs/rfc-2632-const-trait-impl/issue-90052.rs @@ -0,0 +1,9 @@ +#![feature(const_trait_impl)] + +#[const_trait] +trait Bar {} + +fn foo<T>() where T: ~const Bar {} +//~^ ERROR `~const` is not allowed + +fn main() {} diff --git a/tests/ui/rfcs/rfc-2632-const-trait-impl/issue-90052.stderr b/tests/ui/rfcs/rfc-2632-const-trait-impl/issue-90052.stderr new file mode 100644 index 000000000..b2a936537 --- /dev/null +++ b/tests/ui/rfcs/rfc-2632-const-trait-impl/issue-90052.stderr @@ -0,0 +1,14 @@ +error: `~const` is not allowed here + --> $DIR/issue-90052.rs:6:22 + | +LL | fn foo<T>() where T: ~const Bar {} + | ^^^^^^^^^^ + | +note: this function is not `const`, so it cannot have `~const` trait bounds + --> $DIR/issue-90052.rs:6:4 + | +LL | fn foo<T>() where T: ~const Bar {} + | ^^^ + +error: aborting due to previous error + diff --git a/tests/ui/rfcs/rfc-2632-const-trait-impl/issue-92111.rs b/tests/ui/rfcs/rfc-2632-const-trait-impl/issue-92111.rs new file mode 100644 index 000000000..96a3e386e --- /dev/null +++ b/tests/ui/rfcs/rfc-2632-const-trait-impl/issue-92111.rs @@ -0,0 +1,23 @@ +// Regression test for #92111. +// +// check-pass + +#![feature(const_trait_impl)] + +use std::marker::Destruct; + +pub trait Tr {} + +#[allow(drop_bounds)] +impl<T: Drop> Tr for T {} + +#[derive(Debug)] +pub struct S(i32); + +impl Tr for S {} + +const fn a<T: ~const Destruct>(t: T) {} + +fn main() { + a(S(0)); +} diff --git a/tests/ui/rfcs/rfc-2632-const-trait-impl/issue-92230-wf-super-trait-env.rs b/tests/ui/rfcs/rfc-2632-const-trait-impl/issue-92230-wf-super-trait-env.rs new file mode 100644 index 000000000..4d3469653 --- /dev/null +++ b/tests/ui/rfcs/rfc-2632-const-trait-impl/issue-92230-wf-super-trait-env.rs @@ -0,0 +1,15 @@ +// Regression test for #92230. +// +// check-pass + +#![feature(const_trait_impl)] + +#[const_trait] +pub trait Super {} +#[const_trait] +pub trait Sub: Super {} + +impl<A> const Super for &A where A: ~const Super {} +impl<A> const Sub for &A where A: ~const Sub {} + +fn main() {} diff --git a/tests/ui/rfcs/rfc-2632-const-trait-impl/match-non-const-eq.gated.stderr b/tests/ui/rfcs/rfc-2632-const-trait-impl/match-non-const-eq.gated.stderr new file mode 100644 index 000000000..bd0dd126c --- /dev/null +++ b/tests/ui/rfcs/rfc-2632-const-trait-impl/match-non-const-eq.gated.stderr @@ -0,0 +1,26 @@ +error[E0277]: can't compare `str` with `str` in const contexts + --> $DIR/match-non-const-eq.rs:6:9 + | +LL | "a" => (), + | ^^^ no implementation for `str == str` + | + = help: the trait `~const PartialEq` is not implemented for `str` +note: the trait `PartialEq` is implemented for `str`, but that implementation is not `const` + --> $DIR/match-non-const-eq.rs:6:9 + | +LL | "a" => (), + | ^^^ + +error[E0015]: cannot match on `str` in constant functions + --> $DIR/match-non-const-eq.rs:6:9 + | +LL | "a" => (), + | ^^^ + | + = note: `str` cannot be compared in compile-time, and therefore cannot be used in `match`es + = note: calls in constant functions are limited to constant functions, tuple structs and tuple variants + +error: aborting due to 2 previous errors + +Some errors have detailed explanations: E0015, E0277. +For more information about an error, try `rustc --explain E0015`. diff --git a/tests/ui/rfcs/rfc-2632-const-trait-impl/match-non-const-eq.rs b/tests/ui/rfcs/rfc-2632-const-trait-impl/match-non-const-eq.rs new file mode 100644 index 000000000..0d04101a3 --- /dev/null +++ b/tests/ui/rfcs/rfc-2632-const-trait-impl/match-non-const-eq.rs @@ -0,0 +1,12 @@ +// revisions: stock gated +#![cfg_attr(gated, feature(const_trait_impl))] + +const fn foo(input: &'static str) { + match input { + "a" => (), //[gated]~ ERROR can't compare `str` with `str` in const contexts + //~^ ERROR cannot match on `str` in constant functions + _ => (), + } +} + +fn main() {} diff --git a/tests/ui/rfcs/rfc-2632-const-trait-impl/match-non-const-eq.stock.stderr b/tests/ui/rfcs/rfc-2632-const-trait-impl/match-non-const-eq.stock.stderr new file mode 100644 index 000000000..dcb9b49ea --- /dev/null +++ b/tests/ui/rfcs/rfc-2632-const-trait-impl/match-non-const-eq.stock.stderr @@ -0,0 +1,13 @@ +error[E0015]: cannot match on `str` in constant functions + --> $DIR/match-non-const-eq.rs:6:9 + | +LL | "a" => (), + | ^^^ + | + = note: `str` cannot be compared in compile-time, and therefore cannot be used in `match`es + = note: calls in constant functions are limited to constant functions, tuple structs and tuple variants + = help: add `#![feature(const_trait_impl)]` to the crate attributes to enable + +error: aborting due to previous error + +For more information about this error, try `rustc --explain E0015`. diff --git a/tests/ui/rfcs/rfc-2632-const-trait-impl/nested-closure.rs b/tests/ui/rfcs/rfc-2632-const-trait-impl/nested-closure.rs new file mode 100644 index 000000000..0b423b340 --- /dev/null +++ b/tests/ui/rfcs/rfc-2632-const-trait-impl/nested-closure.rs @@ -0,0 +1,12 @@ +// check-pass + +#![feature(const_trait_impl, lazy_cell)] + +use std::sync::LazyLock; + +static EXTERN_FLAGS: LazyLock<String> = LazyLock::new(|| { + let x = || String::new(); + x() +}); + +fn main() {} diff --git a/tests/ui/rfcs/rfc-2632-const-trait-impl/non-const-op-const-closure-non-const-outer.rs b/tests/ui/rfcs/rfc-2632-const-trait-impl/non-const-op-const-closure-non-const-outer.rs new file mode 100644 index 000000000..cd8bb5963 --- /dev/null +++ b/tests/ui/rfcs/rfc-2632-const-trait-impl/non-const-op-const-closure-non-const-outer.rs @@ -0,0 +1,15 @@ +#![feature(const_closures, const_trait_impl)] +#![allow(incomplete_features)] + +trait Foo { + fn foo(&self); +} + +impl Foo for () { + fn foo(&self) {} +} + +fn main() { + (const || { (()).foo() })(); + //~^ ERROR: cannot call non-const fn +} diff --git a/tests/ui/rfcs/rfc-2632-const-trait-impl/non-const-op-const-closure-non-const-outer.stderr b/tests/ui/rfcs/rfc-2632-const-trait-impl/non-const-op-const-closure-non-const-outer.stderr new file mode 100644 index 000000000..979d7febb --- /dev/null +++ b/tests/ui/rfcs/rfc-2632-const-trait-impl/non-const-op-const-closure-non-const-outer.stderr @@ -0,0 +1,11 @@ +error[E0015]: cannot call non-const fn `<() as Foo>::foo` in constant functions + --> $DIR/non-const-op-const-closure-non-const-outer.rs:13:22 + | +LL | (const || { (()).foo() })(); + | ^^^^^ + | + = note: calls in constant functions are limited to constant functions, tuple structs and tuple variants + +error: aborting due to previous error + +For more information about this error, try `rustc --explain E0015`. diff --git a/tests/ui/rfcs/rfc-2632-const-trait-impl/non-const-op-in-closure-in-const.rs b/tests/ui/rfcs/rfc-2632-const-trait-impl/non-const-op-in-closure-in-const.rs new file mode 100644 index 000000000..dff8a2444 --- /dev/null +++ b/tests/ui/rfcs/rfc-2632-const-trait-impl/non-const-op-in-closure-in-const.rs @@ -0,0 +1,18 @@ +// known-bug: #110395 + +#![feature(const_trait_impl)] + +#[const_trait] +trait Convert<T> { + fn to(self) -> T; +} + +impl<A, B> const Convert<B> for A where B: ~const From<A> { + fn to(self) -> B { + B::from(self) + } +} + +const FOO: fn() -> String = || "foo".to(); + +fn main() {} diff --git a/tests/ui/rfcs/rfc-2632-const-trait-impl/non-const-op-in-closure-in-const.stderr b/tests/ui/rfcs/rfc-2632-const-trait-impl/non-const-op-in-closure-in-const.stderr new file mode 100644 index 000000000..cfdda4713 --- /dev/null +++ b/tests/ui/rfcs/rfc-2632-const-trait-impl/non-const-op-in-closure-in-const.stderr @@ -0,0 +1,8 @@ +error: ~const can only be applied to `#[const_trait]` traits + --> $DIR/non-const-op-in-closure-in-const.rs:10:51 + | +LL | impl<A, B> const Convert<B> for A where B: ~const From<A> { + | ^^^^^^^ + +error: aborting due to previous error + diff --git a/tests/ui/rfcs/rfc-2632-const-trait-impl/specialization/const-default-bound-non-const-specialized-bound.rs b/tests/ui/rfcs/rfc-2632-const-trait-impl/specialization/const-default-bound-non-const-specialized-bound.rs new file mode 100644 index 000000000..f31123f16 --- /dev/null +++ b/tests/ui/rfcs/rfc-2632-const-trait-impl/specialization/const-default-bound-non-const-specialized-bound.rs @@ -0,0 +1,58 @@ +// Tests that trait bounds on specializing trait impls must be `~const` if the +// same bound is present on the default impl and is `~const` there. + +#![feature(const_trait_impl)] +#![feature(rustc_attrs)] +#![feature(min_specialization)] + +#[rustc_specialization_trait] +trait Specialize {} + +#[const_trait] +trait Foo {} + +#[const_trait] +trait Bar { + fn bar(); +} + +// bgr360: I was only able to exercise the code path that raises the +// "missing ~const qualifier" error by making this base impl non-const, even +// though that doesn't really make sense to do. As seen below, if the base impl +// is made const, rustc fails earlier with an overlapping impl failure. +impl<T> Bar for T +where + T: ~const Foo, +{ + default fn bar() {} +} + +impl<T> Bar for T +where + T: Foo, //~ ERROR missing `~const` qualifier + T: Specialize, +{ + fn bar() {} +} + +#[const_trait] +trait Baz { + fn baz(); +} + +impl<T> const Baz for T +where + T: ~const Foo, +{ + default fn baz() {} +} + +impl<T> const Baz for T //~ ERROR conflicting implementations of trait `Baz` +where + T: Foo, + T: Specialize, +{ + fn baz() {} +} + +fn main() {} diff --git a/tests/ui/rfcs/rfc-2632-const-trait-impl/specialization/const-default-bound-non-const-specialized-bound.stderr b/tests/ui/rfcs/rfc-2632-const-trait-impl/specialization/const-default-bound-non-const-specialized-bound.stderr new file mode 100644 index 000000000..057cf4aea --- /dev/null +++ b/tests/ui/rfcs/rfc-2632-const-trait-impl/specialization/const-default-bound-non-const-specialized-bound.stderr @@ -0,0 +1,18 @@ +error: missing `~const` qualifier for specialization + --> $DIR/const-default-bound-non-const-specialized-bound.rs:32:8 + | +LL | T: Foo, + | ^^^ + +error[E0119]: conflicting implementations of trait `Baz` + --> $DIR/const-default-bound-non-const-specialized-bound.rs:50:1 + | +LL | impl<T> const Baz for T + | ----------------------- first implementation here +... +LL | impl<T> const Baz for T + | ^^^^^^^^^^^^^^^^^^^^^^^ conflicting implementation + +error: aborting due to 2 previous errors + +For more information about this error, try `rustc --explain E0119`. diff --git a/tests/ui/rfcs/rfc-2632-const-trait-impl/specialization/const-default-const-specialized.rs b/tests/ui/rfcs/rfc-2632-const-trait-impl/specialization/const-default-const-specialized.rs new file mode 100644 index 000000000..9ddea427c --- /dev/null +++ b/tests/ui/rfcs/rfc-2632-const-trait-impl/specialization/const-default-const-specialized.rs @@ -0,0 +1,39 @@ +// Tests that a const default trait impl can be specialized by another const +// trait impl and that the specializing impl will be used during const-eval. + +// run-pass + +#![feature(const_trait_impl)] +#![feature(min_specialization)] + +#[const_trait] +trait Value { + fn value() -> u32; +} + +const fn get_value<T: ~const Value>() -> u32 { + T::value() +} + +impl<T> const Value for T { + default fn value() -> u32 { + 0 + } +} + +struct FortyTwo; + +impl const Value for FortyTwo { + fn value() -> u32 { + 42 + } +} + +const ZERO: u32 = get_value::<()>(); + +const FORTY_TWO: u32 = get_value::<FortyTwo>(); + +fn main() { + assert_eq!(ZERO, 0); + assert_eq!(FORTY_TWO, 42); +} diff --git a/tests/ui/rfcs/rfc-2632-const-trait-impl/specialization/const-default-impl-non-const-specialized-impl.rs b/tests/ui/rfcs/rfc-2632-const-trait-impl/specialization/const-default-impl-non-const-specialized-impl.rs new file mode 100644 index 000000000..a3bb9b3f9 --- /dev/null +++ b/tests/ui/rfcs/rfc-2632-const-trait-impl/specialization/const-default-impl-non-const-specialized-impl.rs @@ -0,0 +1,26 @@ +// Tests that specializing trait impls must be at least as const as the default impl. + +#![feature(const_trait_impl)] +#![feature(min_specialization)] + +#[const_trait] +trait Value { + fn value() -> u32; +} + +impl<T> const Value for T { + default fn value() -> u32 { + 0 + } +} + +struct FortyTwo; + +impl Value for FortyTwo { //~ ERROR cannot specialize on const impl with non-const impl + fn value() -> u32 { + println!("You can't do that (constly)"); + 42 + } +} + +fn main() {} diff --git a/tests/ui/rfcs/rfc-2632-const-trait-impl/specialization/const-default-impl-non-const-specialized-impl.stderr b/tests/ui/rfcs/rfc-2632-const-trait-impl/specialization/const-default-impl-non-const-specialized-impl.stderr new file mode 100644 index 000000000..247668047 --- /dev/null +++ b/tests/ui/rfcs/rfc-2632-const-trait-impl/specialization/const-default-impl-non-const-specialized-impl.stderr @@ -0,0 +1,8 @@ +error: cannot specialize on const impl with non-const impl + --> $DIR/const-default-impl-non-const-specialized-impl.rs:19:1 + | +LL | impl Value for FortyTwo { + | ^^^^^^^^^^^^^^^^^^^^^^^ + +error: aborting due to previous error + diff --git a/tests/ui/rfcs/rfc-2632-const-trait-impl/specialization/default-keyword.rs b/tests/ui/rfcs/rfc-2632-const-trait-impl/specialization/default-keyword.rs new file mode 100644 index 000000000..2aac0a2b4 --- /dev/null +++ b/tests/ui/rfcs/rfc-2632-const-trait-impl/specialization/default-keyword.rs @@ -0,0 +1,15 @@ +// check-pass + +#![feature(const_trait_impl)] +#![feature(min_specialization)] + +#[const_trait] +trait Foo { + fn foo(); +} + +impl const Foo for u32 { + default fn foo() {} +} + +fn main() {} diff --git a/tests/ui/rfcs/rfc-2632-const-trait-impl/specialization/issue-95186-specialize-on-tilde-const.rs b/tests/ui/rfcs/rfc-2632-const-trait-impl/specialization/issue-95186-specialize-on-tilde-const.rs new file mode 100644 index 000000000..92d8be6bb --- /dev/null +++ b/tests/ui/rfcs/rfc-2632-const-trait-impl/specialization/issue-95186-specialize-on-tilde-const.rs @@ -0,0 +1,49 @@ +// Tests that `~const` trait bounds can be used to specialize const trait impls. + +// check-pass + +#![feature(const_trait_impl)] +#![feature(rustc_attrs)] +#![feature(min_specialization)] + +#[const_trait] +#[rustc_specialization_trait] +trait Specialize {} + +#[const_trait] +trait Foo { + fn foo(); +} + +impl<T> const Foo for T { + default fn foo() {} +} + +impl<T> const Foo for T +where + T: ~const Specialize, +{ + fn foo() {} +} + +#[const_trait] +trait Bar { + fn bar() {} +} + +impl<T> const Bar for T +where + T: ~const Foo, +{ + default fn bar() {} +} + +impl<T> const Bar for T +where + T: ~const Foo, + T: ~const Specialize, +{ + fn bar() {} +} + +fn main() {} diff --git a/tests/ui/rfcs/rfc-2632-const-trait-impl/specialization/issue-95187-same-trait-bound-different-constness.rs b/tests/ui/rfcs/rfc-2632-const-trait-impl/specialization/issue-95187-same-trait-bound-different-constness.rs new file mode 100644 index 000000000..51bfaf73b --- /dev/null +++ b/tests/ui/rfcs/rfc-2632-const-trait-impl/specialization/issue-95187-same-trait-bound-different-constness.rs @@ -0,0 +1,57 @@ +// Tests that `T: ~const Foo` in a specializing impl is treated as equivalent to +// `T: Foo` in the default impl for the purposes of specialization (i.e., it +// does not think that the user is attempting to specialize on trait `Foo`). + +// check-pass + +#![feature(rustc_attrs)] +#![feature(min_specialization)] +#![feature(const_trait_impl)] + +#[rustc_specialization_trait] +trait Specialize {} + +#[const_trait] +trait Foo {} + +#[const_trait] +trait Bar { + fn bar(); +} + +impl<T> Bar for T +where + T: Foo, +{ + default fn bar() {} +} + +impl<T> const Bar for T +where + T: ~const Foo, + T: Specialize, +{ + fn bar() {} +} + +#[const_trait] +trait Baz { + fn baz(); +} + +impl<T> const Baz for T +where + T: Foo, +{ + default fn baz() {} +} + +impl<T> const Baz for T +where + T: ~const Foo, + T: Specialize, +{ + fn baz() {} +} + +fn main() {} diff --git a/tests/ui/rfcs/rfc-2632-const-trait-impl/specialization/non-const-default-const-specialized.rs b/tests/ui/rfcs/rfc-2632-const-trait-impl/specialization/non-const-default-const-specialized.rs new file mode 100644 index 000000000..35aa52fbd --- /dev/null +++ b/tests/ui/rfcs/rfc-2632-const-trait-impl/specialization/non-const-default-const-specialized.rs @@ -0,0 +1,39 @@ +// Tests that a non-const default impl can be specialized by a const trait impl, +// but that the default impl cannot be used in a const context. + +// run-pass + +#![feature(const_trait_impl)] +#![feature(min_specialization)] + +#[const_trait] +trait Value { + fn value() -> u32; +} + +const fn get_value<T: ~const Value>() -> u32 { + T::value() +} + +impl<T> Value for T { + default fn value() -> u32 { + println!("You can't do that (constly)"); + 0 + } +} + +struct FortyTwo; + +impl const Value for FortyTwo { + fn value() -> u32 { + 42 + } +} + +fn main() { + let zero = get_value::<()>(); + assert_eq!(zero, 0); + + const FORTY_TWO: u32 = get_value::<FortyTwo>(); + assert_eq!(FORTY_TWO, 42); +} diff --git a/tests/ui/rfcs/rfc-2632-const-trait-impl/specializing-constness-2.rs b/tests/ui/rfcs/rfc-2632-const-trait-impl/specializing-constness-2.rs new file mode 100644 index 000000000..633543700 --- /dev/null +++ b/tests/ui/rfcs/rfc-2632-const-trait-impl/specializing-constness-2.rs @@ -0,0 +1,31 @@ +#![feature(const_trait_impl, min_specialization, rustc_attrs)] + +#[rustc_specialization_trait] +#[const_trait] +pub trait Sup {} + +impl const Sup for () {} + +#[const_trait] +pub trait A { + fn a() -> u32; +} + +impl<T: Default> A for T { + default fn a() -> u32 { + 2 + } +} + +impl<T: Default + ~const Sup> const A for T { + fn a() -> u32 { + 3 + } +} + +const fn generic<T: Default>() { + <T as A>::a(); + //~^ ERROR: the trait bound `T: ~const Sup` is not satisfied +} + +fn main() {} diff --git a/tests/ui/rfcs/rfc-2632-const-trait-impl/specializing-constness-2.stderr b/tests/ui/rfcs/rfc-2632-const-trait-impl/specializing-constness-2.stderr new file mode 100644 index 000000000..8923416f4 --- /dev/null +++ b/tests/ui/rfcs/rfc-2632-const-trait-impl/specializing-constness-2.stderr @@ -0,0 +1,21 @@ +error[E0277]: the trait bound `T: ~const Sup` is not satisfied + --> $DIR/specializing-constness-2.rs:27:5 + | +LL | <T as A>::a(); + | ^^^^^^^^^^^^^ the trait `~const Sup` is not implemented for `T` + | +note: required for `T` to implement `~const A` + --> $DIR/specializing-constness-2.rs:20:37 + | +LL | impl<T: Default + ~const Sup> const A for T { + | ---------- ^ ^ + | | + | unsatisfied trait bound introduced here +help: consider further restricting this bound + | +LL | const fn generic<T: Default + ~const Sup>() { + | ++++++++++++ + +error: aborting due to previous error + +For more information about this error, try `rustc --explain E0277`. diff --git a/tests/ui/rfcs/rfc-2632-const-trait-impl/specializing-constness.rs b/tests/ui/rfcs/rfc-2632-const-trait-impl/specializing-constness.rs new file mode 100644 index 000000000..5c2a3f801 --- /dev/null +++ b/tests/ui/rfcs/rfc-2632-const-trait-impl/specializing-constness.rs @@ -0,0 +1,31 @@ +#![feature(const_trait_impl, min_specialization, rustc_attrs)] + +#[rustc_specialization_trait] +#[const_trait] +pub trait Sup {} + +impl const Sup for () {} + +#[const_trait] +pub trait A { + fn a() -> u32; +} + +#[const_trait] +pub trait Spec {} + +impl<T: ~const Spec> const A for T { + default fn a() -> u32 { + 2 + } +} + +impl<T: Spec + Sup> A for T { +//~^ ERROR: cannot specialize +//~| ERROR: missing `~const` qualifier + fn a() -> u32 { + 3 + } +} + +fn main() {} diff --git a/tests/ui/rfcs/rfc-2632-const-trait-impl/specializing-constness.stderr b/tests/ui/rfcs/rfc-2632-const-trait-impl/specializing-constness.stderr new file mode 100644 index 000000000..1ffdc50e5 --- /dev/null +++ b/tests/ui/rfcs/rfc-2632-const-trait-impl/specializing-constness.stderr @@ -0,0 +1,14 @@ +error: cannot specialize on const impl with non-const impl + --> $DIR/specializing-constness.rs:23:1 + | +LL | impl<T: Spec + Sup> A for T { + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^ + +error: missing `~const` qualifier for specialization + --> $DIR/specializing-constness.rs:23:9 + | +LL | impl<T: Spec + Sup> A for T { + | ^^^^ + +error: aborting due to 2 previous errors + diff --git a/tests/ui/rfcs/rfc-2632-const-trait-impl/staged-api-user-crate.rs b/tests/ui/rfcs/rfc-2632-const-trait-impl/staged-api-user-crate.rs new file mode 100644 index 000000000..fc0d82727 --- /dev/null +++ b/tests/ui/rfcs/rfc-2632-const-trait-impl/staged-api-user-crate.rs @@ -0,0 +1,16 @@ +// aux-build: staged-api.rs +extern crate staged_api; + +use staged_api::*; + +// Const stability has no impact on usage in non-const contexts. +fn non_const_context() { + Unstable::func(); +} + +const fn stable_const_context() { + Unstable::func(); + //~^ ERROR cannot call non-const fn `<staged_api::Unstable as staged_api::MyTrait>::func` in constant functions +} + +fn main() {} diff --git a/tests/ui/rfcs/rfc-2632-const-trait-impl/staged-api-user-crate.stderr b/tests/ui/rfcs/rfc-2632-const-trait-impl/staged-api-user-crate.stderr new file mode 100644 index 000000000..d7aa0d95c --- /dev/null +++ b/tests/ui/rfcs/rfc-2632-const-trait-impl/staged-api-user-crate.stderr @@ -0,0 +1,12 @@ +error[E0015]: cannot call non-const fn `<staged_api::Unstable as staged_api::MyTrait>::func` in constant functions + --> $DIR/staged-api-user-crate.rs:12:5 + | +LL | Unstable::func(); + | ^^^^^^^^^^^^^^^^ + | + = note: calls in constant functions are limited to constant functions, tuple structs and tuple variants + = help: add `#![feature(const_trait_impl)]` to the crate attributes to enable + +error: aborting due to previous error + +For more information about this error, try `rustc --explain E0015`. diff --git a/tests/ui/rfcs/rfc-2632-const-trait-impl/staged-api.rs b/tests/ui/rfcs/rfc-2632-const-trait-impl/staged-api.rs new file mode 100644 index 000000000..1d79f5adf --- /dev/null +++ b/tests/ui/rfcs/rfc-2632-const-trait-impl/staged-api.rs @@ -0,0 +1,63 @@ +// revisions: stable unstable + +#![cfg_attr(unstable, feature(unstable))] // The feature from the ./auxiliary/staged-api.rs file. +#![feature(const_trait_impl)] +#![feature(staged_api)] +#![stable(feature = "rust1", since = "1.0.0")] + +// aux-build: staged-api.rs +extern crate staged_api; + +use staged_api::*; + +#[stable(feature = "rust1", since = "1.0.0")] +pub struct Foo; + +#[stable(feature = "rust1", since = "1.0.0")] +#[cfg_attr(unstable, rustc_const_unstable(feature = "foo", issue = "none"))] +#[cfg_attr(stable, rustc_const_stable(feature = "foo", since = "1.0.0"))] +impl const MyTrait for Foo { + //[stable]~^ ERROR trait implementations cannot be const stable yet + fn func() {} +} + +// Const stability has no impact on usage in non-const contexts. +fn non_const_context() { + Unstable::func(); + Foo::func(); +} + +#[unstable(feature = "none", issue = "none")] +const fn const_context() { + Unstable::func(); + // ^ This is okay regardless of whether the `unstable` feature is enabled, as this function is + // not const-stable. + Foo::func(); + //[unstable]~^ ERROR not yet stable as a const fn + // ^ fails, because the `foo` feature is not active +} + +#[stable(feature = "rust1", since = "1.0.0")] +#[cfg_attr(unstable, rustc_const_unstable(feature = "foo", issue = "none"))] +pub const fn const_context_not_const_stable() { + //[stable]~^ ERROR function has missing const stability attribute + Unstable::func(); + // ^ This is okay regardless of whether the `unstable` feature is enabled, as this function is + // not const-stable. + Foo::func(); + //[unstable]~^ ERROR not yet stable as a const fn + // ^ fails, because the `foo` feature is not active +} + +#[stable(feature = "rust1", since = "1.0.0")] +#[rustc_const_stable(feature = "cheese", since = "1.0.0")] +const fn stable_const_context() { + Unstable::func(); + //[unstable]~^ ERROR not yet stable as a const fn + Foo::func(); + //[unstable]~^ ERROR not yet stable as a const fn + const_context_not_const_stable() + //[unstable]~^ ERROR not yet stable as a const fn +} + +fn main() {} diff --git a/tests/ui/rfcs/rfc-2632-const-trait-impl/staged-api.stable.stderr b/tests/ui/rfcs/rfc-2632-const-trait-impl/staged-api.stable.stderr new file mode 100644 index 000000000..a1aca762e --- /dev/null +++ b/tests/ui/rfcs/rfc-2632-const-trait-impl/staged-api.stable.stderr @@ -0,0 +1,25 @@ +error: trait implementations cannot be const stable yet + --> $DIR/staged-api.rs:19:1 + | +LL | / impl const MyTrait for Foo { +LL | | +LL | | fn func() {} +LL | | } + | |_^ + | + = note: see issue #67792 <https://github.com/rust-lang/rust/issues/67792> for more information + +error: function has missing const stability attribute + --> $DIR/staged-api.rs:42:1 + | +LL | / pub const fn const_context_not_const_stable() { +LL | | +LL | | Unstable::func(); +LL | | // ^ This is okay regardless of whether the `unstable` feature is enabled, as this function is +... | +LL | | // ^ fails, because the `foo` feature is not active +LL | | } + | |_^ + +error: aborting due to 2 previous errors + diff --git a/tests/ui/rfcs/rfc-2632-const-trait-impl/staged-api.unstable.stderr b/tests/ui/rfcs/rfc-2632-const-trait-impl/staged-api.unstable.stderr new file mode 100644 index 000000000..c38d1a81a --- /dev/null +++ b/tests/ui/rfcs/rfc-2632-const-trait-impl/staged-api.unstable.stderr @@ -0,0 +1,42 @@ +error: `<Foo as staged_api::MyTrait>::func` is not yet stable as a const fn + --> $DIR/staged-api.rs:35:5 + | +LL | Foo::func(); + | ^^^^^^^^^^^ + | + = help: add `#![feature(foo)]` to the crate attributes to enable + +error: `<Foo as staged_api::MyTrait>::func` is not yet stable as a const fn + --> $DIR/staged-api.rs:47:5 + | +LL | Foo::func(); + | ^^^^^^^^^^^ + | + = help: add `#![feature(foo)]` to the crate attributes to enable + +error: `<staged_api::Unstable as staged_api::MyTrait>::func` is not yet stable as a const fn + --> $DIR/staged-api.rs:55:5 + | +LL | Unstable::func(); + | ^^^^^^^^^^^^^^^^ + | + = help: const-stable functions can only call other const-stable functions + +error: `<Foo as staged_api::MyTrait>::func` is not yet stable as a const fn + --> $DIR/staged-api.rs:57:5 + | +LL | Foo::func(); + | ^^^^^^^^^^^ + | + = help: const-stable functions can only call other const-stable functions + +error: `const_context_not_const_stable` is not yet stable as a const fn + --> $DIR/staged-api.rs:59:5 + | +LL | const_context_not_const_stable() + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + | + = help: const-stable functions can only call other const-stable functions + +error: aborting due to 5 previous errors + diff --git a/tests/ui/rfcs/rfc-2632-const-trait-impl/static-const-trait-bound.rs b/tests/ui/rfcs/rfc-2632-const-trait-impl/static-const-trait-bound.rs new file mode 100644 index 000000000..4520a3696 --- /dev/null +++ b/tests/ui/rfcs/rfc-2632-const-trait-impl/static-const-trait-bound.rs @@ -0,0 +1,18 @@ +// check-pass +pub struct S<T, F: FnOnce() -> T = fn() -> T> { + f: F, + x: Option<T>, +} + +impl<T, F: FnOnce() -> T> S<T, F> { + pub const fn new(f: F) -> Self { + Self { f, x: None } + } +} + +#[derive(Default)] +pub struct Foo; + +static LOCKED_CALLSITES: S<Foo> = S::new(Default::default); + +fn main() {} diff --git a/tests/ui/rfcs/rfc-2632-const-trait-impl/std-impl-gate.gated.stderr b/tests/ui/rfcs/rfc-2632-const-trait-impl/std-impl-gate.gated.stderr new file mode 100644 index 000000000..78aab9469 --- /dev/null +++ b/tests/ui/rfcs/rfc-2632-const-trait-impl/std-impl-gate.gated.stderr @@ -0,0 +1,9 @@ +error[E0635]: unknown feature `const_default_impls` + --> $DIR/std-impl-gate.rs:6:46 + | +LL | #![cfg_attr(gated, feature(const_trait_impl, const_default_impls))] + | ^^^^^^^^^^^^^^^^^^^ + +error: aborting due to previous error + +For more information about this error, try `rustc --explain E0635`. diff --git a/tests/ui/rfcs/rfc-2632-const-trait-impl/std-impl-gate.rs b/tests/ui/rfcs/rfc-2632-const-trait-impl/std-impl-gate.rs new file mode 100644 index 000000000..e9e5e0235 --- /dev/null +++ b/tests/ui/rfcs/rfc-2632-const-trait-impl/std-impl-gate.rs @@ -0,0 +1,21 @@ +// This tests feature gates for const impls in the standard library. + +// revisions: stock gated +//[gated] known-bug: #110395 + +#![cfg_attr(gated, feature(const_trait_impl, const_default_impls))] + +fn non_const_context() -> Vec<usize> { + Default::default() +} + +const fn const_context() -> Vec<usize> { + Default::default() + //[stock]~^ ERROR cannot call non-const fn +} + +fn main() { + const VAL: Vec<usize> = const_context(); + + assert_eq!(VAL, non_const_context()); +} diff --git a/tests/ui/rfcs/rfc-2632-const-trait-impl/std-impl-gate.stock.stderr b/tests/ui/rfcs/rfc-2632-const-trait-impl/std-impl-gate.stock.stderr new file mode 100644 index 000000000..6a3396401 --- /dev/null +++ b/tests/ui/rfcs/rfc-2632-const-trait-impl/std-impl-gate.stock.stderr @@ -0,0 +1,12 @@ +error[E0015]: cannot call non-const fn `<Vec<usize> as Default>::default` in constant functions + --> $DIR/std-impl-gate.rs:13:5 + | +LL | Default::default() + | ^^^^^^^^^^^^^^^^^^ + | + = note: calls in constant functions are limited to constant functions, tuple structs and tuple variants + = help: add `#![feature(const_trait_impl)]` to the crate attributes to enable + +error: aborting due to previous error + +For more information about this error, try `rustc --explain E0015`. diff --git a/tests/ui/rfcs/rfc-2632-const-trait-impl/super-traits-fail-2.nn.stderr b/tests/ui/rfcs/rfc-2632-const-trait-impl/super-traits-fail-2.nn.stderr new file mode 100644 index 000000000..97f346e8c --- /dev/null +++ b/tests/ui/rfcs/rfc-2632-const-trait-impl/super-traits-fail-2.nn.stderr @@ -0,0 +1,14 @@ +error: ~const can only be applied to `#[const_trait]` traits + --> $DIR/super-traits-fail-2.rs:11:19 + | +LL | trait Bar: ~const Foo {} + | ^^^ + +error: ~const can only be applied to `#[const_trait]` traits + --> $DIR/super-traits-fail-2.rs:11:19 + | +LL | trait Bar: ~const Foo {} + | ^^^ + +error: aborting due to 2 previous errors + diff --git a/tests/ui/rfcs/rfc-2632-const-trait-impl/super-traits-fail-2.ny.stderr b/tests/ui/rfcs/rfc-2632-const-trait-impl/super-traits-fail-2.ny.stderr new file mode 100644 index 000000000..97f346e8c --- /dev/null +++ b/tests/ui/rfcs/rfc-2632-const-trait-impl/super-traits-fail-2.ny.stderr @@ -0,0 +1,14 @@ +error: ~const can only be applied to `#[const_trait]` traits + --> $DIR/super-traits-fail-2.rs:11:19 + | +LL | trait Bar: ~const Foo {} + | ^^^ + +error: ~const can only be applied to `#[const_trait]` traits + --> $DIR/super-traits-fail-2.rs:11:19 + | +LL | trait Bar: ~const Foo {} + | ^^^ + +error: aborting due to 2 previous errors + diff --git a/tests/ui/rfcs/rfc-2632-const-trait-impl/super-traits-fail-2.rs b/tests/ui/rfcs/rfc-2632-const-trait-impl/super-traits-fail-2.rs new file mode 100644 index 000000000..ecb06271c --- /dev/null +++ b/tests/ui/rfcs/rfc-2632-const-trait-impl/super-traits-fail-2.rs @@ -0,0 +1,20 @@ +#![feature(const_trait_impl)] + +// revisions: yy yn ny nn + +#[cfg_attr(any(yy, yn), const_trait)] +trait Foo { + fn a(&self); +} + +#[cfg_attr(any(yy, ny), const_trait)] +trait Bar: ~const Foo {} +//[ny,nn]~^ ERROR: ~const can only be applied to `#[const_trait]` +//[ny,nn]~| ERROR: ~const can only be applied to `#[const_trait]` + +const fn foo<T: Bar>(x: &T) { + x.a(); + //[yn,yy]~^ ERROR the trait bound +} + +fn main() {} diff --git a/tests/ui/rfcs/rfc-2632-const-trait-impl/super-traits-fail-2.yn.stderr b/tests/ui/rfcs/rfc-2632-const-trait-impl/super-traits-fail-2.yn.stderr new file mode 100644 index 000000000..c9fa19554 --- /dev/null +++ b/tests/ui/rfcs/rfc-2632-const-trait-impl/super-traits-fail-2.yn.stderr @@ -0,0 +1,19 @@ +error[E0277]: the trait bound `T: ~const Foo` is not satisfied + --> $DIR/super-traits-fail-2.rs:16:7 + | +LL | x.a(); + | ^ the trait `~const Foo` is not implemented for `T` + | +note: the trait `Foo` is implemented for `T`, but that implementation is not `const` + --> $DIR/super-traits-fail-2.rs:16:5 + | +LL | x.a(); + | ^ +help: consider further restricting this bound + | +LL | const fn foo<T: Bar + ~const Foo>(x: &T) { + | ++++++++++++ + +error: aborting due to previous error + +For more information about this error, try `rustc --explain E0277`. diff --git a/tests/ui/rfcs/rfc-2632-const-trait-impl/super-traits-fail-2.yy.stderr b/tests/ui/rfcs/rfc-2632-const-trait-impl/super-traits-fail-2.yy.stderr new file mode 100644 index 000000000..c9fa19554 --- /dev/null +++ b/tests/ui/rfcs/rfc-2632-const-trait-impl/super-traits-fail-2.yy.stderr @@ -0,0 +1,19 @@ +error[E0277]: the trait bound `T: ~const Foo` is not satisfied + --> $DIR/super-traits-fail-2.rs:16:7 + | +LL | x.a(); + | ^ the trait `~const Foo` is not implemented for `T` + | +note: the trait `Foo` is implemented for `T`, but that implementation is not `const` + --> $DIR/super-traits-fail-2.rs:16:5 + | +LL | x.a(); + | ^ +help: consider further restricting this bound + | +LL | const fn foo<T: Bar + ~const Foo>(x: &T) { + | ++++++++++++ + +error: aborting due to previous error + +For more information about this error, try `rustc --explain E0277`. diff --git a/tests/ui/rfcs/rfc-2632-const-trait-impl/super-traits-fail-3.nn.stderr b/tests/ui/rfcs/rfc-2632-const-trait-impl/super-traits-fail-3.nn.stderr new file mode 100644 index 000000000..fdc6b8058 --- /dev/null +++ b/tests/ui/rfcs/rfc-2632-const-trait-impl/super-traits-fail-3.nn.stderr @@ -0,0 +1,20 @@ +error: ~const can only be applied to `#[const_trait]` traits + --> $DIR/super-traits-fail-3.rs:12:19 + | +LL | trait Bar: ~const Foo {} + | ^^^ + +error: ~const can only be applied to `#[const_trait]` traits + --> $DIR/super-traits-fail-3.rs:12:19 + | +LL | trait Bar: ~const Foo {} + | ^^^ + +error: ~const can only be applied to `#[const_trait]` traits + --> $DIR/super-traits-fail-3.rs:16:24 + | +LL | const fn foo<T: ~const Bar>(x: &T) { + | ^^^ + +error: aborting due to 3 previous errors + diff --git a/tests/ui/rfcs/rfc-2632-const-trait-impl/super-traits-fail-3.ny.stderr b/tests/ui/rfcs/rfc-2632-const-trait-impl/super-traits-fail-3.ny.stderr new file mode 100644 index 000000000..7375b8c81 --- /dev/null +++ b/tests/ui/rfcs/rfc-2632-const-trait-impl/super-traits-fail-3.ny.stderr @@ -0,0 +1,14 @@ +error: ~const can only be applied to `#[const_trait]` traits + --> $DIR/super-traits-fail-3.rs:12:19 + | +LL | trait Bar: ~const Foo {} + | ^^^ + +error: ~const can only be applied to `#[const_trait]` traits + --> $DIR/super-traits-fail-3.rs:12:19 + | +LL | trait Bar: ~const Foo {} + | ^^^ + +error: aborting due to 2 previous errors + diff --git a/tests/ui/rfcs/rfc-2632-const-trait-impl/super-traits-fail-3.rs b/tests/ui/rfcs/rfc-2632-const-trait-impl/super-traits-fail-3.rs new file mode 100644 index 000000000..8cf64944a --- /dev/null +++ b/tests/ui/rfcs/rfc-2632-const-trait-impl/super-traits-fail-3.rs @@ -0,0 +1,21 @@ +#![feature(const_trait_impl)] + +// revisions: yy yn ny nn +//[yy] check-pass + +#[cfg_attr(any(yy, yn), const_trait)] +trait Foo { + fn a(&self); +} + +#[cfg_attr(any(yy, ny), const_trait)] +trait Bar: ~const Foo {} +//[ny,nn]~^ ERROR: ~const can only be applied to `#[const_trait]` +//[ny,nn]~| ERROR: ~const can only be applied to `#[const_trait]` + +const fn foo<T: ~const Bar>(x: &T) { + //[yn,nn]~^ ERROR: ~const can only be applied to `#[const_trait]` + x.a(); +} + +fn main() {} diff --git a/tests/ui/rfcs/rfc-2632-const-trait-impl/super-traits-fail-3.yn.stderr b/tests/ui/rfcs/rfc-2632-const-trait-impl/super-traits-fail-3.yn.stderr new file mode 100644 index 000000000..7a152914b --- /dev/null +++ b/tests/ui/rfcs/rfc-2632-const-trait-impl/super-traits-fail-3.yn.stderr @@ -0,0 +1,8 @@ +error: ~const can only be applied to `#[const_trait]` traits + --> $DIR/super-traits-fail-3.rs:16:24 + | +LL | const fn foo<T: ~const Bar>(x: &T) { + | ^^^ + +error: aborting due to previous error + diff --git a/tests/ui/rfcs/rfc-2632-const-trait-impl/super-traits-fail.rs b/tests/ui/rfcs/rfc-2632-const-trait-impl/super-traits-fail.rs new file mode 100644 index 000000000..3e2b81368 --- /dev/null +++ b/tests/ui/rfcs/rfc-2632-const-trait-impl/super-traits-fail.rs @@ -0,0 +1,18 @@ +#![feature(const_trait_impl)] + +#[const_trait] +trait Foo { + fn a(&self); +} +#[const_trait] +trait Bar: ~const Foo {} + +struct S; +impl Foo for S { + fn a(&self) {} +} + +impl const Bar for S {} +//~^ ERROR the trait bound + +fn main() {} diff --git a/tests/ui/rfcs/rfc-2632-const-trait-impl/super-traits-fail.stderr b/tests/ui/rfcs/rfc-2632-const-trait-impl/super-traits-fail.stderr new file mode 100644 index 000000000..bf12ef1ca --- /dev/null +++ b/tests/ui/rfcs/rfc-2632-const-trait-impl/super-traits-fail.stderr @@ -0,0 +1,20 @@ +error[E0277]: the trait bound `S: ~const Foo` is not satisfied + --> $DIR/super-traits-fail.rs:15:20 + | +LL | impl const Bar for S {} + | ^ the trait `~const Foo` is not implemented for `S` + | +note: the trait `Foo` is implemented for `S`, but that implementation is not `const` + --> $DIR/super-traits-fail.rs:15:20 + | +LL | impl const Bar for S {} + | ^ +note: required by a bound in `Bar` + --> $DIR/super-traits-fail.rs:8:12 + | +LL | trait Bar: ~const Foo {} + | ^^^^^^^^^^ required by this bound in `Bar` + +error: aborting due to previous error + +For more information about this error, try `rustc --explain E0277`. diff --git a/tests/ui/rfcs/rfc-2632-const-trait-impl/super-traits.rs b/tests/ui/rfcs/rfc-2632-const-trait-impl/super-traits.rs new file mode 100644 index 000000000..df96f6fb4 --- /dev/null +++ b/tests/ui/rfcs/rfc-2632-const-trait-impl/super-traits.rs @@ -0,0 +1,25 @@ +// check-pass +#![feature(const_trait_impl)] + +#[const_trait] +trait Foo { + fn a(&self); +} + +#[const_trait] +trait Bar: ~const Foo {} + +struct S; +impl const Foo for S { + fn a(&self) {} +} + +impl const Bar for S {} + +const fn foo<T: ~const Bar>(t: &T) { + t.a(); +} + +const _: () = foo(&S); + +fn main() {} diff --git a/tests/ui/rfcs/rfc-2632-const-trait-impl/syntax.rs b/tests/ui/rfcs/rfc-2632-const-trait-impl/syntax.rs new file mode 100644 index 000000000..7ac2458e3 --- /dev/null +++ b/tests/ui/rfcs/rfc-2632-const-trait-impl/syntax.rs @@ -0,0 +1,8 @@ +// compile-flags: -Z parse-only +// check-pass + +#![feature(const_trait_bound_opt_out)] +#![feature(const_trait_impl)] + +// For now, this parses since an error does not occur until AST lowering. +impl ~const T {} diff --git a/tests/ui/rfcs/rfc-2632-const-trait-impl/tilde-const-and-const-params.rs b/tests/ui/rfcs/rfc-2632-const-trait-impl/tilde-const-and-const-params.rs new file mode 100644 index 000000000..78a64b901 --- /dev/null +++ b/tests/ui/rfcs/rfc-2632-const-trait-impl/tilde-const-and-const-params.rs @@ -0,0 +1,34 @@ +#![feature(const_trait_impl)] +#![feature(generic_arg_infer)] +#![feature(generic_const_exprs)] +#![allow(incomplete_features)] + +struct Foo<const N: usize>; + +impl<const N: usize> Foo<N> { + fn add<A: ~const Add42>(self) -> Foo<{ A::add(N) }> { + Foo + } +} + +#[const_trait] +trait Add42 { + fn add(a: usize) -> usize; +} + +impl const Add42 for () { + fn add(a: usize) -> usize { + a + 42 + } +} + +fn bar<A: ~const Add42, const N: usize>(_: Foo<N>) -> Foo<{ A::add(N) }> { + //~^ ERROR `~const` is not allowed here + Foo +} + +fn main() { + let foo = Foo::<0>; + let foo = bar::<(), _>(foo); + let _foo = bar::<(), _>(foo); +} diff --git a/tests/ui/rfcs/rfc-2632-const-trait-impl/tilde-const-and-const-params.stderr b/tests/ui/rfcs/rfc-2632-const-trait-impl/tilde-const-and-const-params.stderr new file mode 100644 index 000000000..aae72f36e --- /dev/null +++ b/tests/ui/rfcs/rfc-2632-const-trait-impl/tilde-const-and-const-params.stderr @@ -0,0 +1,14 @@ +error: `~const` is not allowed here + --> $DIR/tilde-const-and-const-params.rs:25:11 + | +LL | fn bar<A: ~const Add42, const N: usize>(_: Foo<N>) -> Foo<{ A::add(N) }> { + | ^^^^^^^^^^^^ + | +note: this function is not `const`, so it cannot have `~const` trait bounds + --> $DIR/tilde-const-and-const-params.rs:25:4 + | +LL | fn bar<A: ~const Add42, const N: usize>(_: Foo<N>) -> Foo<{ A::add(N) }> { + | ^^^ + +error: aborting due to previous error + diff --git a/tests/ui/rfcs/rfc-2632-const-trait-impl/tilde-const-invalid-places.rs b/tests/ui/rfcs/rfc-2632-const-trait-impl/tilde-const-invalid-places.rs new file mode 100644 index 000000000..95f7aaba0 --- /dev/null +++ b/tests/ui/rfcs/rfc-2632-const-trait-impl/tilde-const-invalid-places.rs @@ -0,0 +1,7 @@ +#![feature(const_trait_impl)] +#![feature(associated_type_bounds)] + +struct TildeQuestion<T: ~const ?Sized>(std::marker::PhantomData<T>); +//~^ ERROR `~const` and `?` are mutually exclusive + +fn main() {} diff --git a/tests/ui/rfcs/rfc-2632-const-trait-impl/tilde-const-invalid-places.stderr b/tests/ui/rfcs/rfc-2632-const-trait-impl/tilde-const-invalid-places.stderr new file mode 100644 index 000000000..d20f146df --- /dev/null +++ b/tests/ui/rfcs/rfc-2632-const-trait-impl/tilde-const-invalid-places.stderr @@ -0,0 +1,8 @@ +error: `~const` and `?` are mutually exclusive + --> $DIR/tilde-const-invalid-places.rs:4:25 + | +LL | struct TildeQuestion<T: ~const ?Sized>(std::marker::PhantomData<T>); + | ^^^^^^^^^^^^^ + +error: aborting due to previous error + diff --git a/tests/ui/rfcs/rfc-2632-const-trait-impl/tilde-const-syntax.rs b/tests/ui/rfcs/rfc-2632-const-trait-impl/tilde-const-syntax.rs new file mode 100644 index 000000000..9b3c2cf2a --- /dev/null +++ b/tests/ui/rfcs/rfc-2632-const-trait-impl/tilde-const-syntax.rs @@ -0,0 +1,9 @@ +// compile-flags: -Z parse-only +// check-pass + +#![feature(const_trait_impl)] + +struct S< + T: ~const ?for<'a> Tr<'a> + 'static + ~const std::ops::Add, + T: ~const ?for<'a: 'b> m::Trait<'a>, +>; diff --git a/tests/ui/rfcs/rfc-2632-const-trait-impl/tilde-twice.rs b/tests/ui/rfcs/rfc-2632-const-trait-impl/tilde-twice.rs new file mode 100644 index 000000000..06e4ede8b --- /dev/null +++ b/tests/ui/rfcs/rfc-2632-const-trait-impl/tilde-twice.rs @@ -0,0 +1,6 @@ +// compile-flags: -Z parse-only + +#![feature(const_trait_impl)] + +struct S<T: ~const ~const Tr>; +//~^ ERROR expected identifier, found `~` diff --git a/tests/ui/rfcs/rfc-2632-const-trait-impl/tilde-twice.stderr b/tests/ui/rfcs/rfc-2632-const-trait-impl/tilde-twice.stderr new file mode 100644 index 000000000..928d23e8a --- /dev/null +++ b/tests/ui/rfcs/rfc-2632-const-trait-impl/tilde-twice.stderr @@ -0,0 +1,8 @@ +error: expected identifier, found `~` + --> $DIR/tilde-twice.rs:5:20 + | +LL | struct S<T: ~const ~const Tr>; + | ^ expected identifier + +error: aborting due to previous error + diff --git a/tests/ui/rfcs/rfc-2632-const-trait-impl/tilde_const_on_impl_bound.rs b/tests/ui/rfcs/rfc-2632-const-trait-impl/tilde_const_on_impl_bound.rs new file mode 100644 index 000000000..285cef571 --- /dev/null +++ b/tests/ui/rfcs/rfc-2632-const-trait-impl/tilde_const_on_impl_bound.rs @@ -0,0 +1,17 @@ +// check-pass +#![feature(const_trait_impl)] + +#[const_trait] +trait Foo { + fn foo(&self) {} +} + +struct Bar<T>(T); + +impl<T: ~const Foo> Bar<T> { + const fn foo(&self) { + self.0.foo() + } +} + +fn main() {} diff --git a/tests/ui/rfcs/rfc-2632-const-trait-impl/trait-default-body-stability.rs b/tests/ui/rfcs/rfc-2632-const-trait-impl/trait-default-body-stability.rs new file mode 100644 index 000000000..8d56295e7 --- /dev/null +++ b/tests/ui/rfcs/rfc-2632-const-trait-impl/trait-default-body-stability.rs @@ -0,0 +1,50 @@ +// known-bug: #110395 + +#![feature(staged_api)] +#![feature(const_trait_impl)] +#![feature(const_t_try)] +#![feature(const_try)] +#![feature(try_trait_v2)] + +#![stable(feature = "foo", since = "1.0")] + +use std::ops::{ControlFlow, FromResidual, Try}; + +#[stable(feature = "foo", since = "1.0")] +pub struct T; + +#[stable(feature = "foo", since = "1.0")] +#[rustc_const_unstable(feature = "const_t_try", issue = "none")] +impl const Try for T { + type Output = T; + type Residual = T; + + fn from_output(t: T) -> T { + t + } + + fn branch(self) -> ControlFlow<T, T> { + ControlFlow::Continue(self) + } +} + +#[stable(feature = "foo", since = "1.0")] +#[rustc_const_unstable(feature = "const_t_try", issue = "none")] +impl const FromResidual for T { + fn from_residual(t: T) -> T { + t + } +} + +#[stable(feature = "foo", since = "1.0")] +#[const_trait] +pub trait Tr { + #[stable(feature = "foo", since = "1.0")] + fn bar() -> T { + T? + // Should be allowed. + // Must enable unstable features to call this trait fn in const contexts. + } +} + +fn main() {} diff --git a/tests/ui/rfcs/rfc-2632-const-trait-impl/trait-default-body-stability.stderr b/tests/ui/rfcs/rfc-2632-const-trait-impl/trait-default-body-stability.stderr new file mode 100644 index 000000000..35dc1ca12 --- /dev/null +++ b/tests/ui/rfcs/rfc-2632-const-trait-impl/trait-default-body-stability.stderr @@ -0,0 +1,20 @@ +error: const `impl` for trait `Try` which is not marked with `#[const_trait]` + --> $DIR/trait-default-body-stability.rs:18:12 + | +LL | impl const Try for T { + | ^^^ + | + = note: marking a trait with `#[const_trait]` ensures all default method bodies are `const` + = note: adding a non-const method body in the future would be a breaking change + +error: const `impl` for trait `FromResidual` which is not marked with `#[const_trait]` + --> $DIR/trait-default-body-stability.rs:33:12 + | +LL | impl const FromResidual for T { + | ^^^^^^^^^^^^ + | + = note: marking a trait with `#[const_trait]` ensures all default method bodies are `const` + = note: adding a non-const method body in the future would be a breaking change + +error: aborting due to 2 previous errors + diff --git a/tests/ui/rfcs/rfc-2632-const-trait-impl/trait-method-ptr-in-consts-ice.rs b/tests/ui/rfcs/rfc-2632-const-trait-impl/trait-method-ptr-in-consts-ice.rs new file mode 100644 index 000000000..7d7cb967c --- /dev/null +++ b/tests/ui/rfcs/rfc-2632-const-trait-impl/trait-method-ptr-in-consts-ice.rs @@ -0,0 +1,23 @@ +// check-pass + +struct LazyLock<T> { + data: (Option<T>, fn() -> T), +} + +impl<T> LazyLock<T> { + pub const fn new(f: fn() -> T) -> LazyLock<T> { + LazyLock { data: (None, f) } + } +} + +struct A<T = i32>(Option<T>); + +impl<T> Default for A<T> { + fn default() -> Self { + A(None) + } +} + +static EMPTY_SET: LazyLock<A<i32>> = LazyLock::new(A::default); + +fn main() {} diff --git a/tests/ui/rfcs/rfc-2632-const-trait-impl/trait-where-clause-const.rs b/tests/ui/rfcs/rfc-2632-const-trait-impl/trait-where-clause-const.rs new file mode 100644 index 000000000..bfe98b98c --- /dev/null +++ b/tests/ui/rfcs/rfc-2632-const-trait-impl/trait-where-clause-const.rs @@ -0,0 +1,31 @@ +// Like trait-where-clause.rs, but we are calling from a const context. +// Checking the validity of traits' where clauses happen at a later stage. +// (`rustc_const_eval` instead of `rustc_hir_analysis`) Therefore one file as a +// test is not enough. +#![feature(const_trait_impl)] + +#[const_trait] +trait Bar {} + +#[const_trait] +trait Foo { + fn a(); + fn b() where Self: ~const Bar; + fn c<T: ~const Bar>(); +} + +const fn test1<T: ~const Foo + Bar>() { + T::a(); + T::b(); + //~^ ERROR the trait bound + T::c::<T>(); + //~^ ERROR the trait bound +} + +const fn test2<T: ~const Foo + ~const Bar>() { + T::a(); + T::b(); + T::c::<T>(); +} + +fn main() {} diff --git a/tests/ui/rfcs/rfc-2632-const-trait-impl/trait-where-clause-const.stderr b/tests/ui/rfcs/rfc-2632-const-trait-impl/trait-where-clause-const.stderr new file mode 100644 index 000000000..f2846b6a6 --- /dev/null +++ b/tests/ui/rfcs/rfc-2632-const-trait-impl/trait-where-clause-const.stderr @@ -0,0 +1,35 @@ +error[E0277]: the trait bound `T: ~const Bar` is not satisfied + --> $DIR/trait-where-clause-const.rs:19:5 + | +LL | T::b(); + | ^^^^^^ the trait `~const Bar` is not implemented for `T` + | +note: the trait `Bar` is implemented for `T`, but that implementation is not `const` + --> $DIR/trait-where-clause-const.rs:19:5 + | +LL | T::b(); + | ^^^^^^ +help: consider further restricting this bound + | +LL | const fn test1<T: ~const Foo + Bar + ~const Bar>() { + | ++++++++++++ + +error[E0277]: the trait bound `T: ~const Bar` is not satisfied + --> $DIR/trait-where-clause-const.rs:21:5 + | +LL | T::c::<T>(); + | ^^^^^^^^^^^ the trait `~const Bar` is not implemented for `T` + | +note: the trait `Bar` is implemented for `T`, but that implementation is not `const` + --> $DIR/trait-where-clause-const.rs:21:5 + | +LL | T::c::<T>(); + | ^^^^^^^^^^^ +help: consider further restricting this bound + | +LL | const fn test1<T: ~const Foo + Bar + ~const Bar>() { + | ++++++++++++ + +error: aborting due to 2 previous errors + +For more information about this error, try `rustc --explain E0277`. diff --git a/tests/ui/rfcs/rfc-2632-const-trait-impl/trait-where-clause-run.rs b/tests/ui/rfcs/rfc-2632-const-trait-impl/trait-where-clause-run.rs new file mode 100644 index 000000000..4b8b00406 --- /dev/null +++ b/tests/ui/rfcs/rfc-2632-const-trait-impl/trait-where-clause-run.rs @@ -0,0 +1,41 @@ +// run-pass + +#![feature(const_trait_impl)] + +#[const_trait] +trait Bar { + fn bar() -> u8; +} + +#[const_trait] +trait Foo { + fn foo() -> u8 where Self: ~const Bar { + <Self as Bar>::bar() * 6 + } +} + +struct NonConst; +struct Const; + +impl Bar for NonConst { + fn bar() -> u8 { + 3 + } +} + +impl Foo for NonConst {} + +impl const Bar for Const { + fn bar() -> u8 { + 4 + } +} + +impl const Foo for Const {} + +fn main() { + const ANS1: u8 = Const::foo(); + let ans2 = NonConst::foo(); + + assert_eq!(ANS1 + ans2, 42); +} diff --git a/tests/ui/rfcs/rfc-2632-const-trait-impl/trait-where-clause-self-referential.rs b/tests/ui/rfcs/rfc-2632-const-trait-impl/trait-where-clause-self-referential.rs new file mode 100644 index 000000000..3b028ac48 --- /dev/null +++ b/tests/ui/rfcs/rfc-2632-const-trait-impl/trait-where-clause-self-referential.rs @@ -0,0 +1,24 @@ +// check-pass + +#![feature(const_trait_impl)] + +#[const_trait] +trait Foo { + fn bar() where Self: ~const Foo; +} + +struct S; + +impl Foo for S { + fn bar() {} +} + +fn baz<T: Foo>() { + T::bar(); +} + +const fn qux<T: ~const Foo>() { + T::bar(); +} + +fn main() {} diff --git a/tests/ui/rfcs/rfc-2632-const-trait-impl/trait-where-clause.rs b/tests/ui/rfcs/rfc-2632-const-trait-impl/trait-where-clause.rs new file mode 100644 index 000000000..85ca5fc90 --- /dev/null +++ b/tests/ui/rfcs/rfc-2632-const-trait-impl/trait-where-clause.rs @@ -0,0 +1,26 @@ +#![feature(const_trait_impl)] + +#[const_trait] +trait Bar {} + +trait Foo { + fn a(); + fn b() where Self: ~const Bar; + fn c<T: ~const Bar>(); +} + +fn test1<T: Foo>() { + T::a(); + T::b(); + //~^ ERROR the trait bound + T::c::<T>(); + //~^ ERROR the trait bound +} + +fn test2<T: Foo + Bar>() { + T::a(); + T::b(); + T::c::<T>(); +} + +fn main() {} diff --git a/tests/ui/rfcs/rfc-2632-const-trait-impl/trait-where-clause.stderr b/tests/ui/rfcs/rfc-2632-const-trait-impl/trait-where-clause.stderr new file mode 100644 index 000000000..11f0c4016 --- /dev/null +++ b/tests/ui/rfcs/rfc-2632-const-trait-impl/trait-where-clause.stderr @@ -0,0 +1,35 @@ +error[E0277]: the trait bound `T: Bar` is not satisfied + --> $DIR/trait-where-clause.rs:14:5 + | +LL | T::b(); + | ^^^^ the trait `Bar` is not implemented for `T` + | +note: required by a bound in `Foo::b` + --> $DIR/trait-where-clause.rs:8:24 + | +LL | fn b() where Self: ~const Bar; + | ^^^^^^^^^^ required by this bound in `Foo::b` +help: consider further restricting this bound + | +LL | fn test1<T: Foo + Bar>() { + | +++++ + +error[E0277]: the trait bound `T: Bar` is not satisfied + --> $DIR/trait-where-clause.rs:16:12 + | +LL | T::c::<T>(); + | ^ the trait `Bar` is not implemented for `T` + | +note: required by a bound in `Foo::c` + --> $DIR/trait-where-clause.rs:9:13 + | +LL | fn c<T: ~const Bar>(); + | ^^^^^^^^^^ required by this bound in `Foo::c` +help: consider further restricting this bound + | +LL | fn test1<T: Foo + Bar>() { + | +++++ + +error: aborting due to 2 previous errors + +For more information about this error, try `rustc --explain E0277`. diff --git a/tests/ui/rfcs/rfc-2632-const-trait-impl/without-tilde.rs b/tests/ui/rfcs/rfc-2632-const-trait-impl/without-tilde.rs new file mode 100644 index 000000000..d63381b5f --- /dev/null +++ b/tests/ui/rfcs/rfc-2632-const-trait-impl/without-tilde.rs @@ -0,0 +1,6 @@ +// compile-flags: -Z parse-only + +#![feature(const_trait_impl)] + +struct S<T: const Tr>; +//~^ ERROR const bounds must start with `~` diff --git a/tests/ui/rfcs/rfc-2632-const-trait-impl/without-tilde.stderr b/tests/ui/rfcs/rfc-2632-const-trait-impl/without-tilde.stderr new file mode 100644 index 000000000..31300354a --- /dev/null +++ b/tests/ui/rfcs/rfc-2632-const-trait-impl/without-tilde.stderr @@ -0,0 +1,10 @@ +error: const bounds must start with `~` + --> $DIR/without-tilde.rs:5:13 + | +LL | struct S<T: const Tr>; + | -^^^^ + | | + | help: add `~`: `~` + +error: aborting due to previous error + |