diff options
Diffstat (limited to 'tests/ui/extern')
83 files changed, 1541 insertions, 0 deletions
diff --git a/tests/ui/extern/auxiliary/extern-take-value.rs b/tests/ui/extern/auxiliary/extern-take-value.rs new file mode 100644 index 000000000..56256aa19 --- /dev/null +++ b/tests/ui/extern/auxiliary/extern-take-value.rs @@ -0,0 +1,5 @@ +pub extern "C" fn f() -> i32 { 1 } +pub extern "C" fn g() -> i32 { 2 } + +pub fn get_f() -> extern "C" fn() -> i32 { f } +pub fn get_g() -> extern "C" fn() -> i32 { g } diff --git a/tests/ui/extern/auxiliary/extern-types-inherent-impl.rs b/tests/ui/extern/auxiliary/extern-types-inherent-impl.rs new file mode 100644 index 000000000..a1efe1818 --- /dev/null +++ b/tests/ui/extern/auxiliary/extern-types-inherent-impl.rs @@ -0,0 +1,9 @@ +#![feature(extern_types)] + +extern "C" { + pub type CrossCrate; +} + +impl CrossCrate { + pub fn foo(&self) {} +} diff --git a/tests/ui/extern/auxiliary/extern_calling_convention.rs b/tests/ui/extern/auxiliary/extern_calling_convention.rs new file mode 100644 index 000000000..e24cf9fda --- /dev/null +++ b/tests/ui/extern/auxiliary/extern_calling_convention.rs @@ -0,0 +1,26 @@ +// Make sure Rust generates the correct calling convention for extern +// functions. + +#[inline(never)] +#[cfg(target_arch = "x86_64")] +pub extern "win64" fn foo(a: isize, b: isize, c: isize, d: isize) { + assert_eq!(a, 1); + assert_eq!(b, 2); + assert_eq!(c, 3); + assert_eq!(d, 4); + + println!("a: {}, b: {}, c: {}, d: {}", + a, b, c, d) +} + +#[inline(never)] +#[cfg(not(target_arch = "x86_64"))] +pub extern "C" fn foo(a: isize, b: isize, c: isize, d: isize) { + assert_eq!(a, 1); + assert_eq!(b, 2); + assert_eq!(c, 3); + assert_eq!(d, 4); + + println!("a: {}, b: {}, c: {}, d: {}", + a, b, c, d) +} diff --git a/tests/ui/extern/auxiliary/extern_mod_ordering_lib.rs b/tests/ui/extern/auxiliary/extern_mod_ordering_lib.rs new file mode 100644 index 000000000..7357f5970 --- /dev/null +++ b/tests/ui/extern/auxiliary/extern_mod_ordering_lib.rs @@ -0,0 +1,5 @@ +#![crate_type="lib"] + +pub mod extern_mod_ordering_lib { + pub fn f() {} +} diff --git a/tests/ui/extern/auxiliary/fat_drop.rs b/tests/ui/extern/auxiliary/fat_drop.rs new file mode 100644 index 000000000..768d29876 --- /dev/null +++ b/tests/ui/extern/auxiliary/fat_drop.rs @@ -0,0 +1,13 @@ +pub static mut DROPPED: bool = false; + +pub struct S { + _unsized: [u8] +} + +impl Drop for S { + fn drop(&mut self) { + unsafe { + DROPPED = true; + } + } +} diff --git a/tests/ui/extern/auxiliary/invalid-utf8.txt b/tests/ui/extern/auxiliary/invalid-utf8.txt new file mode 100644 index 000000000..dc1115b82 --- /dev/null +++ b/tests/ui/extern/auxiliary/invalid-utf8.txt @@ -0,0 +1 @@ +Ã(
\ No newline at end of file diff --git a/tests/ui/extern/auxiliary/issue-80074-macro.rs b/tests/ui/extern/auxiliary/issue-80074-macro.rs new file mode 100644 index 000000000..30e0f19ab --- /dev/null +++ b/tests/ui/extern/auxiliary/issue-80074-macro.rs @@ -0,0 +1,4 @@ +// edition:2018 + +macro_rules! foo_ { () => {}; } +use foo_ as foo; diff --git a/tests/ui/extern/auxiliary/m1.rs b/tests/ui/extern/auxiliary/m1.rs new file mode 100644 index 000000000..b76b4321d --- /dev/null +++ b/tests/ui/extern/auxiliary/m1.rs @@ -0,0 +1 @@ +pub fn foo() {} diff --git a/tests/ui/extern/auxiliary/m2.rs b/tests/ui/extern/auxiliary/m2.rs new file mode 100644 index 000000000..c5c0bc606 --- /dev/null +++ b/tests/ui/extern/auxiliary/m2.rs @@ -0,0 +1 @@ +pub fn bar() {} diff --git a/tests/ui/extern/auxiliary/no-mangle-associated-fn.rs b/tests/ui/extern/auxiliary/no-mangle-associated-fn.rs new file mode 100644 index 000000000..7fc73c76c --- /dev/null +++ b/tests/ui/extern/auxiliary/no-mangle-associated-fn.rs @@ -0,0 +1,21 @@ +#![crate_type = "lib"] + +struct Bar; + +impl Bar { + #[no_mangle] + fn bar() -> u8 { + 2 + } +} + +trait Foo { + fn baz() -> u8; +} + +impl Foo for Bar { + #[no_mangle] + fn baz() -> u8 { + 3 + } +} diff --git a/tests/ui/extern/auxiliary/reexport-should-still-link.rs b/tests/ui/extern/auxiliary/reexport-should-still-link.rs new file mode 100644 index 000000000..237ea8dfc --- /dev/null +++ b/tests/ui/extern/auxiliary/reexport-should-still-link.rs @@ -0,0 +1,5 @@ +pub use foo::bar; + +mod foo { + pub fn bar() {} +} diff --git a/tests/ui/extern/extern-1.rs b/tests/ui/extern/extern-1.rs new file mode 100644 index 000000000..66e560501 --- /dev/null +++ b/tests/ui/extern/extern-1.rs @@ -0,0 +1,9 @@ +// run-pass +#![allow(dead_code)] +// pretty-expanded FIXME #23616 + +extern "C" fn f() { +} + +pub fn main() { +} diff --git a/tests/ui/extern/extern-calling-convention-test.rs b/tests/ui/extern/extern-calling-convention-test.rs new file mode 100644 index 000000000..7231a7cde --- /dev/null +++ b/tests/ui/extern/extern-calling-convention-test.rs @@ -0,0 +1,12 @@ +// run-pass +// aux-build:extern_calling_convention.rs + +// pretty-expanded FIXME #23616 + +extern crate extern_calling_convention; + +use extern_calling_convention::foo; + +pub fn main() { + foo(1, 2, 3, 4); +} diff --git a/tests/ui/extern/extern-compare-with-return-type.rs b/tests/ui/extern/extern-compare-with-return-type.rs new file mode 100644 index 000000000..42693d3a0 --- /dev/null +++ b/tests/ui/extern/extern-compare-with-return-type.rs @@ -0,0 +1,27 @@ +// run-pass + +// Tests that we can compare various kinds of extern fn signatures. +#![allow(non_camel_case_types)] + +// `dbg!()` differentiates these functions to ensure they won't be merged. +extern "C" fn voidret1() { dbg!() } +extern "C" fn voidret2() { dbg!() } + +extern "C" fn uintret() -> usize { 22 } + +extern "C" fn uintvoidret(_x: usize) {} + +extern "C" fn uintuintuintuintret(x: usize, y: usize, z: usize) -> usize { x+y+z } +type uintuintuintuintret = extern "C" fn(usize,usize,usize) -> usize; + +pub fn main() { + assert!(voidret1 as extern "C" fn() == voidret1 as extern "C" fn()); + assert!(voidret1 as extern "C" fn() != voidret2 as extern "C" fn()); + + assert!(uintret as extern "C" fn() -> usize == uintret as extern "C" fn() -> usize); + + assert!(uintvoidret as extern "C" fn(usize) == uintvoidret as extern "C" fn(usize)); + + assert!(uintuintuintuintret as uintuintuintuintret == + uintuintuintuintret as uintuintuintuintret); +} diff --git a/tests/ui/extern/extern-const.fixed b/tests/ui/extern/extern-const.fixed new file mode 100644 index 000000000..9d96b4f63 --- /dev/null +++ b/tests/ui/extern/extern-const.fixed @@ -0,0 +1,26 @@ +// Check extern items cannot be const + `rustfix` suggests using +// extern static. +// +// #54388: an unused reference to an undefined static may or may not +// compile. To sidestep this by using one that *is* defined. + +// run-rustfix +// ignore-wasm32-bare no external library to link to. +// ignore-asmjs wasm2js does not support source maps yet +// compile-flags: -g +#![feature(rustc_private)] +extern crate libc; + +#[link(name = "rust_test_helpers", kind = "static")] +extern "C" { + static rust_dbg_static_mut: libc::c_int; //~ ERROR extern items cannot be `const` +} + +fn main() { + // We suggest turning the (illegal) extern `const` into an extern `static`, + // but this also requires `unsafe` (a deny-by-default lint at comment time, + // future error; Issue #36247) + unsafe { + let _x = rust_dbg_static_mut; + } +} diff --git a/tests/ui/extern/extern-const.rs b/tests/ui/extern/extern-const.rs new file mode 100644 index 000000000..7cef5b349 --- /dev/null +++ b/tests/ui/extern/extern-const.rs @@ -0,0 +1,26 @@ +// Check extern items cannot be const + `rustfix` suggests using +// extern static. +// +// #54388: an unused reference to an undefined static may or may not +// compile. To sidestep this by using one that *is* defined. + +// run-rustfix +// ignore-wasm32-bare no external library to link to. +// ignore-asmjs wasm2js does not support source maps yet +// compile-flags: -g +#![feature(rustc_private)] +extern crate libc; + +#[link(name = "rust_test_helpers", kind = "static")] +extern "C" { + const rust_dbg_static_mut: libc::c_int; //~ ERROR extern items cannot be `const` +} + +fn main() { + // We suggest turning the (illegal) extern `const` into an extern `static`, + // but this also requires `unsafe` (a deny-by-default lint at comment time, + // future error; Issue #36247) + unsafe { + let _x = rust_dbg_static_mut; + } +} diff --git a/tests/ui/extern/extern-const.stderr b/tests/ui/extern/extern-const.stderr new file mode 100644 index 000000000..7f67adbdb --- /dev/null +++ b/tests/ui/extern/extern-const.stderr @@ -0,0 +1,12 @@ +error: extern items cannot be `const` + --> $DIR/extern-const.rs:16:11 + | +LL | const rust_dbg_static_mut: libc::c_int; + | ------^^^^^^^^^^^^^^^^^^^ + | | + | help: try using a static value: `static` + | + = note: for more information, visit https://doc.rust-lang.org/std/keyword.extern.html + +error: aborting due to previous error + diff --git a/tests/ui/extern/extern-crate-multiple-missing.rs b/tests/ui/extern/extern-crate-multiple-missing.rs new file mode 100644 index 000000000..a6560ca78 --- /dev/null +++ b/tests/ui/extern/extern-crate-multiple-missing.rs @@ -0,0 +1,10 @@ +// If multiple `extern crate` resolutions fail each of them should produce an error +extern crate bar; //~ ERROR can't find crate for `bar` +extern crate foo; //~ ERROR can't find crate for `foo` + +fn main() { + // If the crate name introduced by `extern crate` failed to resolve then subsequent + // derived paths do not emit additional errors + foo::something(); + bar::something(); +} diff --git a/tests/ui/extern/extern-crate-multiple-missing.stderr b/tests/ui/extern/extern-crate-multiple-missing.stderr new file mode 100644 index 000000000..893bb4fb2 --- /dev/null +++ b/tests/ui/extern/extern-crate-multiple-missing.stderr @@ -0,0 +1,15 @@ +error[E0463]: can't find crate for `bar` + --> $DIR/extern-crate-multiple-missing.rs:2:1 + | +LL | extern crate bar; + | ^^^^^^^^^^^^^^^^^ can't find crate + +error[E0463]: can't find crate for `foo` + --> $DIR/extern-crate-multiple-missing.rs:3:1 + | +LL | extern crate foo; + | ^^^^^^^^^^^^^^^^^ can't find crate + +error: aborting due to 2 previous errors + +For more information about this error, try `rustc --explain E0463`. diff --git a/tests/ui/extern/extern-crate-rename.rs b/tests/ui/extern/extern-crate-rename.rs new file mode 100644 index 000000000..fc8afc3e1 --- /dev/null +++ b/tests/ui/extern/extern-crate-rename.rs @@ -0,0 +1,8 @@ +// aux-build:m1.rs +// aux-build:m2.rs + + +extern crate m1; +extern crate m2 as m1; //~ ERROR is defined multiple times + +fn main() {} diff --git a/tests/ui/extern/extern-crate-rename.stderr b/tests/ui/extern/extern-crate-rename.stderr new file mode 100644 index 000000000..5f1477955 --- /dev/null +++ b/tests/ui/extern/extern-crate-rename.stderr @@ -0,0 +1,17 @@ +error[E0259]: the name `m1` is defined multiple times + --> $DIR/extern-crate-rename.rs:6:1 + | +LL | extern crate m1; + | ---------------- previous import of the extern crate `m1` here +LL | extern crate m2 as m1; + | ^^^^^^^^^^^^^^^^^^^^^^ `m1` reimported here + | + = note: `m1` must be defined only once in the type namespace of this module +help: you can use `as` to change the binding name of the import + | +LL | extern crate m2 as other_m1; + | ~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + +error: aborting due to previous error + +For more information about this error, try `rustc --explain E0259`. diff --git a/tests/ui/extern/extern-crate-visibility.rs b/tests/ui/extern/extern-crate-visibility.rs new file mode 100644 index 000000000..cda1227cc --- /dev/null +++ b/tests/ui/extern/extern-crate-visibility.rs @@ -0,0 +1,24 @@ +mod foo { + extern crate core; +} + +// Check that private crates can be used from outside their modules, albeit with warnings +use foo::core::cell; //~ ERROR crate import `core` is private + +fn f() { + foo::core::cell::Cell::new(0); //~ ERROR crate import `core` is private + + use foo::*; + mod core {} // Check that private crates are not glob imported +} + +mod bar { + pub extern crate core; +} + +mod baz { + pub use bar::*; + use self::core::cell; // Check that public extern crates are glob imported +} + +fn main() {} diff --git a/tests/ui/extern/extern-crate-visibility.stderr b/tests/ui/extern/extern-crate-visibility.stderr new file mode 100644 index 000000000..9eeb83ae1 --- /dev/null +++ b/tests/ui/extern/extern-crate-visibility.stderr @@ -0,0 +1,27 @@ +error[E0603]: crate import `core` is private + --> $DIR/extern-crate-visibility.rs:6:10 + | +LL | use foo::core::cell; + | ^^^^ private crate import + | +note: the crate import `core` is defined here + --> $DIR/extern-crate-visibility.rs:2:5 + | +LL | extern crate core; + | ^^^^^^^^^^^^^^^^^^ + +error[E0603]: crate import `core` is private + --> $DIR/extern-crate-visibility.rs:9:10 + | +LL | foo::core::cell::Cell::new(0); + | ^^^^ private crate import + | +note: the crate import `core` is defined here + --> $DIR/extern-crate-visibility.rs:2:5 + | +LL | extern crate core; + | ^^^^^^^^^^^^^^^^^^ + +error: aborting due to 2 previous errors + +For more information about this error, try `rustc --explain E0603`. diff --git a/tests/ui/extern/extern-ffi-fn-with-body.rs b/tests/ui/extern/extern-ffi-fn-with-body.rs new file mode 100644 index 000000000..ef234e8af --- /dev/null +++ b/tests/ui/extern/extern-ffi-fn-with-body.rs @@ -0,0 +1,11 @@ +extern "C" { + fn foo() -> i32 { //~ ERROR incorrect function inside `extern` block + return 0; + } +} + +extern "C" fn bar() -> i32 { + return 0; +} + +fn main() {} diff --git a/tests/ui/extern/extern-ffi-fn-with-body.stderr b/tests/ui/extern/extern-ffi-fn-with-body.stderr new file mode 100644 index 000000000..079c9cecd --- /dev/null +++ b/tests/ui/extern/extern-ffi-fn-with-body.stderr @@ -0,0 +1,18 @@ +error: incorrect function inside `extern` block + --> $DIR/extern-ffi-fn-with-body.rs:2:8 + | +LL | extern "C" { + | ---------- `extern` blocks define existing foreign functions and functions inside of them cannot have a body +LL | fn foo() -> i32 { + | ________^^^__________- + | | | + | | cannot have a body +LL | | return 0; +LL | | } + | |_____- help: remove the invalid body: `;` + | + = help: you might have meant to write a function accessible through FFI, which can be done by writing `extern fn` outside of the `extern` block + = note: for more information, visit https://doc.rust-lang.org/std/keyword.extern.html + +error: aborting due to previous error + diff --git a/tests/ui/extern/extern-foreign-crate.rs b/tests/ui/extern/extern-foreign-crate.rs new file mode 100644 index 000000000..7f774c442 --- /dev/null +++ b/tests/ui/extern/extern-foreign-crate.rs @@ -0,0 +1,6 @@ +// run-pass +// pretty-expanded FIXME #23616 + +extern crate std as mystd; + +pub fn main() {} diff --git a/tests/ui/extern/extern-macro.rs b/tests/ui/extern/extern-macro.rs new file mode 100644 index 000000000..ab974e628 --- /dev/null +++ b/tests/ui/extern/extern-macro.rs @@ -0,0 +1,6 @@ +// #41719 + +fn main() { + enum Foo {} + let _ = Foo::bar!(); //~ ERROR failed to resolve: partially resolved path in a macro +} diff --git a/tests/ui/extern/extern-macro.stderr b/tests/ui/extern/extern-macro.stderr new file mode 100644 index 000000000..5b7a72073 --- /dev/null +++ b/tests/ui/extern/extern-macro.stderr @@ -0,0 +1,9 @@ +error[E0433]: failed to resolve: partially resolved path in a macro + --> $DIR/extern-macro.rs:5:13 + | +LL | let _ = Foo::bar!(); + | ^^^^^^^^ partially resolved path in a macro + +error: aborting due to previous error + +For more information about this error, try `rustc --explain E0433`. diff --git a/tests/ui/extern/extern-main-fn.rs b/tests/ui/extern/extern-main-fn.rs new file mode 100644 index 000000000..bb1468a70 --- /dev/null +++ b/tests/ui/extern/extern-main-fn.rs @@ -0,0 +1 @@ +extern "C" fn main() {} //~ ERROR: `main` function has wrong type [E0580] diff --git a/tests/ui/extern/extern-main-fn.stderr b/tests/ui/extern/extern-main-fn.stderr new file mode 100644 index 000000000..136c95753 --- /dev/null +++ b/tests/ui/extern/extern-main-fn.stderr @@ -0,0 +1,12 @@ +error[E0580]: `main` function has wrong type + --> $DIR/extern-main-fn.rs:1:1 + | +LL | extern "C" fn main() {} + | ^^^^^^^^^^^^^^^^^^^^ expected "Rust" fn, found "C" fn + | + = note: expected fn pointer `fn()` + found fn pointer `extern "C" fn()` + +error: aborting due to previous error + +For more information about this error, try `rustc --explain E0580`. diff --git a/tests/ui/extern/extern-main-issue-86110.rs b/tests/ui/extern/extern-main-issue-86110.rs new file mode 100644 index 000000000..83af7a14c --- /dev/null +++ b/tests/ui/extern/extern-main-issue-86110.rs @@ -0,0 +1,7 @@ +// missing and missing2 exist to make sure that the error only happens on a `main` declaration +extern "C" { + fn missing(); + fn main(); + //~^ the `main` function cannot be declared in an `extern` block + fn missing2(); +} diff --git a/tests/ui/extern/extern-main-issue-86110.stderr b/tests/ui/extern/extern-main-issue-86110.stderr new file mode 100644 index 000000000..18dfddc46 --- /dev/null +++ b/tests/ui/extern/extern-main-issue-86110.stderr @@ -0,0 +1,8 @@ +error: the `main` function cannot be declared in an `extern` block + --> $DIR/extern-main-issue-86110.rs:4:5 + | +LL | fn main(); + | ^^^^^^^^^ + +error: aborting due to previous error + diff --git a/tests/ui/extern/extern-methods.rs b/tests/ui/extern/extern-methods.rs new file mode 100644 index 000000000..22792c113 --- /dev/null +++ b/tests/ui/extern/extern-methods.rs @@ -0,0 +1,29 @@ +// run-pass +// only-x86 + +trait A { + extern "fastcall" fn test1(i: i32); + extern "C" fn test2(i: i32); +} + +struct S; +impl S { + extern "stdcall" fn test3(i: i32) { + assert_eq!(i, 3); + } +} + +impl A for S { + extern "fastcall" fn test1(i: i32) { + assert_eq!(i, 1); + } + extern "C" fn test2(i: i32) { + assert_eq!(i, 2); + } +} + +fn main() { + <S as A>::test1(1); + <S as A>::test2(2); + S::test3(3); +} diff --git a/tests/ui/extern/extern-mod-abi.rs b/tests/ui/extern/extern-mod-abi.rs new file mode 100644 index 000000000..c543394cc --- /dev/null +++ b/tests/ui/extern/extern-mod-abi.rs @@ -0,0 +1,9 @@ +// run-pass +#![allow(dead_code)] +// pretty-expanded FIXME #23616 + +extern "C" { + fn pow(x: f64, y: f64) -> f64; +} + +pub fn main() {} diff --git a/tests/ui/extern/extern-mod-ordering-exe.rs b/tests/ui/extern/extern-mod-ordering-exe.rs new file mode 100644 index 000000000..d7cc4dffb --- /dev/null +++ b/tests/ui/extern/extern-mod-ordering-exe.rs @@ -0,0 +1,12 @@ +// run-pass +// aux-build:extern_mod_ordering_lib.rs + +// pretty-expanded FIXME #23616 + +extern crate extern_mod_ordering_lib; + +use extern_mod_ordering_lib::extern_mod_ordering_lib as the_lib; + +pub fn main() { + the_lib::f(); +} diff --git a/tests/ui/extern/extern-no-mangle.rs b/tests/ui/extern/extern-no-mangle.rs new file mode 100644 index 000000000..ab7c9824a --- /dev/null +++ b/tests/ui/extern/extern-no-mangle.rs @@ -0,0 +1,30 @@ +#![warn(unused_attributes)] + +// Tests that placing the #[no_mangle] attribute on a foreign fn or static emits +// a specialized warning. +// The previous warning only talks about a "function or static" but foreign fns/statics +// are also not allowed to have #[no_mangle] + +// build-pass + +extern "C" { + #[no_mangle] + //~^ WARNING `#[no_mangle]` has no effect on a foreign static + //~^^ WARNING this was previously accepted by the compiler + pub static FOO: u8; + + #[no_mangle] + //~^ WARNING `#[no_mangle]` has no effect on a foreign function + //~^^ WARNING this was previously accepted by the compiler + pub fn bar(); +} + +fn no_new_warn() { + // Should emit the generic "not a function or static" warning + #[no_mangle] + //~^ WARNING attribute should be applied to a free function, impl method or static + //~^^ WARNING this was previously accepted by the compiler + let x = 0_u8; +} + +fn main() {} diff --git a/tests/ui/extern/extern-no-mangle.stderr b/tests/ui/extern/extern-no-mangle.stderr new file mode 100644 index 000000000..f20ee158a --- /dev/null +++ b/tests/ui/extern/extern-no-mangle.stderr @@ -0,0 +1,42 @@ +warning: attribute should be applied to a free function, impl method or static + --> $DIR/extern-no-mangle.rs:24:5 + | +LL | #[no_mangle] + | ^^^^^^^^^^^^ +... +LL | let x = 0_u8; + | ------------- not a free function, impl method or static + | + = warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release! +note: the lint level is defined here + --> $DIR/extern-no-mangle.rs:1:9 + | +LL | #![warn(unused_attributes)] + | ^^^^^^^^^^^^^^^^^ + +warning: `#[no_mangle]` has no effect on a foreign static + --> $DIR/extern-no-mangle.rs:11:5 + | +LL | #[no_mangle] + | ^^^^^^^^^^^^ help: remove this attribute +... +LL | pub static FOO: u8; + | ------------------- foreign static + | + = warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release! + = note: symbol names in extern blocks are not mangled + +warning: `#[no_mangle]` has no effect on a foreign function + --> $DIR/extern-no-mangle.rs:16:5 + | +LL | #[no_mangle] + | ^^^^^^^^^^^^ help: remove this attribute +... +LL | pub fn bar(); + | ------------- foreign function + | + = warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release! + = note: symbol names in extern blocks are not mangled + +warning: 3 warnings emitted + diff --git a/tests/ui/extern/extern-prelude-core.rs b/tests/ui/extern/extern-prelude-core.rs new file mode 100644 index 000000000..56206425f --- /dev/null +++ b/tests/ui/extern/extern-prelude-core.rs @@ -0,0 +1,18 @@ +// run-pass +#![feature(lang_items, start)] +#![no_std] + +extern crate std as other; + +mod foo { + pub fn test() { + let x = core::cmp::min(2, 3); + assert_eq!(x, 2); + } +} + +#[start] +fn start(_argc: isize, _argv: *const *const u8) -> isize { + foo::test(); + 0 +} diff --git a/tests/ui/extern/extern-prelude-no-speculative.rs b/tests/ui/extern/extern-prelude-no-speculative.rs new file mode 100644 index 000000000..3ba124159 --- /dev/null +++ b/tests/ui/extern/extern-prelude-no-speculative.rs @@ -0,0 +1,13 @@ +// run-pass +#![allow(unused_variables)] +// compile-flags: --extern LooksLikeExternCrate=/path/to/nowhere + +mod m { + pub struct LooksLikeExternCrate; +} + +fn main() { + // OK, speculative resolution for `unused_qualifications` doesn't try + // to resolve this as an extern crate and load that crate + let s = m::LooksLikeExternCrate {}; +} diff --git a/tests/ui/extern/extern-prelude-std.rs b/tests/ui/extern/extern-prelude-std.rs new file mode 100644 index 000000000..b5627fad9 --- /dev/null +++ b/tests/ui/extern/extern-prelude-std.rs @@ -0,0 +1,12 @@ +// run-pass + +mod foo { + pub fn test() { + let x = std::cmp::min(2, 3); + assert_eq!(x, 2); + } +} + +fn main() { + foo::test(); +} diff --git a/tests/ui/extern/extern-pub.rs b/tests/ui/extern/extern-pub.rs new file mode 100644 index 000000000..0b95045a0 --- /dev/null +++ b/tests/ui/extern/extern-pub.rs @@ -0,0 +1,8 @@ +// run-pass +// pretty-expanded FIXME #23616 + +extern "C" { + pub fn free(p: *const u8); +} + +pub fn main() {} diff --git a/tests/ui/extern/extern-rust.rs b/tests/ui/extern/extern-rust.rs new file mode 100644 index 000000000..7cea8be59 --- /dev/null +++ b/tests/ui/extern/extern-rust.rs @@ -0,0 +1,12 @@ +// run-pass +// pretty-expanded FIXME #23616 + +#[repr(C)] +pub struct Foo(u32); + +// ICE trigger, bad handling of differing types between rust and external ABIs +pub extern "C" fn bar() -> Foo { + Foo(0) +} + +fn main() {} diff --git a/tests/ui/extern/extern-static-size-overflow.rs b/tests/ui/extern/extern-static-size-overflow.rs new file mode 100644 index 000000000..a96ce0cf4 --- /dev/null +++ b/tests/ui/extern/extern-static-size-overflow.rs @@ -0,0 +1,43 @@ +#[repr(C)] +struct ReallyBig { + _a: [u8; usize::MAX], +} + +// The limit for "too big for the current architecture" is dependent on the target pointer size +// however it's artificially limited on 64 bits +// logic copied from rustc_target::abi::TargetDataLayout::obj_size_bound() +const fn max_size() -> usize { + #[cfg(target_pointer_width = "16")] + { + 1 << 15 + } + + #[cfg(target_pointer_width = "32")] + { + 1 << 31 + } + + #[cfg(target_pointer_width = "64")] + { + 1 << 47 + } + + #[cfg(not(any( + target_pointer_width = "16", + target_pointer_width = "32", + target_pointer_width = "64" + )))] + { + isize::MAX as usize + } +} + +extern "C" { + static FOO: [u8; 1]; + static BAR: [u8; max_size() - 1]; + static BAZ: [u8; max_size()]; //~ ERROR extern static is too large + static UWU: [usize; usize::MAX]; //~ ERROR extern static is too large + static A: ReallyBig; //~ ERROR extern static is too large +} + +fn main() {} diff --git a/tests/ui/extern/extern-static-size-overflow.stderr b/tests/ui/extern/extern-static-size-overflow.stderr new file mode 100644 index 000000000..1c9263995 --- /dev/null +++ b/tests/ui/extern/extern-static-size-overflow.stderr @@ -0,0 +1,20 @@ +error: extern static is too large for the current architecture + --> $DIR/extern-static-size-overflow.rs:38:5 + | +LL | static BAZ: [u8; max_size()]; + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + +error: extern static is too large for the current architecture + --> $DIR/extern-static-size-overflow.rs:39:5 + | +LL | static UWU: [usize; usize::MAX]; + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + +error: extern static is too large for the current architecture + --> $DIR/extern-static-size-overflow.rs:40:5 + | +LL | static A: ReallyBig; + | ^^^^^^^^^^^^^^^^^^^ + +error: aborting due to 3 previous errors + diff --git a/tests/ui/extern/extern-take-value.rs b/tests/ui/extern/extern-take-value.rs new file mode 100644 index 000000000..c09a77436 --- /dev/null +++ b/tests/ui/extern/extern-take-value.rs @@ -0,0 +1,13 @@ +// run-pass +// aux-build:extern-take-value.rs + +extern crate extern_take_value; + +pub fn main() { + let a: extern "C" fn() -> i32 = extern_take_value::get_f(); + let b: extern "C" fn() -> i32 = extern_take_value::get_f(); + let c: extern "C" fn() -> i32 = extern_take_value::get_g(); + + assert!(a == b); + assert!(a != c); +} diff --git a/tests/ui/extern/extern-thiscall.rs b/tests/ui/extern/extern-thiscall.rs new file mode 100644 index 000000000..717df57ec --- /dev/null +++ b/tests/ui/extern/extern-thiscall.rs @@ -0,0 +1,25 @@ +// run-pass +// only-x86 + +#![feature(abi_thiscall)] + +trait A { + extern "thiscall" fn test1(i: i32); +} + +struct S; + +impl A for S { + extern "thiscall" fn test1(i: i32) { + assert_eq!(i, 1); + } +} + +extern "thiscall" fn test2(i: i32) { + assert_eq!(i, 2); +} + +fn main() { + <S as A>::test1(1); + test2(2); +} diff --git a/tests/ui/extern/extern-type-diag-not-similar.rs b/tests/ui/extern/extern-type-diag-not-similar.rs new file mode 100644 index 000000000..39d00a6c1 --- /dev/null +++ b/tests/ui/extern/extern-type-diag-not-similar.rs @@ -0,0 +1,22 @@ +// We previously mentioned other extern types in the error message here. +// +// Two extern types shouldn't really be considered similar just +// because they are both extern types. + +#![feature(extern_types)] +extern { + type ShouldNotBeMentioned; +} + +extern { + type Foo; +} + +unsafe impl Send for ShouldNotBeMentioned {} + +fn assert_send<T: Send + ?Sized>() {} + +fn main() { + assert_send::<Foo>() + //~^ ERROR `Foo` cannot be sent between threads safely +} diff --git a/tests/ui/extern/extern-type-diag-not-similar.stderr b/tests/ui/extern/extern-type-diag-not-similar.stderr new file mode 100644 index 000000000..75836f7ec --- /dev/null +++ b/tests/ui/extern/extern-type-diag-not-similar.stderr @@ -0,0 +1,16 @@ +error[E0277]: `Foo` cannot be sent between threads safely + --> $DIR/extern-type-diag-not-similar.rs:20:19 + | +LL | assert_send::<Foo>() + | ^^^ `Foo` cannot be sent between threads safely + | + = help: the trait `Send` is not implemented for `Foo` +note: required by a bound in `assert_send` + --> $DIR/extern-type-diag-not-similar.rs:17:19 + | +LL | fn assert_send<T: Send + ?Sized>() {} + | ^^^^ required by this bound in `assert_send` + +error: aborting due to previous error + +For more information about this error, try `rustc --explain E0277`. diff --git a/tests/ui/extern/extern-types-distinct-types.rs b/tests/ui/extern/extern-types-distinct-types.rs new file mode 100644 index 000000000..4da049b78 --- /dev/null +++ b/tests/ui/extern/extern-types-distinct-types.rs @@ -0,0 +1,12 @@ +#![feature(extern_types)] + +extern "C" { + type A; + type B; +} + +fn foo(r: &A) -> &B { + r //~ ERROR mismatched types +} + +fn main() {} diff --git a/tests/ui/extern/extern-types-distinct-types.stderr b/tests/ui/extern/extern-types-distinct-types.stderr new file mode 100644 index 000000000..ca25aa64e --- /dev/null +++ b/tests/ui/extern/extern-types-distinct-types.stderr @@ -0,0 +1,19 @@ +error[E0308]: mismatched types + --> $DIR/extern-types-distinct-types.rs:9:5 + | +LL | type A; + | ------ the found foreign type +LL | type B; + | ------ the expected foreign type +... +LL | fn foo(r: &A) -> &B { + | -- expected `&B` because of return type +LL | r + | ^ expected extern type `B`, found extern type `A` + | + = note: expected reference `&B` + found reference `&A` + +error: aborting due to previous error + +For more information about this error, try `rustc --explain E0308`. diff --git a/tests/ui/extern/extern-types-inherent-impl.rs b/tests/ui/extern/extern-types-inherent-impl.rs new file mode 100644 index 000000000..3f09ac7b8 --- /dev/null +++ b/tests/ui/extern/extern-types-inherent-impl.rs @@ -0,0 +1,26 @@ +// Test that inherent impls can be defined for extern types. + +// check-pass +// aux-build:extern-types-inherent-impl.rs + +#![feature(extern_types)] + +extern crate extern_types_inherent_impl; +use extern_types_inherent_impl::CrossCrate; + +extern "C" { + type Local; +} + +impl Local { + fn foo(&self) {} +} + +fn use_foo(x: &Local, y: &CrossCrate) { + Local::foo(x); + x.foo(); + CrossCrate::foo(y); + y.foo(); +} + +fn main() {} diff --git a/tests/ui/extern/extern-types-manual-sync-send.rs b/tests/ui/extern/extern-types-manual-sync-send.rs new file mode 100644 index 000000000..87eb3f622 --- /dev/null +++ b/tests/ui/extern/extern-types-manual-sync-send.rs @@ -0,0 +1,19 @@ +// run-pass +// Test that unsafe impl for Sync/Send can be provided for extern types. + +#![feature(extern_types)] + +extern "C" { + type A; +} + +unsafe impl Sync for A {} +unsafe impl Send for A {} + +fn assert_sync<T: ?Sized + Sync>() {} +fn assert_send<T: ?Sized + Send>() {} + +fn main() { + assert_sync::<A>(); + assert_send::<A>(); +} diff --git a/tests/ui/extern/extern-types-not-sync-send.rs b/tests/ui/extern/extern-types-not-sync-send.rs new file mode 100644 index 000000000..ba82caced --- /dev/null +++ b/tests/ui/extern/extern-types-not-sync-send.rs @@ -0,0 +1,18 @@ +// Make sure extern types are !Sync and !Send. + +#![feature(extern_types)] + +extern "C" { + type A; +} + +fn assert_sync<T: ?Sized + Sync>() {} +fn assert_send<T: ?Sized + Send>() {} + +fn main() { + assert_sync::<A>(); + //~^ ERROR `A` cannot be shared between threads safely [E0277] + + assert_send::<A>(); + //~^ ERROR `A` cannot be sent between threads safely [E0277] +} diff --git a/tests/ui/extern/extern-types-not-sync-send.stderr b/tests/ui/extern/extern-types-not-sync-send.stderr new file mode 100644 index 000000000..7865ddeda --- /dev/null +++ b/tests/ui/extern/extern-types-not-sync-send.stderr @@ -0,0 +1,29 @@ +error[E0277]: `A` cannot be shared between threads safely + --> $DIR/extern-types-not-sync-send.rs:13:19 + | +LL | assert_sync::<A>(); + | ^ `A` cannot be shared between threads safely + | + = help: the trait `Sync` is not implemented for `A` +note: required by a bound in `assert_sync` + --> $DIR/extern-types-not-sync-send.rs:9:28 + | +LL | fn assert_sync<T: ?Sized + Sync>() {} + | ^^^^ required by this bound in `assert_sync` + +error[E0277]: `A` cannot be sent between threads safely + --> $DIR/extern-types-not-sync-send.rs:16:19 + | +LL | assert_send::<A>(); + | ^ `A` cannot be sent between threads safely + | + = help: the trait `Send` is not implemented for `A` +note: required by a bound in `assert_send` + --> $DIR/extern-types-not-sync-send.rs:10:28 + | +LL | fn assert_send<T: ?Sized + Send>() {} + | ^^^^ required by this bound in `assert_send` + +error: aborting due to 2 previous errors + +For more information about this error, try `rustc --explain E0277`. diff --git a/tests/ui/extern/extern-types-pointer-cast.rs b/tests/ui/extern/extern-types-pointer-cast.rs new file mode 100644 index 000000000..de6955bfa --- /dev/null +++ b/tests/ui/extern/extern-types-pointer-cast.rs @@ -0,0 +1,31 @@ +// run-pass +#![allow(dead_code)] +// Test that pointers to extern types can be cast from/to usize, +// despite being !Sized. +#![feature(extern_types)] + +extern "C" { + type A; +} + +struct Foo { + x: u8, + tail: A, +} + +struct Bar<T: ?Sized> { + x: u8, + tail: T, +} + +#[cfg(target_pointer_width = "32")] +const MAGIC: usize = 0xdeadbeef; +#[cfg(target_pointer_width = "64")] +const MAGIC: usize = 0x12345678deadbeef; + +fn main() { + assert_eq!((MAGIC as *const A) as usize, MAGIC); + assert_eq!((MAGIC as *const Foo) as usize, MAGIC); + assert_eq!((MAGIC as *const Bar<A>) as usize, MAGIC); + assert_eq!((MAGIC as *const Bar<Bar<A>>) as usize, MAGIC); +} diff --git a/tests/ui/extern/extern-types-size_of_val.rs b/tests/ui/extern/extern-types-size_of_val.rs new file mode 100644 index 000000000..3b02ea28e --- /dev/null +++ b/tests/ui/extern/extern-types-size_of_val.rs @@ -0,0 +1,15 @@ +// run-pass +#![feature(extern_types)] + +use std::mem::{align_of_val, size_of_val}; + +extern "C" { + type A; +} + +fn main() { + let x: &A = unsafe { &*(1usize as *const A) }; + + assert_eq!(size_of_val(x), 0); + assert_eq!(align_of_val(x), 1); +} diff --git a/tests/ui/extern/extern-types-thin-pointer.rs b/tests/ui/extern/extern-types-thin-pointer.rs new file mode 100644 index 000000000..b85fc4886 --- /dev/null +++ b/tests/ui/extern/extern-types-thin-pointer.rs @@ -0,0 +1,42 @@ +// run-pass +#![allow(dead_code)] +// Test that pointers and references to extern types are thin, ie they have the same size and +// alignment as a pointer to (). +#![feature(extern_types)] + +use std::mem::{align_of, size_of}; + +extern "C" { + type A; +} + +struct Foo { + x: u8, + tail: A, +} + +struct Bar<T: ?Sized> { + x: u8, + tail: T, +} + +fn assert_thin<T: ?Sized>() { + assert_eq!(size_of::<*const T>(), size_of::<*const ()>()); + assert_eq!(align_of::<*const T>(), align_of::<*const ()>()); + + assert_eq!(size_of::<*mut T>(), size_of::<*mut ()>()); + assert_eq!(align_of::<*mut T>(), align_of::<*mut ()>()); + + assert_eq!(size_of::<&T>(), size_of::<&()>()); + assert_eq!(align_of::<&T>(), align_of::<&()>()); + + assert_eq!(size_of::<&mut T>(), size_of::<&mut ()>()); + assert_eq!(align_of::<&mut T>(), align_of::<&mut ()>()); +} + +fn main() { + assert_thin::<A>(); + assert_thin::<Foo>(); + assert_thin::<Bar<A>>(); + assert_thin::<Bar<Bar<A>>>(); +} diff --git a/tests/ui/extern/extern-types-trait-impl.rs b/tests/ui/extern/extern-types-trait-impl.rs new file mode 100644 index 000000000..656101ed5 --- /dev/null +++ b/tests/ui/extern/extern-types-trait-impl.rs @@ -0,0 +1,26 @@ +// run-pass +#![allow(dead_code)] +// Test that traits can be implemented for extern types. +#![feature(extern_types)] + +extern "C" { + type A; +} + +trait Foo { + fn foo(&self) {} +} + +impl Foo for A { + fn foo(&self) {} +} + +fn assert_foo<T: ?Sized + Foo>() {} + +fn use_foo<T: ?Sized + Foo>(x: &dyn Foo) { + x.foo(); +} + +fn main() { + assert_foo::<A>(); +} diff --git a/tests/ui/extern/extern-types-unsized.rs b/tests/ui/extern/extern-types-unsized.rs new file mode 100644 index 000000000..94a222a7e --- /dev/null +++ b/tests/ui/extern/extern-types-unsized.rs @@ -0,0 +1,33 @@ +// Make sure extern types are !Sized. + +#![feature(extern_types)] + +extern "C" { + type A; +} + +struct Foo { + x: u8, + tail: A, +} + +struct Bar<T: ?Sized> { + x: u8, + tail: T, +} + +fn assert_sized<T>() {} + +fn main() { + assert_sized::<A>(); + //~^ ERROR the size for values of type + + assert_sized::<Foo>(); + //~^ ERROR the size for values of type + + assert_sized::<Bar<A>>(); + //~^ ERROR the size for values of type + + assert_sized::<Bar<Bar<A>>>(); + //~^ ERROR the size for values of type +} diff --git a/tests/ui/extern/extern-types-unsized.stderr b/tests/ui/extern/extern-types-unsized.stderr new file mode 100644 index 000000000..a79caced1 --- /dev/null +++ b/tests/ui/extern/extern-types-unsized.stderr @@ -0,0 +1,86 @@ +error[E0277]: the size for values of type `A` cannot be known at compilation time + --> $DIR/extern-types-unsized.rs:22:20 + | +LL | assert_sized::<A>(); + | ^ doesn't have a size known at compile-time + | + = help: the trait `Sized` is not implemented for `A` +note: required by a bound in `assert_sized` + --> $DIR/extern-types-unsized.rs:19:17 + | +LL | fn assert_sized<T>() {} + | ^ required by this bound in `assert_sized` +help: consider relaxing the implicit `Sized` restriction + | +LL | fn assert_sized<T: ?Sized>() {} + | ++++++++ + +error[E0277]: the size for values of type `A` cannot be known at compilation time + --> $DIR/extern-types-unsized.rs:25:20 + | +LL | assert_sized::<Foo>(); + | ^^^ doesn't have a size known at compile-time + | + = help: within `Foo`, the trait `Sized` is not implemented for `A` +note: required because it appears within the type `Foo` + --> $DIR/extern-types-unsized.rs:9:8 + | +LL | struct Foo { + | ^^^ +note: required by a bound in `assert_sized` + --> $DIR/extern-types-unsized.rs:19:17 + | +LL | fn assert_sized<T>() {} + | ^ required by this bound in `assert_sized` +help: consider relaxing the implicit `Sized` restriction + | +LL | fn assert_sized<T: ?Sized>() {} + | ++++++++ + +error[E0277]: the size for values of type `A` cannot be known at compilation time + --> $DIR/extern-types-unsized.rs:28:20 + | +LL | assert_sized::<Bar<A>>(); + | ^^^^^^ doesn't have a size known at compile-time + | + = help: within `Bar<A>`, the trait `Sized` is not implemented for `A` +note: required because it appears within the type `Bar<A>` + --> $DIR/extern-types-unsized.rs:14:8 + | +LL | struct Bar<T: ?Sized> { + | ^^^ +note: required by a bound in `assert_sized` + --> $DIR/extern-types-unsized.rs:19:17 + | +LL | fn assert_sized<T>() {} + | ^ required by this bound in `assert_sized` +help: consider relaxing the implicit `Sized` restriction + | +LL | fn assert_sized<T: ?Sized>() {} + | ++++++++ + +error[E0277]: the size for values of type `A` cannot be known at compilation time + --> $DIR/extern-types-unsized.rs:31:20 + | +LL | assert_sized::<Bar<Bar<A>>>(); + | ^^^^^^^^^^^ doesn't have a size known at compile-time + | + = help: within `Bar<Bar<A>>`, the trait `Sized` is not implemented for `A` +note: required because it appears within the type `Bar<A>` + --> $DIR/extern-types-unsized.rs:14:8 + | +LL | struct Bar<T: ?Sized> { + | ^^^ +note: required by a bound in `assert_sized` + --> $DIR/extern-types-unsized.rs:19:17 + | +LL | fn assert_sized<T>() {} + | ^ required by this bound in `assert_sized` +help: consider relaxing the implicit `Sized` restriction + | +LL | fn assert_sized<T: ?Sized>() {} + | ++++++++ + +error: aborting due to 4 previous errors + +For more information about this error, try `rustc --explain E0277`. diff --git a/tests/ui/extern/extern-vectorcall.rs b/tests/ui/extern/extern-vectorcall.rs new file mode 100644 index 000000000..a283573c9 --- /dev/null +++ b/tests/ui/extern/extern-vectorcall.rs @@ -0,0 +1,27 @@ +// run-pass +// revisions: x64 x32 +// [x64]only-x86_64 +// [x32]only-x86 + +#![feature(abi_vectorcall)] + +trait A { + extern "vectorcall" fn test1(i: i32); +} + +struct S; + +impl A for S { + extern "vectorcall" fn test1(i: i32) { + assert_eq!(i, 1); + } +} + +extern "vectorcall" fn test2(i: i32) { + assert_eq!(i, 2); +} + +fn main() { + <S as A>::test1(1); + test2(2); +} diff --git a/tests/ui/extern/extern-with-type-bounds.rs b/tests/ui/extern/extern-with-type-bounds.rs new file mode 100644 index 000000000..a72aa4171 --- /dev/null +++ b/tests/ui/extern/extern-with-type-bounds.rs @@ -0,0 +1,22 @@ +#![feature(intrinsics)] + +extern "rust-intrinsic" { + // Real example from libcore + #[rustc_safe_intrinsic] + fn type_id<T: ?Sized + 'static>() -> u64; + + // Silent bounds made explicit to make sure they are actually + // resolved. + fn transmute<T: Sized, U: Sized>(val: T) -> U; + + // Bounds aren't checked right now, so this should work + // even though it's incorrect. + #[rustc_safe_intrinsic] + fn size_of<T: Clone>() -> usize; + + // Unresolved bounds should still error. + fn align_of<T: NoSuchTrait>() -> usize; + //~^ ERROR cannot find trait `NoSuchTrait` in this scope +} + +fn main() {} diff --git a/tests/ui/extern/extern-with-type-bounds.stderr b/tests/ui/extern/extern-with-type-bounds.stderr new file mode 100644 index 000000000..88be1e5dd --- /dev/null +++ b/tests/ui/extern/extern-with-type-bounds.stderr @@ -0,0 +1,9 @@ +error[E0405]: cannot find trait `NoSuchTrait` in this scope + --> $DIR/extern-with-type-bounds.rs:18:20 + | +LL | fn align_of<T: NoSuchTrait>() -> usize; + | ^^^^^^^^^^^ not found in this scope + +error: aborting due to previous error + +For more information about this error, try `rustc --explain E0405`. diff --git a/tests/ui/extern/extern-wrong-value-type.rs b/tests/ui/extern/extern-wrong-value-type.rs new file mode 100644 index 000000000..337865ec1 --- /dev/null +++ b/tests/ui/extern/extern-wrong-value-type.rs @@ -0,0 +1,11 @@ +extern "C" fn f() { +} + +fn is_fn<F>(_: F) where F: Fn() {} + +fn main() { + // extern functions are extern "C" fn + let _x: extern "C" fn() = f; // OK + is_fn(f); + //~^ ERROR expected a `Fn<()>` closure, found `extern "C" fn() {f}` +} diff --git a/tests/ui/extern/extern-wrong-value-type.stderr b/tests/ui/extern/extern-wrong-value-type.stderr new file mode 100644 index 000000000..ff2934a2b --- /dev/null +++ b/tests/ui/extern/extern-wrong-value-type.stderr @@ -0,0 +1,19 @@ +error[E0277]: expected a `Fn<()>` closure, found `extern "C" fn() {f}` + --> $DIR/extern-wrong-value-type.rs:9:11 + | +LL | is_fn(f); + | ----- ^ expected an `Fn<()>` closure, found `extern "C" fn() {f}` + | | + | required by a bound introduced by this call + | + = help: the trait `Fn<()>` is not implemented for fn item `extern "C" fn() {f}` + = note: wrap the `extern "C" fn() {f}` in a closure with no arguments: `|| { /* code */ }` +note: required by a bound in `is_fn` + --> $DIR/extern-wrong-value-type.rs:4:28 + | +LL | fn is_fn<F>(_: F) where F: Fn() {} + | ^^^^ required by this bound in `is_fn` + +error: aborting due to previous error + +For more information about this error, try `rustc --explain E0277`. diff --git a/tests/ui/extern/extern_fat_drop.rs b/tests/ui/extern/extern_fat_drop.rs new file mode 100644 index 000000000..1cd12c2ca --- /dev/null +++ b/tests/ui/extern/extern_fat_drop.rs @@ -0,0 +1,13 @@ +// run-pass +// aux-build:fat_drop.rs + +extern crate fat_drop; + +fn main() { + unsafe { + let data: &mut [u8] = &mut [0]; + let s: &mut fat_drop::S = std::mem::transmute::<&mut [u8], _>(data); + std::ptr::drop_in_place(s); + assert!(fat_drop::DROPPED); + } +} diff --git a/tests/ui/extern/issue-10025.rs b/tests/ui/extern/issue-10025.rs new file mode 100644 index 000000000..4439b4685 --- /dev/null +++ b/tests/ui/extern/issue-10025.rs @@ -0,0 +1,11 @@ +// run-pass +// pretty-expanded FIXME #23616 +#![allow(dead_code)] + +unsafe extern fn foo() {} +unsafe extern "C" fn bar() {} + +fn main() { + let _a: unsafe extern fn() = foo; + let _a: unsafe extern "C" fn() = foo; +} diff --git a/tests/ui/extern/issue-10763.rs b/tests/ui/extern/issue-10763.rs new file mode 100644 index 000000000..627a8c238 --- /dev/null +++ b/tests/ui/extern/issue-10763.rs @@ -0,0 +1,7 @@ +// build-pass +#![allow(dead_code)] +// pretty-expanded FIXME #23616 + +extern "Rust" fn foo() {} + +fn main() {} diff --git a/tests/ui/extern/issue-10764-rpass.rs b/tests/ui/extern/issue-10764-rpass.rs new file mode 100644 index 000000000..42ed1ae93 --- /dev/null +++ b/tests/ui/extern/issue-10764-rpass.rs @@ -0,0 +1,4 @@ +// run-pass +// pretty-expanded FIXME #23616 + +extern "Rust" fn main() {} diff --git a/tests/ui/extern/issue-13655.rs b/tests/ui/extern/issue-13655.rs new file mode 100644 index 000000000..6dd184799 --- /dev/null +++ b/tests/ui/extern/issue-13655.rs @@ -0,0 +1,32 @@ +// run-pass +#![feature(fn_traits, unboxed_closures)] +use std::ops::Fn; + +struct Foo<T>(T); + +impl<T: Copy> Fn<()> for Foo<T> { + extern "rust-call" fn call(&self, _: ()) -> T { + match *self { + Foo(t) => t + } + } +} + +impl<T: Copy> FnMut<()> for Foo<T> { + extern "rust-call" fn call_mut(&mut self, _: ()) -> T { + self.call(()) + } +} + +impl<T: Copy> FnOnce<()> for Foo<T> { + type Output = T; + + extern "rust-call" fn call_once(self, _: ()) -> T { + self.call(()) + } +} + +fn main() { + let t: u8 = 1; + println!("{}", Foo(t)()); +} diff --git a/tests/ui/extern/issue-28324.mir.stderr b/tests/ui/extern/issue-28324.mir.stderr new file mode 100644 index 000000000..aff8bf792 --- /dev/null +++ b/tests/ui/extern/issue-28324.mir.stderr @@ -0,0 +1,11 @@ +error[E0133]: use of extern static is unsafe and requires unsafe function or block + --> $DIR/issue-28324.rs:8:24 + | +LL | pub static BAZ: u32 = *&error_message_count; + | ^^^^^^^^^^^^^^^^^^^^ use of extern static + | + = note: extern statics are not controlled by the Rust type system: invalid data, aliasing violations or data races will cause undefined behavior + +error: aborting due to previous error + +For more information about this error, try `rustc --explain E0133`. diff --git a/tests/ui/extern/issue-28324.rs b/tests/ui/extern/issue-28324.rs new file mode 100644 index 000000000..fbe83e325 --- /dev/null +++ b/tests/ui/extern/issue-28324.rs @@ -0,0 +1,11 @@ +// revisions: mir thir +// [thir]compile-flags: -Z thir-unsafeck + +extern "C" { + static error_message_count: u32; +} + +pub static BAZ: u32 = *&error_message_count; +//~^ ERROR use of extern static is unsafe and requires + +fn main() {} diff --git a/tests/ui/extern/issue-28324.thir.stderr b/tests/ui/extern/issue-28324.thir.stderr new file mode 100644 index 000000000..c696c3598 --- /dev/null +++ b/tests/ui/extern/issue-28324.thir.stderr @@ -0,0 +1,11 @@ +error[E0133]: use of extern static is unsafe and requires unsafe function or block + --> $DIR/issue-28324.rs:8:25 + | +LL | pub static BAZ: u32 = *&error_message_count; + | ^^^^^^^^^^^^^^^^^^^ use of extern static + | + = note: extern statics are not controlled by the Rust type system: invalid data, aliasing violations or data races will cause undefined behavior + +error: aborting due to previous error + +For more information about this error, try `rustc --explain E0133`. diff --git a/tests/ui/extern/issue-36122-accessing-externed-dst.rs b/tests/ui/extern/issue-36122-accessing-externed-dst.rs new file mode 100644 index 000000000..5f886ff57 --- /dev/null +++ b/tests/ui/extern/issue-36122-accessing-externed-dst.rs @@ -0,0 +1,6 @@ +fn main() { + extern "C" { + static symbol: [usize]; //~ ERROR: the size for values of type + } + println!("{}", symbol[0]); +} diff --git a/tests/ui/extern/issue-36122-accessing-externed-dst.stderr b/tests/ui/extern/issue-36122-accessing-externed-dst.stderr new file mode 100644 index 000000000..5f78775f5 --- /dev/null +++ b/tests/ui/extern/issue-36122-accessing-externed-dst.stderr @@ -0,0 +1,11 @@ +error[E0277]: the size for values of type `[usize]` cannot be known at compilation time + --> $DIR/issue-36122-accessing-externed-dst.rs:3:24 + | +LL | static symbol: [usize]; + | ^^^^^^^ doesn't have a size known at compile-time + | + = help: the trait `Sized` is not implemented for `[usize]` + +error: aborting due to previous error + +For more information about this error, try `rustc --explain E0277`. diff --git a/tests/ui/extern/issue-64655-allow-unwind-when-calling-panic-directly.rs b/tests/ui/extern/issue-64655-allow-unwind-when-calling-panic-directly.rs new file mode 100644 index 000000000..233120c92 --- /dev/null +++ b/tests/ui/extern/issue-64655-allow-unwind-when-calling-panic-directly.rs @@ -0,0 +1,64 @@ +// run-pass +// needs-unwind +// ignore-emscripten no threads support + +// rust-lang/rust#64655: with panic=unwind, a panic from a subroutine +// should still run destructors as it unwinds the stack. However, +// bugs with how the nounwind LLVM attribute was applied led to this +// simple case being mishandled *if* you had fat LTO turned on. + +// Unlike issue-64655-extern-rust-must-allow-unwind.rs, the issue +// embodied in this test cropped up regardless of optimization level. +// Therefore it seemed worthy of being enshrined as a dedicated unit +// test. + +// LTO settings cannot be combined with -C prefer-dynamic +// no-prefer-dynamic + +// The revisions just enumerate lto settings (the opt-level appeared irrelevant in practice) + +// revisions: no thin fat +//[no]compile-flags: -C lto=no +//[thin]compile-flags: -C lto=thin +//[fat]compile-flags: -C lto=fat + +#![feature(core_panic)] + +// (For some reason, reproducing the LTO issue requires pulling in std +// explicitly this way.) +#![no_std] +extern crate std; + +fn main() { + use std::sync::atomic::{AtomicUsize, Ordering}; + use std::boxed::Box; + + static SHARED: AtomicUsize = AtomicUsize::new(0); + + assert_eq!(SHARED.fetch_add(0, Ordering::SeqCst), 0); + + let old_hook = std::panic::take_hook(); + + std::panic::set_hook(Box::new(|_| { } )); // no-op on panic. + + let handle = std::thread::spawn(|| { + struct Droppable; + impl Drop for Droppable { + fn drop(&mut self) { + SHARED.fetch_add(1, Ordering::SeqCst); + } + } + + let _guard = Droppable; + core::panicking::panic("???"); + }); + + let wait = handle.join(); + + // Reinstate handler to ease observation of assertion failures. + std::panic::set_hook(old_hook); + + assert!(wait.is_err()); + + assert_eq!(SHARED.fetch_add(0, Ordering::SeqCst), 1); +} diff --git a/tests/ui/extern/issue-64655-extern-rust-must-allow-unwind.rs b/tests/ui/extern/issue-64655-extern-rust-must-allow-unwind.rs new file mode 100644 index 000000000..3b263e58c --- /dev/null +++ b/tests/ui/extern/issue-64655-extern-rust-must-allow-unwind.rs @@ -0,0 +1,83 @@ +// run-pass +// needs-unwind +// ignore-emscripten no threads support + +// rust-lang/rust#64655: with panic=unwind, a panic from a subroutine +// should still run destructors as it unwinds the stack. However, +// bugs with how the nounwind LLVM attribute was applied led to this +// simple case being mishandled *if* you had optimization *and* fat +// LTO turned on. + +// This test is the closest thing to a "regression test" we can do +// without actually spawning subprocesses and comparing stderr +// results. +// +// This test takes the code from the above issue and adapts it to +// better fit our test infrastructure: +// +// * Instead of relying on `println!` to observe whether the destructor +// is run, we instead run the code in a spawned thread and +// communicate the destructor's operation via a synchronous atomic +// in static memory. +// +// * To keep the output from confusing a casual user, we override the +// panic hook to be a no-op (rather than printing a message to +// stderr). +// +// (pnkfelix has confirmed by hand that these additions do not mask +// the underlying bug.) + +// LTO settings cannot be combined with -C prefer-dynamic +// no-prefer-dynamic + +// The revisions combine each lto setting with each optimization +// setting; pnkfelix observed three differing behaviors at opt-levels +// 0/1/2+3 for this test, so it seems prudent to be thorough. + +// revisions: no0 no1 no2 no3 thin0 thin1 thin2 thin3 fat0 fat1 fat2 fat3 + +//[no0]compile-flags: -C opt-level=0 -C lto=no +//[no1]compile-flags: -C opt-level=1 -C lto=no +//[no2]compile-flags: -C opt-level=2 -C lto=no +//[no3]compile-flags: -C opt-level=3 -C lto=no +//[thin0]compile-flags: -C opt-level=0 -C lto=thin +//[thin1]compile-flags: -C opt-level=1 -C lto=thin +//[thin2]compile-flags: -C opt-level=2 -C lto=thin +//[thin3]compile-flags: -C opt-level=3 -C lto=thin +//[fat0]compile-flags: -C opt-level=0 -C lto=fat +//[fat1]compile-flags: -C opt-level=1 -C lto=fat +//[fat2]compile-flags: -C opt-level=2 -C lto=fat +//[fat3]compile-flags: -C opt-level=3 -C lto=fat + +fn main() { + use std::sync::atomic::{AtomicUsize, Ordering}; + + static SHARED: AtomicUsize = AtomicUsize::new(0); + + assert_eq!(SHARED.fetch_add(0, Ordering::SeqCst), 0); + + let old_hook = std::panic::take_hook(); + + std::panic::set_hook(Box::new(|_| { } )); // no-op on panic. + + let handle = std::thread::spawn(|| { + struct Droppable; + impl Drop for Droppable { + fn drop(&mut self) { + SHARED.fetch_add(1, Ordering::SeqCst); + } + } + + let _guard = Droppable; + None::<()>.expect("???"); + }); + + let wait = handle.join(); + + // reinstate handler to ease observation of assertion failures. + std::panic::set_hook(old_hook); + + assert!(wait.is_err()); + + assert_eq!(SHARED.fetch_add(0, Ordering::SeqCst), 1); +} diff --git a/tests/ui/extern/issue-80074.rs b/tests/ui/extern/issue-80074.rs new file mode 100644 index 000000000..f83027d4a --- /dev/null +++ b/tests/ui/extern/issue-80074.rs @@ -0,0 +1,10 @@ +// edition:2018 +// build-pass +// aux-crate:issue_80074=issue-80074-macro.rs + +#[macro_use] +extern crate issue_80074; + +fn main() { + foo!(); +} diff --git a/tests/ui/extern/issue-95829.rs b/tests/ui/extern/issue-95829.rs new file mode 100644 index 000000000..3379148ae --- /dev/null +++ b/tests/ui/extern/issue-95829.rs @@ -0,0 +1,10 @@ +// edition:2018 + +extern { + async fn L() { //~ ERROR: incorrect function inside `extern` block + //~^ ERROR: functions in `extern` blocks cannot have qualifiers + async fn M() {} + } +} + +fn main() {} diff --git a/tests/ui/extern/issue-95829.stderr b/tests/ui/extern/issue-95829.stderr new file mode 100644 index 000000000..b902f0ef8 --- /dev/null +++ b/tests/ui/extern/issue-95829.stderr @@ -0,0 +1,32 @@ +error: incorrect function inside `extern` block + --> $DIR/issue-95829.rs:4:14 + | +LL | extern { + | ------ `extern` blocks define existing foreign functions and functions inside of them cannot have a body +LL | async fn L() { + | ______________^___- + | | | + | | cannot have a body +LL | | +LL | | async fn M() {} +LL | | } + | |_____- help: remove the invalid body: `;` + | + = help: you might have meant to write a function accessible through FFI, which can be done by writing `extern fn` outside of the `extern` block + = note: for more information, visit https://doc.rust-lang.org/std/keyword.extern.html + +error: functions in `extern` blocks cannot have qualifiers + --> $DIR/issue-95829.rs:4:14 + | +LL | extern { + | ------ in this `extern` block +LL | async fn L() { + | ^ + | +help: remove the qualifiers + | +LL | fn L() { + | ~~ + +error: aborting due to 2 previous errors + diff --git a/tests/ui/extern/no-mangle-associated-fn.rs b/tests/ui/extern/no-mangle-associated-fn.rs new file mode 100644 index 000000000..ecd44abbf --- /dev/null +++ b/tests/ui/extern/no-mangle-associated-fn.rs @@ -0,0 +1,37 @@ +// aux-build: no-mangle-associated-fn.rs +// run-pass + +extern crate no_mangle_associated_fn; + +struct Foo; + +impl Foo { + #[no_mangle] + fn foo() -> u8 { + 1 + } +} + +trait Bar { + fn qux() -> u8; +} + +impl Bar for Foo { + #[no_mangle] + fn qux() -> u8 { + 4 + } +} + +fn main() { + extern "Rust" { + fn foo() -> u8; + fn bar() -> u8; + fn baz() -> u8; + fn qux() -> u8; + } + assert_eq!(unsafe { foo() }, 1); + assert_eq!(unsafe { bar() }, 2); + assert_eq!(unsafe { baz() }, 3); + assert_eq!(unsafe { qux() }, 4); +} diff --git a/tests/ui/extern/not-in-block.rs b/tests/ui/extern/not-in-block.rs new file mode 100644 index 000000000..d3bcafdef --- /dev/null +++ b/tests/ui/extern/not-in-block.rs @@ -0,0 +1,6 @@ +#![crate_type = "lib"] + +extern fn none_fn(x: bool) -> i32; +//~^ ERROR free function without a body +extern "C" fn c_fn(x: bool) -> i32; +//~^ ERROR free function without a body diff --git a/tests/ui/extern/not-in-block.stderr b/tests/ui/extern/not-in-block.stderr new file mode 100644 index 000000000..2544949ab --- /dev/null +++ b/tests/ui/extern/not-in-block.stderr @@ -0,0 +1,32 @@ +error: free function without a body + --> $DIR/not-in-block.rs:3:1 + | +LL | extern fn none_fn(x: bool) -> i32; + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + | +help: provide a definition for the function + | +LL | extern fn none_fn(x: bool) -> i32 { <body> } + | ~~~~~~~~~~ +help: if you meant to declare an externally defined function, use an `extern` block + | +LL | extern { fn none_fn(x: bool) -> i32; } + | ~~~~~~~~ + + +error: free function without a body + --> $DIR/not-in-block.rs:5:1 + | +LL | extern "C" fn c_fn(x: bool) -> i32; + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + | +help: provide a definition for the function + | +LL | extern "C" fn c_fn(x: bool) -> i32 { <body> } + | ~~~~~~~~~~ +help: if you meant to declare an externally defined function, use an `extern` block + | +LL | extern "C" { fn c_fn(x: bool) -> i32; } + | ~~~~~~~~~~~~ + + +error: aborting due to 2 previous errors + |