diff options
author | Daniel Baumann <daniel.baumann@progress-linux.org> | 2024-04-17 12:19:13 +0000 |
---|---|---|
committer | Daniel Baumann <daniel.baumann@progress-linux.org> | 2024-04-17 12:19:13 +0000 |
commit | 218caa410aa38c29984be31a5229b9fa717560ee (patch) | |
tree | c54bd55eeb6e4c508940a30e94c0032fbd45d677 /tests/ui/consts/control-flow | |
parent | Releasing progress-linux version 1.67.1+dfsg1-1~progress7.99u1. (diff) | |
download | rustc-218caa410aa38c29984be31a5229b9fa717560ee.tar.xz rustc-218caa410aa38c29984be31a5229b9fa717560ee.zip |
Merging upstream version 1.68.2+dfsg1.
Signed-off-by: Daniel Baumann <daniel.baumann@progress-linux.org>
Diffstat (limited to 'tests/ui/consts/control-flow')
23 files changed, 739 insertions, 0 deletions
diff --git a/tests/ui/consts/control-flow/assert.rs b/tests/ui/consts/control-flow/assert.rs new file mode 100644 index 000000000..9d17f65b9 --- /dev/null +++ b/tests/ui/consts/control-flow/assert.rs @@ -0,0 +1,8 @@ +// Test that `assert` works in consts. + +const _: () = assert!(true); + +const _: () = assert!(false); +//~^ ERROR evaluation of constant value failed + +fn main() {} diff --git a/tests/ui/consts/control-flow/assert.stderr b/tests/ui/consts/control-flow/assert.stderr new file mode 100644 index 000000000..8b1ca183d --- /dev/null +++ b/tests/ui/consts/control-flow/assert.stderr @@ -0,0 +1,11 @@ +error[E0080]: evaluation of constant value failed + --> $DIR/assert.rs:5:15 + | +LL | const _: () = assert!(false); + | ^^^^^^^^^^^^^^ the evaluated program panicked at 'assertion failed: false', $DIR/assert.rs:5:15 + | + = note: this error originates in the macro `assert` (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 E0080`. diff --git a/tests/ui/consts/control-flow/basics.rs b/tests/ui/consts/control-flow/basics.rs new file mode 100644 index 000000000..02e5501f1 --- /dev/null +++ b/tests/ui/consts/control-flow/basics.rs @@ -0,0 +1,82 @@ +// Test basic functionality of control flow in a const context. + +// run-pass + +const X: u32 = 4; +const Y: u32 = 5; + +const ABS_DIFF: u32 = if X < Y { + Y - X +} else { + X - Y +}; + +const fn abs_diff(a: u32, b: u32) -> u32 { + match (a, b) { + (big, little) if big > little => big - little, + (little, big) => big - little, + } +} + +const fn gcd(a: u32, b: u32) -> u32 { + if b == 0 { + return a; + } + + gcd(b, a % b) +} + +const fn fib(n: u64) -> u64 { + if n == 0 { + return 0; + } + + let mut fib = (0, 1); + let mut i = 1; + while i < n { + fib = (fib.1, fib.0 + fib.1); + i += 1; + } + + fib.1 +} + +const fn is_prime(n: u64) -> bool { + if n % 2 == 0 { + return false; + } + + let mut div = 3; + loop { + if n % div == 0 { + return false; + } + + if div * div > n { + return true; + } + + div += 2; + } +} + +macro_rules! const_assert { + ($expr:expr) => { + const _: () = assert!($expr); + assert!($expr); + } +} + +fn main() { + const_assert!(abs_diff(4, 5) == abs_diff(5, 4)); + const_assert!(ABS_DIFF == abs_diff(5, 4)); + + const_assert!(gcd(48, 18) == 6); + const_assert!(gcd(18, 48) == 6); + + const_assert!(fib(2) == 1); + const_assert!(fib(8) == 21); + + const_assert!(is_prime(113)); + const_assert!(!is_prime(117)); +} diff --git a/tests/ui/consts/control-flow/drop-fail.precise.stderr b/tests/ui/consts/control-flow/drop-fail.precise.stderr new file mode 100644 index 000000000..93b5f257e --- /dev/null +++ b/tests/ui/consts/control-flow/drop-fail.precise.stderr @@ -0,0 +1,15 @@ +error[E0493]: destructor of `Option<Vec<i32>>` cannot be evaluated at compile-time + --> $DIR/drop-fail.rs:8:9 + | +LL | let x = Some(Vec::new()); + | ^ the destructor for this type cannot be evaluated in constants + +error[E0493]: destructor of `Option<Vec<i32>>` cannot be evaluated at compile-time + --> $DIR/drop-fail.rs:39:9 + | +LL | let mut tmp = None; + | ^^^^^^^ the destructor for this type cannot be evaluated in constants + +error: aborting due to 2 previous errors + +For more information about this error, try `rustc --explain E0493`. diff --git a/tests/ui/consts/control-flow/drop-fail.rs b/tests/ui/consts/control-flow/drop-fail.rs new file mode 100644 index 000000000..41341f312 --- /dev/null +++ b/tests/ui/consts/control-flow/drop-fail.rs @@ -0,0 +1,62 @@ +// revisions: stock precise + +#![cfg_attr(precise, feature(const_precise_live_drops))] + +// `x` is *not* always moved into the final value and may be dropped inside the initializer. +const _: Option<Vec<i32>> = { + let y: Option<Vec<i32>> = None; + let x = Some(Vec::new()); + //[stock,precise]~^ ERROR destructor of + + if true { + x + } else { + y + } +}; + +// We only clear `NeedsDrop` if a local is moved from in entirely. This is a shortcoming of the +// existing analysis. +const _: Vec<i32> = { + let vec_tuple = (Vec::new(),); + //[stock]~^ ERROR destructor of + + vec_tuple.0 +}; + +// This applies to single-field enum variants as well. +const _: Vec<i32> = { + let x: Result<_, Vec<i32>> = Ok(Vec::new()); + //[stock]~^ ERROR destructor of + + match x { + Ok(x) | Err(x) => x, + } +}; + +const _: Option<Vec<i32>> = { + let mut some = Some(Vec::new()); + let mut tmp = None; + //[stock,precise]~^ ERROR destructor of + + let mut i = 0; + while i < 10 { + tmp = some; + some = None; + + // We can escape the loop with `Some` still in `tmp`, + // which would require that it be dropped at the end of the block. + if i > 100 { + break; + } + + some = tmp; + tmp = None; + + i += 1; + } + + some +}; + +fn main() {} diff --git a/tests/ui/consts/control-flow/drop-fail.stock.stderr b/tests/ui/consts/control-flow/drop-fail.stock.stderr new file mode 100644 index 000000000..2cc856802 --- /dev/null +++ b/tests/ui/consts/control-flow/drop-fail.stock.stderr @@ -0,0 +1,39 @@ +error[E0493]: destructor of `Option<Vec<i32>>` cannot be evaluated at compile-time + --> $DIR/drop-fail.rs:8:9 + | +LL | let x = Some(Vec::new()); + | ^ the destructor for this type cannot be evaluated in constants +... +LL | }; + | - value is dropped here + +error[E0493]: destructor of `(Vec<i32>,)` cannot be evaluated at compile-time + --> $DIR/drop-fail.rs:21:9 + | +LL | let vec_tuple = (Vec::new(),); + | ^^^^^^^^^ the destructor for this type cannot be evaluated in constants +... +LL | }; + | - value is dropped here + +error[E0493]: destructor of `Result<Vec<i32>, Vec<i32>>` cannot be evaluated at compile-time + --> $DIR/drop-fail.rs:29:9 + | +LL | let x: Result<_, Vec<i32>> = Ok(Vec::new()); + | ^ the destructor for this type cannot be evaluated in constants +... +LL | }; + | - value is dropped here + +error[E0493]: destructor of `Option<Vec<i32>>` cannot be evaluated at compile-time + --> $DIR/drop-fail.rs:39:9 + | +LL | let mut tmp = None; + | ^^^^^^^ the destructor for this type cannot be evaluated in constants +... +LL | }; + | - value is dropped here + +error: aborting due to 4 previous errors + +For more information about this error, try `rustc --explain E0493`. diff --git a/tests/ui/consts/control-flow/drop-pass.rs b/tests/ui/consts/control-flow/drop-pass.rs new file mode 100644 index 000000000..2a6d12768 --- /dev/null +++ b/tests/ui/consts/control-flow/drop-pass.rs @@ -0,0 +1,46 @@ +// run-pass +// revisions: stock precise + +#![allow(unused)] +#![cfg_attr(precise, feature(const_precise_live_drops))] + +// `x` is always moved into the final value and is not dropped inside the initializer. +const _: Option<Vec<i32>> = { + let y: Option<Vec<i32>> = None; + let x = Some(Vec::new()); + + if true { + x + } else { + x + } +}; + +const _: Option<Vec<i32>> = { + let x = Some(Vec::new()); + match () { + () => x, + } +}; + +const _: Option<Vec<i32>> = { + let mut some = Some(Vec::new()); + let mut tmp = None; + + let mut i = 0; + while i < 10 { + tmp = some; + some = None; + + // We can never exit the loop with `Some` in `tmp`. + + some = tmp; + tmp = None; + + i += 1; + } + + some +}; + +fn main() {} diff --git a/tests/ui/consts/control-flow/drop-precise.rs b/tests/ui/consts/control-flow/drop-precise.rs new file mode 100644 index 000000000..4ecc5ef78 --- /dev/null +++ b/tests/ui/consts/control-flow/drop-precise.rs @@ -0,0 +1,18 @@ +// run-pass +// gate-test-const_precise_live_drops + +#![feature(const_precise_live_drops)] + +const _: Vec<i32> = { + let vec_tuple = (Vec::new(),); + vec_tuple.0 +}; + +const _: Vec<i32> = { + let x: Result<_, Vec<i32>> = Ok(Vec::new()); + match x { + Ok(x) | Err(x) => x, + } +}; + +fn main() {} diff --git a/tests/ui/consts/control-flow/exhaustive-c-like-enum-match.rs b/tests/ui/consts/control-flow/exhaustive-c-like-enum-match.rs new file mode 100644 index 000000000..4320133df --- /dev/null +++ b/tests/ui/consts/control-flow/exhaustive-c-like-enum-match.rs @@ -0,0 +1,29 @@ +// Test for <https://github.com/rust-lang/rust/issues/66756> + +// check-pass + +enum E { + A, + B, + C +} + +const fn f(e: E) { + match e { + E::A => {} + E::B => {} + E::C => {} + } +} + +const fn g(e: E) -> usize { + match e { + _ => 0 + } +} + +fn main() { + const X: usize = g(E::C); + assert_eq!(X, 0); + assert_eq!(g(E::A), 0); +} diff --git a/tests/ui/consts/control-flow/feature-gate-const-if-match.rs b/tests/ui/consts/control-flow/feature-gate-const-if-match.rs new file mode 100644 index 000000000..cb66bc753 --- /dev/null +++ b/tests/ui/consts/control-flow/feature-gate-const-if-match.rs @@ -0,0 +1,96 @@ +// check-pass + +const _: i32 = if true { 5 } else { 6 }; + +const _: i32 = if let Some(true) = Some(false) { 0 } else { 1 }; + +const _: i32 = match 1 { + 2 => 3, + 4 => 5, + _ => 0, +}; + +static FOO: i32 = { + let x = if true { 0 } else { 1 }; + let x = match x { + 0 => 1, + _ => 0, + }; + if let Some(x) = Some(x) { x } else { 1 } +}; + +static mut BAR: i32 = { + let x = if true { 0 } else { 1 }; + let x = match x { + 0 => 1, + _ => 0, + }; + if let Some(x) = Some(x) { x } else { 1 } +}; + +const fn if_() -> i32 { + if true { 5 } else { 6 } +} + +const fn if_let(a: Option<bool>) -> i32 { + if let Some(true) = a { 0 } else { 1 } +} + +const fn match_(i: i32) -> i32 { + match i { + i if i > 10 => i, + 1 => 2, + _ => 0, + } +} + +pub trait Foo { + const IF: i32 = if true { 5 } else { 6 }; + const IF_LET: i32 = if let Some(true) = None { 5 } else { 6 }; + const MATCH: i32 = match 0 { + 1 => 2, + _ => 0, + }; +} + +impl Foo for () { + const IF: i32 = if true { 5 } else { 6 }; + const IF_LET: i32 = if let Some(true) = None { 5 } else { 6 }; + const MATCH: i32 = match 0 { + 1 => 2, + _ => 0, + }; +} + +fn non_const_outside() { + const fn const_inside(y: bool) -> i32 { + let x = if y { 0 } else { 1 }; + let x = match x { + 0 => 1, + _ => 0, + }; + if let Some(x) = Some(x) { x } else { 1 } + } +} + +const fn const_outside() { + fn non_const_inside(y: bool) -> i32 { + let x = if y { 0 } else { 1 }; + let x = match x { + 0 => 1, + _ => 0, + }; + if let Some(x) = Some(x) { x } else { 1 } + } +} + +fn main() { + let _ = [0; { + let x = if false { 0 } else { 1 }; + let x = match x { + 0 => 1, + _ => 0, + }; + if let Some(x) = Some(x) { x } else { 1 } + }]; +} diff --git a/tests/ui/consts/control-flow/interior-mutability.rs b/tests/ui/consts/control-flow/interior-mutability.rs new file mode 100644 index 000000000..a6d44237b --- /dev/null +++ b/tests/ui/consts/control-flow/interior-mutability.rs @@ -0,0 +1,43 @@ +// Ensure that *any* assignment to the return place of a value with interior mutability +// disqualifies it from promotion. + +use std::cell::Cell; + +const X: Option<Cell<i32>> = { + let mut x = None; + if false { + x = Some(Cell::new(4)); + } + x +}; + +const Y: Option<Cell<i32>> = { + let mut y = Some(Cell::new(4)); + if true { + y = None; + } + y +}; + +const Z: Option<Cell<i32>> = { + let mut z = None; + let mut i = 0; + while i < 10 { + if i == 8 { + z = Some(Cell::new(4)); + } + + if i == 9 { + z = None; + } + + i += 1; + } + z +}; + +fn main() { + let x: &'static _ = &X; //~ ERROR temporary value dropped while borrowed + let y: &'static _ = &Y; //~ ERROR temporary value dropped while borrowed + let z: &'static _ = &Z; //~ ERROR temporary value dropped while borrowed +} diff --git a/tests/ui/consts/control-flow/interior-mutability.stderr b/tests/ui/consts/control-flow/interior-mutability.stderr new file mode 100644 index 000000000..db2ffb91b --- /dev/null +++ b/tests/ui/consts/control-flow/interior-mutability.stderr @@ -0,0 +1,35 @@ +error[E0716]: temporary value dropped while borrowed + --> $DIR/interior-mutability.rs:40:26 + | +LL | let x: &'static _ = &X; + | ---------- ^ creates a temporary value which is freed while still in use + | | + | type annotation requires that borrow lasts for `'static` +... +LL | } + | - temporary value is freed at the end of this statement + +error[E0716]: temporary value dropped while borrowed + --> $DIR/interior-mutability.rs:41:26 + | +LL | let y: &'static _ = &Y; + | ---------- ^ creates a temporary value which is freed while still in use + | | + | type annotation requires that borrow lasts for `'static` +LL | let z: &'static _ = &Z; +LL | } + | - temporary value is freed at the end of this statement + +error[E0716]: temporary value dropped while borrowed + --> $DIR/interior-mutability.rs:42:26 + | +LL | let z: &'static _ = &Z; + | ---------- ^ creates a temporary value which is freed while still in use + | | + | type annotation requires that borrow lasts for `'static` +LL | } + | - temporary value is freed at the end of this statement + +error: aborting due to 3 previous errors + +For more information about this error, try `rustc --explain E0716`. diff --git a/tests/ui/consts/control-flow/issue-46843.rs b/tests/ui/consts/control-flow/issue-46843.rs new file mode 100644 index 000000000..ddddc8505 --- /dev/null +++ b/tests/ui/consts/control-flow/issue-46843.rs @@ -0,0 +1,16 @@ +enum Thing { + This, + That, +} + +fn non_const() -> Thing { + Thing::This +} + +pub const Q: i32 = match non_const() { + //~^ ERROR cannot call non-const fn + Thing::This => 1, + Thing::That => 0 +}; + +fn main() {} diff --git a/tests/ui/consts/control-flow/issue-46843.stderr b/tests/ui/consts/control-flow/issue-46843.stderr new file mode 100644 index 000000000..66227f61e --- /dev/null +++ b/tests/ui/consts/control-flow/issue-46843.stderr @@ -0,0 +1,11 @@ +error[E0015]: cannot call non-const fn `non_const` in constants + --> $DIR/issue-46843.rs:10:26 + | +LL | pub const Q: i32 = match non_const() { + | ^^^^^^^^^^^ + | + = note: calls in constants 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/consts/control-flow/issue-50577.rs b/tests/ui/consts/control-flow/issue-50577.rs new file mode 100644 index 000000000..beb9a44fc --- /dev/null +++ b/tests/ui/consts/control-flow/issue-50577.rs @@ -0,0 +1,6 @@ +fn main() { + enum Foo { + Drop = assert_eq!(1, 1), + //~^ ERROR `if` may be missing an `else` clause + } +} diff --git a/tests/ui/consts/control-flow/issue-50577.stderr b/tests/ui/consts/control-flow/issue-50577.stderr new file mode 100644 index 000000000..a931c89f4 --- /dev/null +++ b/tests/ui/consts/control-flow/issue-50577.stderr @@ -0,0 +1,13 @@ +error[E0317]: `if` may be missing an `else` clause + --> $DIR/issue-50577.rs:3:16 + | +LL | Drop = assert_eq!(1, 1), + | ^^^^^^^^^^^^^^^^ expected `isize`, found `()` + | + = note: `if` expressions without `else` evaluate to `()` + = help: consider adding an `else` block that evaluates to the expected type + = note: this error originates in the macro `assert_eq` (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 E0317`. diff --git a/tests/ui/consts/control-flow/loop.rs b/tests/ui/consts/control-flow/loop.rs new file mode 100644 index 000000000..2b8561a26 --- /dev/null +++ b/tests/ui/consts/control-flow/loop.rs @@ -0,0 +1,89 @@ +const _: () = loop { break (); }; + +static FOO: i32 = loop { break 4; }; + +const fn foo() { + loop {} +} + +pub trait Foo { + const BAR: i32 = loop { break 4; }; +} + +impl Foo for () { + const BAR: i32 = loop { break 4; }; +} + +fn non_const_outside() { + const fn const_inside() { + loop {} + } +} + +const fn const_outside() { + fn non_const_inside() { + loop {} + } +} + +fn main() { + let x = [0; { + while false {} + 4 + }]; +} + +const _: i32 = { + let mut x = 0; + + while x < 4 { + x += 1; + } + + while x < 8 { + x += 1; + } + + x +}; + +const _: i32 = { + let mut x = 0; + + for i in 0..4 { //~ ERROR `for` is not allowed in a `const` + x += i; + } + + for i in 0..4 { //~ ERROR `for` is not allowed in a `const` + x += i; + } + + x +}; + +const _: i32 = { + let mut x = 0; + + loop { + x += 1; + if x == 4 { + break; + } + } + + loop { + x += 1; + if x == 8 { + break; + } + } + + x +}; + +const _: i32 = { + let mut x = 0; + while let None = Some(x) { } + while let None = Some(x) { } + x +}; diff --git a/tests/ui/consts/control-flow/loop.stderr b/tests/ui/consts/control-flow/loop.stderr new file mode 100644 index 000000000..5f6ad8c10 --- /dev/null +++ b/tests/ui/consts/control-flow/loop.stderr @@ -0,0 +1,25 @@ +error[E0658]: `for` is not allowed in a `const` + --> $DIR/loop.rs:53:5 + | +LL | / for i in 0..4 { +LL | | x += i; +LL | | } + | |_____^ + | + = note: see issue #87575 <https://github.com/rust-lang/rust/issues/87575> for more information + = help: add `#![feature(const_for)]` to the crate attributes to enable + +error[E0658]: `for` is not allowed in a `const` + --> $DIR/loop.rs:57:5 + | +LL | / for i in 0..4 { +LL | | x += i; +LL | | } + | |_____^ + | + = note: see issue #87575 <https://github.com/rust-lang/rust/issues/87575> for more information + = help: add `#![feature(const_for)]` 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/consts/control-flow/short-circuit-let.rs b/tests/ui/consts/control-flow/short-circuit-let.rs new file mode 100644 index 000000000..8a58d06ac --- /dev/null +++ b/tests/ui/consts/control-flow/short-circuit-let.rs @@ -0,0 +1,36 @@ +// `&&` and `||` were previously forbidden in constants alongside let bindings. + +// run-pass + +const X: i32 = { + let mut x = 0; + let _ = true && { x = 1; false }; + x +}; + +const Y: bool = { + let x = true && false || true; + x +}; + +const fn truthy() -> bool { + let x = true || return false; + x +} + +const fn falsy() -> bool { + let x = true && return false; + x +} + +fn main() { + const _: () = assert!(Y); + assert!(Y); + + const _: () = assert!(X == 1); + assert_eq!(X, 1); + + const _: () = assert!(truthy()); + const _: () = assert!(!falsy()); + assert!(truthy() && !falsy()); +} diff --git a/tests/ui/consts/control-flow/short-circuit.rs b/tests/ui/consts/control-flow/short-circuit.rs new file mode 100644 index 000000000..6abe10785 --- /dev/null +++ b/tests/ui/consts/control-flow/short-circuit.rs @@ -0,0 +1,12 @@ +// run-pass + +// Test that both `&&` and `||` actually short-circuit. +// Formerly, both sides were evaluated unconditionally + +const TRUE: bool = true || panic!(); +const FALSE: bool = false && panic!(); + +fn main() { + assert!(TRUE); + assert!(!FALSE); +} diff --git a/tests/ui/consts/control-flow/single_variant_match_ice.rs b/tests/ui/consts/control-flow/single_variant_match_ice.rs new file mode 100644 index 000000000..b59be00ff --- /dev/null +++ b/tests/ui/consts/control-flow/single_variant_match_ice.rs @@ -0,0 +1,25 @@ +// check-pass + +enum Foo { + Prob, +} + +const FOO: u32 = match Foo::Prob { + Foo::Prob => 42, +}; + +const BAR: u32 = match Foo::Prob { + x => 42, +}; + +impl Foo { + pub const fn as_val(&self) -> u8 { + use self::Foo::*; + + match *self { + Prob => 0x1, + } + } +} + +fn main() {} diff --git a/tests/ui/consts/control-flow/try.rs b/tests/ui/consts/control-flow/try.rs new file mode 100644 index 000000000..7d85a412b --- /dev/null +++ b/tests/ui/consts/control-flow/try.rs @@ -0,0 +1,10 @@ +// The `?` operator is still not const-evaluatable because it calls `From::from` on the error +// variant. + +const fn opt() -> Option<i32> { + let x = Some(2); + x?; //~ ERROR `?` is not allowed in a `const fn` + None +} + +fn main() {} diff --git a/tests/ui/consts/control-flow/try.stderr b/tests/ui/consts/control-flow/try.stderr new file mode 100644 index 000000000..5aeec8fbf --- /dev/null +++ b/tests/ui/consts/control-flow/try.stderr @@ -0,0 +1,12 @@ +error[E0658]: `?` is not allowed in a `const fn` + --> $DIR/try.rs:6:5 + | +LL | x?; + | ^^ + | + = 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`. |