diff options
Diffstat (limited to 'gcc/testsuite/rust')
66 files changed, 949 insertions, 4 deletions
diff --git a/gcc/testsuite/rust/compile/attr-macro.rs b/gcc/testsuite/rust/compile/attr-macro.rs new file mode 100644 index 0000000..de9fce1 --- /dev/null +++ b/gcc/testsuite/rust/compile/attr-macro.rs @@ -0,0 +1,7 @@ +macro_rules! foo { +    () => { #[cfg(all())] 12 } +} + +fn main() -> i32 { +    foo!() +} diff --git a/gcc/testsuite/rust/compile/attr_malformed_doc.rs b/gcc/testsuite/rust/compile/attr_malformed_doc.rs new file mode 100644 index 0000000..6b9ef61 --- /dev/null +++ b/gcc/testsuite/rust/compile/attr_malformed_doc.rs @@ -0,0 +1,3 @@ +// { dg-error "valid forms for the attribute are ...doc.hidden.inline....... and ...doc = . string ..." "" { target *-*-* } .+1 } +#[doc] +trait MyTrait {} diff --git a/gcc/testsuite/rust/compile/attr_malformed_path.rs b/gcc/testsuite/rust/compile/attr_malformed_path.rs new file mode 100644 index 0000000..2bccf37 --- /dev/null +++ b/gcc/testsuite/rust/compile/attr_malformed_path.rs @@ -0,0 +1,3 @@ +#[cfg_attr(target_arch = "x86_64", path = (target_arch = "x86",    path = "x86.rs"))] +mod imp {} +// { dg-error "malformed .path. attribute input" "" { target *-*-* } .-2 } diff --git a/gcc/testsuite/rust/compile/cfg-test.rs b/gcc/testsuite/rust/compile/cfg-test.rs new file mode 100644 index 0000000..a2e870c --- /dev/null +++ b/gcc/testsuite/rust/compile/cfg-test.rs @@ -0,0 +1,4 @@ +#[test] +fn foo() { +    some_function_which_doesnt_exist(); +} diff --git a/gcc/testsuite/rust/compile/enum_discriminant3.rs b/gcc/testsuite/rust/compile/enum_discriminant3.rs new file mode 100644 index 0000000..32c79a5 --- /dev/null +++ b/gcc/testsuite/rust/compile/enum_discriminant3.rs @@ -0,0 +1,8 @@ +const x: isize = 1; +// { dg-warning "unused name" "" { target *-*-* } .-1 } + +fn main() { +    enum Foo { +        Bar = x, +    } +} diff --git a/gcc/testsuite/rust/compile/format_args_concat.rs b/gcc/testsuite/rust/compile/format_args_concat.rs new file mode 100644 index 0000000..b180667 --- /dev/null +++ b/gcc/testsuite/rust/compile/format_args_concat.rs @@ -0,0 +1,51 @@ +#![feature(rustc_attrs)] + +#[rustc_builtin_macro] +macro_rules! format_args { +    () => {}; +} + +#[rustc_builtin_macro] +macro_rules! concat { +    () => {}; +} + +#[lang = "sized"] +trait Sized {} + +pub mod core { +    pub mod fmt { +        pub struct Formatter; +        pub struct Result; + +        pub struct Arguments<'a>; + +        impl<'a> Arguments<'a> { +            pub fn new_v1(_: &'a [&'static str], _: &'a [ArgumentV1<'a>]) -> Arguments<'a> { +                Arguments +            } +        } + +        pub struct ArgumentV1<'a>; + +        impl<'a> ArgumentV1<'a> { +            pub fn new<'b, T>(_: &'b T, _: fn(&T, &mut Formatter) -> Result) -> ArgumentV1 { +                ArgumentV1 +            } +        } + +        pub trait Display { +            fn fmt(&self, _: &mut Formatter) -> Result; +        } + +        impl Display for i32 { +            fn fmt(&self, _: &mut Formatter) -> Result { +                Result +            } +        } +    } +} + +fn main() { +    let _formatted = format_args!(concat!("hello ", "{}"), 15); +} diff --git a/gcc/testsuite/rust/compile/global-path-array.rs b/gcc/testsuite/rust/compile/global-path-array.rs new file mode 100644 index 0000000..c3aa024 --- /dev/null +++ b/gcc/testsuite/rust/compile/global-path-array.rs @@ -0,0 +1,5 @@ +const X: i32 = 1; + +pub fn foo() -> [i32; 1] { +    [::X] +} diff --git a/gcc/testsuite/rust/compile/impl_fnptr.rs b/gcc/testsuite/rust/compile/impl_fnptr.rs new file mode 100644 index 0000000..20c9d88 --- /dev/null +++ b/gcc/testsuite/rust/compile/impl_fnptr.rs @@ -0,0 +1,18 @@ +#[lang = "sized"] +pub trait Sized {} + +#[lang = "eq"] +pub trait PartialEq<Rhs: ?Sized = Self> { +    fn eq(&self, other: &Rhs) -> bool; + +    fn ne(&self, other: &Rhs) -> bool { +        !self.eq(other) +    } +} + +impl<Ret> PartialEq for extern "C" fn() -> Ret { +    #[inline] +    fn eq(&self, other: &Self) -> bool { +        *self as usize == *other as usize +    } +} diff --git a/gcc/testsuite/rust/compile/import_wildcards.rs b/gcc/testsuite/rust/compile/import_wildcards.rs new file mode 100644 index 0000000..3fc3658 --- /dev/null +++ b/gcc/testsuite/rust/compile/import_wildcards.rs @@ -0,0 +1,8 @@ +mod x {} + +mod y {} + +fn main() { +    use x as _; +    use y as _; +} diff --git a/gcc/testsuite/rust/compile/issue-1725-2.rs b/gcc/testsuite/rust/compile/issue-1725-2.rs index 726d967..d6a2d68 100644 --- a/gcc/testsuite/rust/compile/issue-1725-2.rs +++ b/gcc/testsuite/rust/compile/issue-1725-2.rs @@ -26,6 +26,5 @@ pub fn foo<T: core::ops::Add<Output = i32>>(a: T) -> i32 {  pub fn main() {      foo(123f32); -    // { dg-error "type mismatch, expected .i32. but got .f32." "" { target *-*-* } .-1 } -    // { dg-error "bounds not satisfied for f32 .Add. is not satisfied" "" { target *-*-* } .-2 } +    // { dg-error "bounds not satisfied for f32 .Add. is not satisfied" "" { target *-*-* } .-1 }  } diff --git a/gcc/testsuite/rust/compile/issue-2394.rs b/gcc/testsuite/rust/compile/issue-2394.rs index 92f7afc..b5b5394 100644 --- a/gcc/testsuite/rust/compile/issue-2394.rs +++ b/gcc/testsuite/rust/compile/issue-2394.rs @@ -1,5 +1,6 @@  const A: i32 = (1 / 0);  // { dg-error "division by zero" "" { target *-*-* } .-1 } +// { dg-error "is not a constant expression" "" { target *-*-* } .-2 }  fn main() {      let a = 1 / 0; diff --git a/gcc/testsuite/rust/compile/issue-3538.rs b/gcc/testsuite/rust/compile/issue-3538.rs new file mode 100644 index 0000000..7269457 --- /dev/null +++ b/gcc/testsuite/rust/compile/issue-3538.rs @@ -0,0 +1,9 @@ +enum A { +    Value(()), +} + +fn main() { +    let a = A::Value(()); +    a == A::Value; +    // { dg-error "variant expected constructor call" "" { target *-*-* } .-1 } +} diff --git a/gcc/testsuite/rust/compile/issue-3556.rs b/gcc/testsuite/rust/compile/issue-3556.rs new file mode 100644 index 0000000..be7d85a --- /dev/null +++ b/gcc/testsuite/rust/compile/issue-3556.rs @@ -0,0 +1,4 @@ +fn main() { +    let ref mut a @ (ref mut b,); +    // { dg-error "expected T\\?, found tuple" "" { target *-*-* } .-1 } +}
\ No newline at end of file diff --git a/gcc/testsuite/rust/compile/issue-3592.rs b/gcc/testsuite/rust/compile/issue-3592.rs new file mode 100644 index 0000000..34018d1 --- /dev/null +++ b/gcc/testsuite/rust/compile/issue-3592.rs @@ -0,0 +1,7 @@ +pub trait X { +    fn x() { +        fn f(&mut self) {} +        // { dg-error ".self. parameter is only allowed in associated functions" "" { target *-*-* } .-1 } +        f(); +    } +} diff --git a/gcc/testsuite/rust/compile/issue-3645.rs b/gcc/testsuite/rust/compile/issue-3645.rs new file mode 100644 index 0000000..91285f1 --- /dev/null +++ b/gcc/testsuite/rust/compile/issue-3645.rs @@ -0,0 +1,6 @@ +// { dg-warning "unused name 'y'" "" { target *-*-* } 5 } +// { dg-warning "unused name 'z'" "" { target *-*-* } 5 } + +fn main() { +    let (ref y,z) = (1i32, 2u32); +}
\ No newline at end of file diff --git a/gcc/testsuite/rust/compile/issue-3726.rs b/gcc/testsuite/rust/compile/issue-3726.rs new file mode 100644 index 0000000..ced87a5 --- /dev/null +++ b/gcc/testsuite/rust/compile/issue-3726.rs @@ -0,0 +1,17 @@ +pub enum TypeCtor { +    Slice, +    Array, +} +pub struct ApplicationTy(TypeCtor); + +macro_rules! ty_app { +    ($ctor:pat) => { +        ApplicationTy($ctor) +    }; +} + +pub fn foo(ty: ApplicationTy) { +    match ty { +        ty_app!(TypeCtor::Array) => {} +    } +} diff --git a/gcc/testsuite/rust/compile/issue-3898.rs b/gcc/testsuite/rust/compile/issue-3898.rs new file mode 100644 index 0000000..114370c --- /dev/null +++ b/gcc/testsuite/rust/compile/issue-3898.rs @@ -0,0 +1,112 @@ +// { dg-additional-options "-frust-compile-until=lowering" } + +#[lang = "sized"] +trait Sized {} + +enum Result<T, E> { +    Ok(T), +    Err(E), +} + +use Result::{Err, Ok}; + +struct Utf8Error; + +const CONT_MASK: u8 = 15; +const TAG_CONT_U8: u8 = 15; + +#[inline(always)] +pub fn run_utf8_validation(v: &[u8]) -> Result<(), Utf8Error> { +    let mut index = 0; +    let len = 64; + +    let usize_bytes = 8; +    let ascii_block_size = 2 * usize_bytes; +    let blocks_end = if len >= ascii_block_size { +        len - ascii_block_size + 1 +    } else { +        0 +    }; + +    while index < len { +        let old_offset = index; +        macro_rules! err { +            ($error_len: expr) => { +                return Err(Utf8Error) +            }; +        } + +        macro_rules! next { +            () => {{ +                index += 1; +                // we needed data, but there was none: error! +                if index >= len { +                    err!(None) +                } +                v[index] +            }}; +        } + +        let first = v[index]; +        if first >= 128 { +            let w = 15; +            // 2-byte encoding is for codepoints  \u{0080} to  \u{07ff} +            //        first  C2 80        last DF BF +            // 3-byte encoding is for codepoints  \u{0800} to  \u{ffff} +            //        first  E0 A0 80     last EF BF BF +            //   excluding surrogates codepoints  \u{d800} to  \u{dfff} +            //               ED A0 80 to       ED BF BF +            // 4-byte encoding is for codepoints \u{1000}0 to \u{10ff}ff +            //        first  F0 90 80 80  last F4 8F BF BF +            // +            // Use the UTF-8 syntax from the RFC +            // +            // https://tools.ietf.org/html/rfc3629 +            // UTF8-1      = %x00-7F +            // UTF8-2      = %xC2-DF UTF8-tail +            // UTF8-3      = %xE0 %xA0-BF UTF8-tail / %xE1-EC 2( UTF8-tail ) / +            //               %xED %x80-9F UTF8-tail / %xEE-EF 2( UTF8-tail ) +            // UTF8-4      = %xF0 %x90-BF 2( UTF8-tail ) / %xF1-F3 3( UTF8-tail ) / +            //               %xF4 %x80-8F 2( UTF8-tail ) +            match w { +                2 => { +                    if next!() & !CONT_MASK != TAG_CONT_U8 { +                        err!(Some(1)) +                    } +                } +                3 => { +                    match (first, next!()) { +                        (0xE0, 0xA0..=0xBF) +                        | (0xE1..=0xEC, 0x80..=0xBF) +                        | (0xED, 0x80..=0x9F) +                        | (0xEE..=0xEF, 0x80..=0xBF) => {} +                        _ => err!(Some(1)), +                    } +                    if next!() & !CONT_MASK != TAG_CONT_U8 { +                        err!(Some(2)) +                    } +                } +                4 => { +                    match (first, next!()) { +                        (0xF0, 0x90..=0xBF) | (0xF1..=0xF3, 0x80..=0xBF) | (0xF4, 0x80..=0x8F) => {} +                        _ => err!(Some(1)), +                    } +                    if next!() & !CONT_MASK != TAG_CONT_U8 { +                        err!(Some(2)) +                    } +                    if next!() & !CONT_MASK != TAG_CONT_U8 { +                        err!(Some(3)) +                    } +                } +                _ => err!(Some(1)), +            } +            index += 1; +        } else { +            index += 1; +        } +    } + +    Ok(()) +} + +fn main() {} diff --git a/gcc/testsuite/rust/compile/issue-3922.rs b/gcc/testsuite/rust/compile/issue-3922.rs new file mode 100644 index 0000000..3c07f94 --- /dev/null +++ b/gcc/testsuite/rust/compile/issue-3922.rs @@ -0,0 +1,12 @@ +struct S( +    [u8; { +        { +            // { dg-error "mismatched types. expected .... but got ..integer.. .E0308." "" { target *-*-* } .-1 } +            struct Z; +            0 +        } +        0 +    }], +); + +fn main() {} diff --git a/gcc/testsuite/rust/compile/issue-3924.rs b/gcc/testsuite/rust/compile/issue-3924.rs new file mode 100644 index 0000000..cc423ce --- /dev/null +++ b/gcc/testsuite/rust/compile/issue-3924.rs @@ -0,0 +1,6 @@ +pub fn main() { +    const S: usize = 23 as i64; +    // { dg-error {mismatched types, expected .usize. but got .i64.} "" { target *-*-* } .-1 } +    [0; S]; +    () +} diff --git a/gcc/testsuite/rust/compile/issue-3928.rs b/gcc/testsuite/rust/compile/issue-3928.rs new file mode 100644 index 0000000..639d4c8 --- /dev/null +++ b/gcc/testsuite/rust/compile/issue-3928.rs @@ -0,0 +1,12 @@ +// { dg-do compile } +// { dg-options "-fsyntax-only" } + +#![feature(exclusive_range_pattern)] + +fn Foo() { +    let x = 1u32; + +    match x { +        3..-1 => 4, +    }; +} diff --git a/gcc/testsuite/rust/compile/issue-3929-1.rs b/gcc/testsuite/rust/compile/issue-3929-1.rs new file mode 100644 index 0000000..3d7b056 --- /dev/null +++ b/gcc/testsuite/rust/compile/issue-3929-1.rs @@ -0,0 +1,9 @@ +// { dg-options "-w" } +struct S(); + +fn main() { +    let s = S{}; +    match s { +        S{..} => {} +    } +} diff --git a/gcc/testsuite/rust/compile/issue-3929-2.rs b/gcc/testsuite/rust/compile/issue-3929-2.rs new file mode 100644 index 0000000..5f45a7c --- /dev/null +++ b/gcc/testsuite/rust/compile/issue-3929-2.rs @@ -0,0 +1,12 @@ +// { dg-options "-w" } +struct S { +    x: i32, +    y: i32, +} + +fn main() { +    let s = S{x: 1, y: 2}; +    match s { +        S{x: 1, ..} => {} +    } +} diff --git a/gcc/testsuite/rust/compile/issue-3930.rs b/gcc/testsuite/rust/compile/issue-3930.rs new file mode 100644 index 0000000..dfcd19a --- /dev/null +++ b/gcc/testsuite/rust/compile/issue-3930.rs @@ -0,0 +1,4 @@ +// { dg-additional-options "-w" } +fn main() { +    let (a, .., b) = (2, 3); +} diff --git a/gcc/testsuite/rust/compile/issue-3947.rs b/gcc/testsuite/rust/compile/issue-3947.rs new file mode 100644 index 0000000..58ccde6 --- /dev/null +++ b/gcc/testsuite/rust/compile/issue-3947.rs @@ -0,0 +1,10 @@ +enum _Enum { +    A(), +} + +type _E = _Enum; + +// { dg-warning "function is never used: '_a'" "" { target *-*-* } .+1 } +const fn _a() -> _Enum { +    _E::A() +} diff --git a/gcc/testsuite/rust/compile/issue-3958.rs b/gcc/testsuite/rust/compile/issue-3958.rs new file mode 100644 index 0000000..935b512 --- /dev/null +++ b/gcc/testsuite/rust/compile/issue-3958.rs @@ -0,0 +1,11 @@ +// { dg-options "-fsyntax-only" } +trait A { +    fn a(&self) -> <Self as A>::X; +} + +impl A for u32 {} + +fn main() { +    let a: u32 = 0; +    let b: u32 = a.a(); +} diff --git a/gcc/testsuite/rust/compile/issue-3965-1.rs b/gcc/testsuite/rust/compile/issue-3965-1.rs new file mode 100644 index 0000000..291a220 --- /dev/null +++ b/gcc/testsuite/rust/compile/issue-3965-1.rs @@ -0,0 +1,4 @@ +fn main() { +    [(); { continue }]; +    // { dg-error ".continue. outside of a loop .E0268." "" { target *-*-* } .-1 } +} diff --git a/gcc/testsuite/rust/compile/issue-3965-2.rs b/gcc/testsuite/rust/compile/issue-3965-2.rs new file mode 100644 index 0000000..d48503f --- /dev/null +++ b/gcc/testsuite/rust/compile/issue-3965-2.rs @@ -0,0 +1,7 @@ +fn main() { +    loop { continue } + +    [(); {while true {break}; 0}]; + +    [(); {while true {break}; 0}]; +} diff --git a/gcc/testsuite/rust/compile/issue-3966.rs b/gcc/testsuite/rust/compile/issue-3966.rs new file mode 100644 index 0000000..20d3031 --- /dev/null +++ b/gcc/testsuite/rust/compile/issue-3966.rs @@ -0,0 +1,5 @@ +struct S { +    #[cfg_attr()] +    field: u8, +    // { dg-error "malformed .cfg_attr. attribute input" "" { target *-*-* } .-2 } +} diff --git a/gcc/testsuite/rust/compile/issue-3969.rs b/gcc/testsuite/rust/compile/issue-3969.rs new file mode 100644 index 0000000..9608589 --- /dev/null +++ b/gcc/testsuite/rust/compile/issue-3969.rs @@ -0,0 +1,30 @@ +#[lang = "sized"] +pub trait Sized { +    // Empty. +} + +#[lang = "fn_once"] +pub trait FnOnce<Args> { +    #[lang = "fn_once_output"] +    type Output; + +    extern "rust-call" fn call_once(self, args: Args) -> Self::Output; +} + +fn main() { +    [(); { +        while true { +            // { dg-error ".constexpr. loop iteration count exceeds limit" "" { target *-*-* } .-1 } +            break 9; +            // { dg-error "can only .break. with a value inside a .loop. block .E0571." "" { target *-*-* } .-1 } +        } +        51 +    }]; + +    while true { +        break (|| { +            // { dg-error "can only .break. with a value inside a .loop. block .E0571." "" { target *-*-* } .-1 } +            let while_true = 9; +        }); +    } +} diff --git a/gcc/testsuite/rust/compile/issue-3974.rs b/gcc/testsuite/rust/compile/issue-3974.rs new file mode 100644 index 0000000..dfd693a --- /dev/null +++ b/gcc/testsuite/rust/compile/issue-3974.rs @@ -0,0 +1,8 @@ +impl<'a, F> RunUntil<'a, F> { +    // { dg-error "could not resolve type path" "" { target *-*-* } .-1 } +    fn project<'pin>() -> Projection<'pin, 'a, F> { +        // { dg-error "could not resolve type path" "" { target *-*-* } .-1 } +        Self!() +        // { dg-error "could not resolve macro invocation" "" { target *-*-* } .-1 } +    } +} diff --git a/gcc/testsuite/rust/compile/issue-4090-1.rs b/gcc/testsuite/rust/compile/issue-4090-1.rs new file mode 100644 index 0000000..9f83835 --- /dev/null +++ b/gcc/testsuite/rust/compile/issue-4090-1.rs @@ -0,0 +1,68 @@ +mod core { +    mod marker { +        #[lang = "sized"] +        pub trait Sized {} + +        #[lang = "phantom_data"] +        #[stable(feature = "rust1", since = "1.0.0")] +        pub struct PhantomData<T: ?Sized>; + +        #[unstable(feature = "structural_match", issue = "31434")] +        #[lang = "structural_teq"] +        pub trait StructuralEq { +            // Empty. +        } + +        #[unstable(feature = "structural_match", issue = "31434")] +        #[lang = "structural_peq"] +        pub trait StructuralPartialEq { +            // Empty. +        } +    } + +    pub mod cmp { +        use super::marker::Sized; + +        #[lang = "eq"] +        pub trait PartialEq<Rhs: ?Sized = Self> { +            fn eq(&self, other: &Rhs) -> bool; + +            fn ne(&self, other: &Rhs) -> bool { +                !self.eq(other) +            } +        } + +        pub trait Eq: PartialEq<Self> { +            fn assert_receiver_is_total_eq(&self) {} +        } +    } + +    pub mod ptr { + +        use super::cmp::{Eq, PartialEq}; + +        macro_rules! fnptr_impls_safety_abi { +            ($FnTy: ty, $($Arg: ident),*) => { +                #[stable(feature = "fnptr_impls", since = "1.4.0")] +                impl<Ret, $($Arg),*> PartialEq for $FnTy { +                    #[inline] +                    fn eq(&self, other: &Self) -> bool { +                        *self as usize == *other as usize +                    } +                } + +                #[stable(feature = "fnptr_impls", since = "1.4.0")] +                impl<Ret, $($Arg),*> Eq for $FnTy {} + +            } +        } + +        fnptr_impls_safety_abi! { extern "Rust" fn() -> Ret, } +    } +} + +#[derive(PartialEq, Eq)] +struct AllowedBelow { +    // { dg-warning "struct is never constructed" "" { target *-*-* } .-1 } +    f: fn(), +} diff --git a/gcc/testsuite/rust/compile/issue-4090-2.rs b/gcc/testsuite/rust/compile/issue-4090-2.rs new file mode 100644 index 0000000..75d6b7c --- /dev/null +++ b/gcc/testsuite/rust/compile/issue-4090-2.rs @@ -0,0 +1,71 @@ +mod core { +    mod marker { +        #[lang = "sized"] +        pub trait Sized {} + +        #[lang = "phantom_data"] +        #[stable(feature = "rust1", since = "1.0.0")] +        pub struct PhantomData<T: ?Sized>; + +        #[unstable(feature = "structural_match", issue = "31434")] +        #[lang = "structural_teq"] +        pub trait StructuralEq { +            // Empty. +        } + +        #[unstable(feature = "structural_match", issue = "31434")] +        #[lang = "structural_peq"] +        pub trait StructuralPartialEq { +            // Empty. +        } +    } + +    pub mod cmp { +        use super::marker::Sized; + +        #[lang = "eq"] +        pub trait PartialEq<Rhs: ?Sized = Self> { +            fn eq(&self, other: &Rhs) -> bool; + +            fn ne(&self, other: &Rhs) -> bool { +                !self.eq(other) +            } +        } + +        pub trait Eq: PartialEq<Self> { +            fn assert_receiver_is_total_eq(&self) {} +        } +    } + +    pub mod ptr { + +        use super::cmp::{Eq, PartialEq}; + +        macro_rules! fnptr_impls_safety_abi { +            ($FnTy: ty, $($Arg: ident),*) => { +                #[stable(feature = "fnptr_impls", since = "1.4.0")] +                impl<Ret, $($Arg),*> PartialEq for $FnTy { +                    #[inline] +                    fn eq(&self, other: &Self) -> bool { +                        *self as usize == *other as usize +                    } +                } + +                #[stable(feature = "fnptr_impls", since = "1.4.0")] +                impl<Ret, $($Arg),*> Eq for $FnTy {} + +            } +        } + +        fnptr_impls_safety_abi! { extern "Rust" fn() -> Ret, } +        fnptr_impls_safety_abi! { extern "C" fn() -> Ret, } +        fnptr_impls_safety_abi! { unsafe extern "Rust" fn() -> Ret, } +        fnptr_impls_safety_abi! { unsafe extern "C" fn() -> Ret, } +    } +} + +#[derive(PartialEq, Eq)] +struct AllowedBelow { +    // { dg-warning "struct is never constructed" "" { target *-*-* } .-1 } +    f: fn(), +} diff --git a/gcc/testsuite/rust/compile/issue-4139.rs b/gcc/testsuite/rust/compile/issue-4139.rs new file mode 100644 index 0000000..dc62d1c --- /dev/null +++ b/gcc/testsuite/rust/compile/issue-4139.rs @@ -0,0 +1,7 @@ +// { dg-skip-if "" { *-*-* } { "-m32" } { "" } } +const X: i32 = const { +    let a = 0x736f6d6570736575; +    // { dg-error "integer overflows the respective type" "" { target *-*-* } .-1 } +    let b = 14; +    a + b +}; diff --git a/gcc/testsuite/rust/compile/issue-4145.rs b/gcc/testsuite/rust/compile/issue-4145.rs new file mode 100644 index 0000000..98b33ca --- /dev/null +++ b/gcc/testsuite/rust/compile/issue-4145.rs @@ -0,0 +1,13 @@ +// { dg-excess-errors "warnings" } + +struct S { +    field: [u8; { +        #[path = "outer/inner.rs"] +        // { dg-warning "error handling module file for .inner." "#4145" { xfail *-*-* } .+1 } +        mod inner; +        // OK +        0 +    }], +} + +fn main() {} diff --git a/gcc/testsuite/rust/compile/issue-4146.rs b/gcc/testsuite/rust/compile/issue-4146.rs new file mode 100644 index 0000000..efb3ee2 --- /dev/null +++ b/gcc/testsuite/rust/compile/issue-4146.rs @@ -0,0 +1,3 @@ +const _NISIZE_DIV_P: &isize = &(1isize / 0); +// { dg-error "division by zero" "" { target *-*-* } .-1 } +// { dg-error "is not a constant expression" "" { target *-*-* } .-2 } diff --git a/gcc/testsuite/rust/compile/issue-4148.rs b/gcc/testsuite/rust/compile/issue-4148.rs new file mode 100644 index 0000000..599d739 --- /dev/null +++ b/gcc/testsuite/rust/compile/issue-4148.rs @@ -0,0 +1,26 @@ +// { dg-excess-errors "warnings" } + +// TODO: all `xfail` conditions should be changed to `target` once the ICE in #4148 is resolved + +pub fn ret_parens(x: i32) -> i32 { +    // { dg-warning "unnecessary parentheses around block return value" "#4148" { xfail *-*-* } .+1 } +    ((x+1)) +} + +// { dg-warning "unnecessary parentheses around type" "#4148" { xfail *-*-* } .+1 } +// { dg-warning "unnecessary parentheses around pattern" "#4148" { xfail *-*-* } .+1 } +pub fn arg_ret_parens((x): (i32)) -> (i32) { +    // { dg-warning "unnecessary parentheses around block return value" "#4148" { xfail *-*-* } .+1 } +    ((x+1)) +} + +// { dg-warning "unnecessary parentheses around type" "#4148" { xfail *-*-* } .+1 } +pub fn ret_rpit_parens2(x: i32) -> (i32) { +    // { dg-warning "unnecessary parentheses around block return value" "#4148" { xfail *-*-* } .+1 } +    ((x+1)) +} + +pub fn ret_parens3(x: i32) -> i32 { +    // { dg-warning "unnecessary parentheses around block return value" "#4148" { xfail *-*-* } .+1 } +    ((x+1)) +} diff --git a/gcc/testsuite/rust/compile/issue-4155.rs b/gcc/testsuite/rust/compile/issue-4155.rs new file mode 100644 index 0000000..9fae613 --- /dev/null +++ b/gcc/testsuite/rust/compile/issue-4155.rs @@ -0,0 +1,7 @@ +struct Bug { +    inner: [(); match Vec::new { +        f @  |n() => 1 +// { dg-error "failed to parse pattern to bind" "" { target *-*-* } .-1 } +// { dg-error "unexpected token .|. in pattern" "" { target *-*-* } .-2 } +    }], +} diff --git a/gcc/testsuite/rust/compile/issue-4165.rs b/gcc/testsuite/rust/compile/issue-4165.rs new file mode 100644 index 0000000..bc513da --- /dev/null +++ b/gcc/testsuite/rust/compile/issue-4165.rs @@ -0,0 +1,12 @@ +const N: usize = 2; +const ARR: [i32; N] = [42; X]; +// { dg-error {cannot find value .X. in this scope \[E0425\]} "" { target *-*-* } .-1 } +// { dg-error {mismatched types, expected .\[i32; 2]. but got .<tyty::error>. \[E0308\]} "" { target *-*-* } .-2 } +// { dg-error {mismatched types, expected .usize. but got .bool. \[E0308\]} "" { target *-*-* } .-3 } +const X: bool = (N[0] == 99) && (ARR[0] == 0); +// { dg-error {the type .usize. cannot be indexed by .<integer>. \[E0277\]} "" { target *-*-* } .-1 } +// { dg-error {mismatched types, expected .<tyty::error>. but got .<integer>. \[E0308\]} "" { target *-*-* } .-2 } + +fn main() { +    let _ = X; +} diff --git a/gcc/testsuite/rust/compile/issue-4168.rs b/gcc/testsuite/rust/compile/issue-4168.rs new file mode 100644 index 0000000..abb1190 --- /dev/null +++ b/gcc/testsuite/rust/compile/issue-4168.rs @@ -0,0 +1,7 @@ +const fn add(x: usize, y: usize) -> i32 { +    add + y +    // { dg-error "cannot apply operator .+. to types fn .x usize,y usize,. -> i32 and usize" "" { target *-*-* } .-1 } +} +const ARR: [i32; add(1, 2)] = [5, 6, 1]; +// { dg-error "mismatched types, expected .usize. but got .i32. .E0308." "" { target *-*-* } .-1 } +// { dg-error "mismatched types" "" { target *-*-* } .-2 } diff --git a/gcc/testsuite/rust/compile/issue-4212.rs b/gcc/testsuite/rust/compile/issue-4212.rs new file mode 100644 index 0000000..e068e45 --- /dev/null +++ b/gcc/testsuite/rust/compile/issue-4212.rs @@ -0,0 +1,5 @@ +#![derive(PartialOrd, PartialEq)] +// { dg-error "derive attribute cannot be used at crate level" "" { target *-*-* } .-1 } +pub fn check_ge(a: i32, b: i32) -> bool { +    a >= b +} diff --git a/gcc/testsuite/rust/compile/issue-4231.rs b/gcc/testsuite/rust/compile/issue-4231.rs new file mode 100644 index 0000000..4629baa --- /dev/null +++ b/gcc/testsuite/rust/compile/issue-4231.rs @@ -0,0 +1,6 @@ +#[repr = ""] // { dg-error "malformed .repr. attribute" } +struct ThreeInts { +    first: i16, +    second: i8, +    third: i32 +} diff --git a/gcc/testsuite/rust/compile/macros/mbe/macro-issue4054.rs b/gcc/testsuite/rust/compile/macros/mbe/macro-issue4054.rs new file mode 100644 index 0000000..6dcab23 --- /dev/null +++ b/gcc/testsuite/rust/compile/macros/mbe/macro-issue4054.rs @@ -0,0 +1,14 @@ +#[allow(path_statements)] + +macro_rules! array_impl_default { +    {$t:ident} => { +        $t; +        array_impl_default!{} +    }; +    {} => {} +} + +pub fn foo() { +    let x = 12; +    array_impl_default! {x} +} diff --git a/gcc/testsuite/rust/compile/macros/mbe/macro49.rs b/gcc/testsuite/rust/compile/macros/mbe/macro49.rs index 0900f7c..9d63ff1 100644 --- a/gcc/testsuite/rust/compile/macros/mbe/macro49.rs +++ b/gcc/testsuite/rust/compile/macros/mbe/macro49.rs @@ -1,3 +1,14 @@ +#[lang = "sized"] +pub trait Sized {} + +#[lang = "fn_once"] +trait FnOnce<Args> { +    #[lang = "fn_once_output"] +    type Output; + +    extern "rust-call" fn call_once(self, args: Args) -> Self::Output; +} +  macro_rules! closure {      () => {{          14 + 15 diff --git a/gcc/testsuite/rust/compile/macros/mbe/macro58.rs b/gcc/testsuite/rust/compile/macros/mbe/macro58.rs new file mode 100644 index 0000000..d8f7599 --- /dev/null +++ b/gcc/testsuite/rust/compile/macros/mbe/macro58.rs @@ -0,0 +1,12 @@ +pub fn print(a: *const u8) {} +#[macro_export] +macro_rules! pr_warn ( +    ($($arg:tt)*) => ( +        $($crate::print($arg))* +    ) +); + +fn main() { +    pr_warn!("test\0", "test\0"); +    // { dg-error "expecting .;. but .identifier. found" "" { target *-*-* } .-1 } +} diff --git a/gcc/testsuite/rust/compile/match-tuplestructpattern-err.rs b/gcc/testsuite/rust/compile/match-tuplestructpattern-err.rs new file mode 100644 index 0000000..efd1a89 --- /dev/null +++ b/gcc/testsuite/rust/compile/match-tuplestructpattern-err.rs @@ -0,0 +1,14 @@ +fn main() { +    struct A (i32, i32); +    let a = A (0, 1); + +    match a { +        A (1, 2, 3, 4) => {}, +        // { dg-error "this pattern has 4 fields but the corresponding tuple variant has 2 fields .E0023." "" { target *-*-* } .-1 } +        A (1, 2, .., 3, 4) => {}, +        // { dg-error "this pattern has 4 fields but the corresponding tuple variant has 2 fields .E0023." "" { target *-*-* } .-1 } +        A (.., 3, 4, 5) => {}, +        // { dg-error "this pattern has 3 fields but the corresponding tuple variant has 2 fields .E0023." "" { target *-*-* } .-1 } +        _ => {} +    } +}
\ No newline at end of file diff --git a/gcc/testsuite/rust/compile/match-tuplestructpattern-non-variant.rs b/gcc/testsuite/rust/compile/match-tuplestructpattern-non-variant.rs new file mode 100644 index 0000000..cf751cb --- /dev/null +++ b/gcc/testsuite/rust/compile/match-tuplestructpattern-non-variant.rs @@ -0,0 +1,20 @@ +enum Empty {} +enum NonEmpty { +    Foo(i32), +} + +fn f(e: Empty) { +    match e {  +        Empty(0) => {} // { dg-error "expected tuple struct or tuple variant, found enum 'Empty'" } +    } + +    match e { +        Empty(Empty(..)) => {} // { dg-error "expected tuple struct or tuple variant, found enum 'Empty'" } +    } +} + +fn g(e: NonEmpty) { +    match e { +        NonEmpty(0) => {} // { dg-error "expected tuple struct or tuple variant, found enum 'NonEmpty'" } +    } +} diff --git a/gcc/testsuite/rust/compile/match-tuplestructpattern-rest.rs b/gcc/testsuite/rust/compile/match-tuplestructpattern-rest.rs new file mode 100644 index 0000000..4681acb --- /dev/null +++ b/gcc/testsuite/rust/compile/match-tuplestructpattern-rest.rs @@ -0,0 +1,9 @@ +fn main() { +    struct A (i32, i32); +    let a = A (0, 1); + +    match a { +        A (0, ..) => {}, +        _ => {} +    } +} diff --git a/gcc/testsuite/rust/compile/parse_closure_bind.rs b/gcc/testsuite/rust/compile/parse_closure_bind.rs new file mode 100644 index 0000000..1e08197 --- /dev/null +++ b/gcc/testsuite/rust/compile/parse_closure_bind.rs @@ -0,0 +1,19 @@ +// { dg-additional-options "-frust-compile-until=typecheck" } +// TODO: this should typecheck + +#[lang = "sized"] +trait Sized {} + +#[lang = "fn_once"] +pub trait FnOnce<Args> { +    /// The returned type after the call operator is used. +    #[lang = "fn_once_output"] +    type Output; + +    /// Performs the call operation. +    extern "rust-call" fn call_once(self, args: Args) -> Self::Output; +} + +pub fn foo() { +    (|_a @ _b| {}) (1) +} diff --git a/gcc/testsuite/rust/compile/parse_float_dot.rs b/gcc/testsuite/rust/compile/parse_float_dot.rs new file mode 100644 index 0000000..bfe3da2 --- /dev/null +++ b/gcc/testsuite/rust/compile/parse_float_dot.rs @@ -0,0 +1,3 @@ +// floating point literals can't start with a '.' +// TODO: improve the error message emitted here +const X: f32 = .5; // { dg-error ".*" } diff --git a/gcc/testsuite/rust/compile/primitive-import.rs b/gcc/testsuite/rust/compile/primitive-import.rs new file mode 100644 index 0000000..cc750af --- /dev/null +++ b/gcc/testsuite/rust/compile/primitive-import.rs @@ -0,0 +1,7 @@ +mod primitive { +    pub use i32; +} + +pub fn foo() -> primitive::i32 { +    1 +} diff --git a/gcc/testsuite/rust/compile/slice_rest_pattern.rs b/gcc/testsuite/rust/compile/slice_rest_pattern.rs index c27a8dd..bb3c414 100644 --- a/gcc/testsuite/rust/compile/slice_rest_pattern.rs +++ b/gcc/testsuite/rust/compile/slice_rest_pattern.rs @@ -1,5 +1,4 @@ -// { dg-options "-fsyntax-only" } -fn foo(a: &[u32]) { +pub fn foo(a: &[u32]) {      match a {          [first, ..] => {}          [.., last] => {} diff --git a/gcc/testsuite/rust/compile/tuple_index_on_non_tuple.rs b/gcc/testsuite/rust/compile/tuple_index_on_non_tuple.rs new file mode 100644 index 0000000..f94b8c3 --- /dev/null +++ b/gcc/testsuite/rust/compile/tuple_index_on_non_tuple.rs @@ -0,0 +1,15 @@ +enum E { +    V(usize), +} + +struct S { +    field: i32, +} + +fn main() { +    let e = E::V(0); +    let _ = e.0; // { dg-error "expected tuple or tuple struct, found 'E'" } + +    let s = S { field: 0 }; +    let _ = s.0; // { dg-error "expected tuple or tuple struct, found 'S'" } +} diff --git a/gcc/testsuite/rust/compile/tuplepattern-rest-readonly.rs b/gcc/testsuite/rust/compile/tuplepattern-rest-readonly.rs new file mode 100644 index 0000000..db165ef --- /dev/null +++ b/gcc/testsuite/rust/compile/tuplepattern-rest-readonly.rs @@ -0,0 +1,5 @@ +fn main() { +    let (a, .., b) = (1, 1); +    a = 2; // { dg-error "assignment of read-only variable .a." } +    b = 2; // { dg-error "assignment of read-only variable .b." } +}
\ No newline at end of file diff --git a/gcc/testsuite/rust/compile/tuplepattern-restpattern-typecheck-err.rs b/gcc/testsuite/rust/compile/tuplepattern-restpattern-typecheck-err.rs new file mode 100644 index 0000000..d9f7c18 --- /dev/null +++ b/gcc/testsuite/rust/compile/tuplepattern-restpattern-typecheck-err.rs @@ -0,0 +1,8 @@ +fn main() { +    match (1, 2.2, "not 3") { +        // { dg-error "expected a tuple with 3 elements, found one with 5 elements" "" { target *-*-* } .+1 } +        (a, b, .., c, d, e) => { +            let _ = b + c; // { dg-error "cannot apply operator .+. to types <float> and & str" } +        } +    } +}
\ No newline at end of file diff --git a/gcc/testsuite/rust/compile/use_3.rs b/gcc/testsuite/rust/compile/use_3.rs new file mode 100644 index 0000000..2cfe38f --- /dev/null +++ b/gcc/testsuite/rust/compile/use_3.rs @@ -0,0 +1,10 @@ +mod intrinsic { +    pub fn foo() {} +} + +pub mod a { +    pub fn b() { +        use crate::intrinsic; +        intrinsic::foo(); +    } +} diff --git a/gcc/testsuite/rust/compile/use_self_alone.rs b/gcc/testsuite/rust/compile/use_self_alone.rs new file mode 100644 index 0000000..1df923c --- /dev/null +++ b/gcc/testsuite/rust/compile/use_self_alone.rs @@ -0,0 +1,2 @@ +use self; +// { dg-error ".self. imports are only allowed within a { } list" "" { target *-*-* } .-1 } diff --git a/gcc/testsuite/rust/compile/use_self_alone_in_list.rs b/gcc/testsuite/rust/compile/use_self_alone_in_list.rs new file mode 100644 index 0000000..2e87227 --- /dev/null +++ b/gcc/testsuite/rust/compile/use_self_alone_in_list.rs @@ -0,0 +1,7 @@ +struct B; + +use {B as B2, self}; +// { dg-error ".self. import can only appear in an import list with a non-empty prefix" "" { target *-*-* } .-1 } + +use {self}; +// { dg-error ".self. import can only appear in an import list with a non-empty prefix" "" { target *-*-* } .-1 } diff --git a/gcc/testsuite/rust/core/core.exp b/gcc/testsuite/rust/core/core.exp new file mode 100644 index 0000000..330c6d5 --- /dev/null +++ b/gcc/testsuite/rust/core/core.exp @@ -0,0 +1,37 @@ +# Copyright (C) 2025 Free Software Foundation, Inc. + +# This program is free software; you can redistribute it and/or modify +# it under the terms of the GNU General Public License as published by +# the Free Software Foundation; either version 3 of the License, or +# (at your option) any later version. +#  +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the +# GNU General Public License for more details. +#  +# You should have received a copy of the GNU General Public License +# along with GCC; see the file COPYING3.  If not see +# <http://www.gnu.org/licenses/>. + +# Compile test libcore, no torture testing. +# +# Skip torture testing for now, as it'd be slow + +# Load support procs. +load_lib rust-dg.exp + +# Initialize `dg'. +dg-init + +# Main loop. +set saved-dg-do-what-default ${dg-do-what-default} + +set dg-do-what-default "compile" +set individual_timeout 600 +dg-additional-files [lsort [glob -nocomplain $srcdir/../../libgrust/rustc-lib/*]] +dg-runtest $srcdir/../../libgrust/rustc-lib/core/src/lib.rs "-frust-edition=2018 -frust-crate=core -frust-compile-until=astvalidation -w" "" +set dg-do-what-default ${saved-dg-do-what-default} + +# All done. +dg-finish diff --git a/gcc/testsuite/rust/execute/inline_asm_inout_ident.rs b/gcc/testsuite/rust/execute/inline_asm_inout_ident.rs index b0a3d25..324b84d 100644 --- a/gcc/testsuite/rust/execute/inline_asm_inout_ident.rs +++ b/gcc/testsuite/rust/execute/inline_asm_inout_ident.rs @@ -1,3 +1,4 @@ +/* { dg-do run { target x86_64*-*-* } } */  /* { dg-output "Value is: 5\r*\n" } */  #![feature(rustc_attrs)] diff --git a/gcc/testsuite/rust/execute/inline_asm_inout_var.rs b/gcc/testsuite/rust/execute/inline_asm_inout_var.rs index ff101b8..fff432e 100644 --- a/gcc/testsuite/rust/execute/inline_asm_inout_var.rs +++ b/gcc/testsuite/rust/execute/inline_asm_inout_var.rs @@ -1,3 +1,4 @@ +/* { dg-do run { target x86_64*-*-* } } */  /* { dg-output "Value is: 5\r*\n" } */  #![feature(rustc_attrs)] diff --git a/gcc/testsuite/rust/execute/torture/let-identifierpattern-subpattern.rs b/gcc/testsuite/rust/execute/torture/let-identifierpattern-subpattern.rs new file mode 100644 index 0000000..fa1f56e --- /dev/null +++ b/gcc/testsuite/rust/execute/torture/let-identifierpattern-subpattern.rs @@ -0,0 +1,11 @@ +fn main() -> i32 { +    let foo @ (bar, _, _) = (0, 2, 3); +    let mut ret = 1; + +    match foo { +        (0, 2, 3) => { ret = bar }, +        _ => {} +    } + +    ret +}
\ No newline at end of file diff --git a/gcc/testsuite/rust/execute/torture/link-name.rs b/gcc/testsuite/rust/execute/torture/link-name.rs new file mode 100644 index 0000000..1ab1ac1 --- /dev/null +++ b/gcc/testsuite/rust/execute/torture/link-name.rs @@ -0,0 +1,16 @@ +// { dg-additional-options "-fdump-rtl-final" } +// { dg-final { scan-rtl-dump "printf" "final" } } +// { dg-output "gcc\r*\n" } + +extern "C" { +    #[link_name = "printf"] +    fn druckt(fmt: *const i8, ...); +} + +fn main() -> i32 { +    let a = "gcc\0"; + +    unsafe { druckt("%s\n\0" as *const str as *const i8, a as *const str as *const i8); } + +    0 +} diff --git a/gcc/testsuite/rust/execute/torture/match-slicepattern-array-2.rs b/gcc/testsuite/rust/execute/torture/match-slicepattern-array-2.rs new file mode 100644 index 0000000..c6e7762 --- /dev/null +++ b/gcc/testsuite/rust/execute/torture/match-slicepattern-array-2.rs @@ -0,0 +1,27 @@ +// { dg-output "correct\r*" } +extern "C" { +    fn puts(s: *const i8); +} + +fn main() -> i32 { +    let a = [0, 4, 5, 6, 1]; +    let mut ret = 1; + +    match a { +        [1, .., b] => { +            /* should not take this path */ +            unsafe { puts("wrong\0" as *const str as *const i8) } +        } +        [0, .., 0] => { +            /* should not take this path */ +            unsafe { puts("wrong\0" as *const str as *const i8) } +        }, +        [0, .., b] => { +            ret -= b; +            unsafe { puts("correct\0" as *const str as *const i8) } +        }, +        _ => {} +    } + +    ret +} diff --git a/gcc/testsuite/rust/execute/torture/match-slicepattern-slice-2.rs b/gcc/testsuite/rust/execute/torture/match-slicepattern-slice-2.rs new file mode 100644 index 0000000..2fdffbb --- /dev/null +++ b/gcc/testsuite/rust/execute/torture/match-slicepattern-slice-2.rs @@ -0,0 +1,28 @@ +// { dg-output "correct\r*" } +extern "C" { +    fn puts(s: *const i8); +} + +fn main() -> i32 { +    let arr = [0, 4, 5, 6, 1]; +    let a: &[i32] = &arr; +    let mut ret = 1; + +    match a { +        [1, .., b] => { +            /* should not take this path */ +            unsafe { puts("wrong\0" as *const str as *const i8) } +        } +        [0, .., 0] => { +            /* should not take this path */ +            unsafe { puts("wrong\0" as *const str as *const i8) } +        }, +        [0, .., b] => { +            ret -= b; +            unsafe { puts("correct\0" as *const str as *const i8) } +        }, +        _ => {} +    } + +    ret +} diff --git a/gcc/testsuite/rust/execute/torture/match-tuplestructpattern-rest-1.rs b/gcc/testsuite/rust/execute/torture/match-tuplestructpattern-rest-1.rs new file mode 100644 index 0000000..8d7446d --- /dev/null +++ b/gcc/testsuite/rust/execute/torture/match-tuplestructpattern-rest-1.rs @@ -0,0 +1,24 @@ +// { dg-output "correct\r*" } +extern "C" { +    fn puts(s: *const i8); +} + +fn main() -> i32 { +    struct A (i32, i32, i32); +    let a = A (0, 1, 2); +    let mut ret = 1; + +    match a { +        A (1, ..) => { +            /* should not take this path */ +            unsafe { puts("wrong\0" as *const str as *const i8) } +        } +        A (0, b, ..) => {  +            ret -= b; +            unsafe { puts("correct\0" as *const str as *const i8) } +        }, +        _ => {} +    } + +    ret +} diff --git a/gcc/testsuite/rust/execute/torture/match-tuplestructpattern-rest-2.rs b/gcc/testsuite/rust/execute/torture/match-tuplestructpattern-rest-2.rs new file mode 100644 index 0000000..f433be9 --- /dev/null +++ b/gcc/testsuite/rust/execute/torture/match-tuplestructpattern-rest-2.rs @@ -0,0 +1,28 @@ +// { dg-output "correct\r*" } +extern "C" { +    fn puts(s: *const i8); +} + +fn main() -> i32 { +    struct A (i32, i32, i32); +    let a = A (0, 3, 1); +    let mut ret = 1; + +    match a { +        A (1, ..) => { +            /* should not take this path */ +            unsafe { puts("wrong\0" as *const str as *const i8) } +        } +        A (.., 3) => { +            /* should not take this path */ +            unsafe { puts("wrong\0" as *const str as *const i8) } +        } +        A (.., b) => {  +            ret -= b; +            unsafe { puts("correct\0" as *const str as *const i8) } +        }, +        _ => {} +    } + +    ret +}  | 
