summaryrefslogtreecommitdiffstats
path: root/tests/ui/extern
diff options
context:
space:
mode:
Diffstat (limited to 'tests/ui/extern')
-rw-r--r--tests/ui/extern/auxiliary/extern-take-value.rs5
-rw-r--r--tests/ui/extern/auxiliary/extern-types-inherent-impl.rs9
-rw-r--r--tests/ui/extern/auxiliary/extern_calling_convention.rs26
-rw-r--r--tests/ui/extern/auxiliary/extern_mod_ordering_lib.rs5
-rw-r--r--tests/ui/extern/auxiliary/fat_drop.rs13
-rw-r--r--tests/ui/extern/auxiliary/invalid-utf8.txt1
-rw-r--r--tests/ui/extern/auxiliary/issue-80074-macro.rs4
-rw-r--r--tests/ui/extern/auxiliary/m1.rs1
-rw-r--r--tests/ui/extern/auxiliary/m2.rs1
-rw-r--r--tests/ui/extern/auxiliary/no-mangle-associated-fn.rs21
-rw-r--r--tests/ui/extern/auxiliary/reexport-should-still-link.rs5
-rw-r--r--tests/ui/extern/extern-1.rs9
-rw-r--r--tests/ui/extern/extern-calling-convention-test.rs12
-rw-r--r--tests/ui/extern/extern-compare-with-return-type.rs27
-rw-r--r--tests/ui/extern/extern-const.fixed26
-rw-r--r--tests/ui/extern/extern-const.rs26
-rw-r--r--tests/ui/extern/extern-const.stderr12
-rw-r--r--tests/ui/extern/extern-crate-multiple-missing.rs10
-rw-r--r--tests/ui/extern/extern-crate-multiple-missing.stderr15
-rw-r--r--tests/ui/extern/extern-crate-rename.rs8
-rw-r--r--tests/ui/extern/extern-crate-rename.stderr17
-rw-r--r--tests/ui/extern/extern-crate-visibility.rs24
-rw-r--r--tests/ui/extern/extern-crate-visibility.stderr27
-rw-r--r--tests/ui/extern/extern-ffi-fn-with-body.rs11
-rw-r--r--tests/ui/extern/extern-ffi-fn-with-body.stderr18
-rw-r--r--tests/ui/extern/extern-foreign-crate.rs6
-rw-r--r--tests/ui/extern/extern-macro.rs6
-rw-r--r--tests/ui/extern/extern-macro.stderr9
-rw-r--r--tests/ui/extern/extern-main-fn.rs1
-rw-r--r--tests/ui/extern/extern-main-fn.stderr12
-rw-r--r--tests/ui/extern/extern-main-issue-86110.rs7
-rw-r--r--tests/ui/extern/extern-main-issue-86110.stderr8
-rw-r--r--tests/ui/extern/extern-methods.rs29
-rw-r--r--tests/ui/extern/extern-mod-abi.rs9
-rw-r--r--tests/ui/extern/extern-mod-ordering-exe.rs12
-rw-r--r--tests/ui/extern/extern-no-mangle.rs30
-rw-r--r--tests/ui/extern/extern-no-mangle.stderr42
-rw-r--r--tests/ui/extern/extern-prelude-core.rs18
-rw-r--r--tests/ui/extern/extern-prelude-no-speculative.rs13
-rw-r--r--tests/ui/extern/extern-prelude-std.rs12
-rw-r--r--tests/ui/extern/extern-pub.rs8
-rw-r--r--tests/ui/extern/extern-rust.rs12
-rw-r--r--tests/ui/extern/extern-static-size-overflow.rs43
-rw-r--r--tests/ui/extern/extern-static-size-overflow.stderr20
-rw-r--r--tests/ui/extern/extern-take-value.rs13
-rw-r--r--tests/ui/extern/extern-thiscall.rs25
-rw-r--r--tests/ui/extern/extern-type-diag-not-similar.rs22
-rw-r--r--tests/ui/extern/extern-type-diag-not-similar.stderr16
-rw-r--r--tests/ui/extern/extern-types-distinct-types.rs12
-rw-r--r--tests/ui/extern/extern-types-distinct-types.stderr19
-rw-r--r--tests/ui/extern/extern-types-inherent-impl.rs26
-rw-r--r--tests/ui/extern/extern-types-manual-sync-send.rs19
-rw-r--r--tests/ui/extern/extern-types-not-sync-send.rs18
-rw-r--r--tests/ui/extern/extern-types-not-sync-send.stderr29
-rw-r--r--tests/ui/extern/extern-types-pointer-cast.rs31
-rw-r--r--tests/ui/extern/extern-types-size_of_val.rs15
-rw-r--r--tests/ui/extern/extern-types-thin-pointer.rs42
-rw-r--r--tests/ui/extern/extern-types-trait-impl.rs26
-rw-r--r--tests/ui/extern/extern-types-unsized.rs33
-rw-r--r--tests/ui/extern/extern-types-unsized.stderr86
-rw-r--r--tests/ui/extern/extern-vectorcall.rs27
-rw-r--r--tests/ui/extern/extern-with-type-bounds.rs22
-rw-r--r--tests/ui/extern/extern-with-type-bounds.stderr9
-rw-r--r--tests/ui/extern/extern-wrong-value-type.rs11
-rw-r--r--tests/ui/extern/extern-wrong-value-type.stderr19
-rw-r--r--tests/ui/extern/extern_fat_drop.rs13
-rw-r--r--tests/ui/extern/issue-10025.rs11
-rw-r--r--tests/ui/extern/issue-10763.rs7
-rw-r--r--tests/ui/extern/issue-10764-rpass.rs4
-rw-r--r--tests/ui/extern/issue-13655.rs32
-rw-r--r--tests/ui/extern/issue-28324.mir.stderr11
-rw-r--r--tests/ui/extern/issue-28324.rs11
-rw-r--r--tests/ui/extern/issue-28324.thir.stderr11
-rw-r--r--tests/ui/extern/issue-36122-accessing-externed-dst.rs6
-rw-r--r--tests/ui/extern/issue-36122-accessing-externed-dst.stderr11
-rw-r--r--tests/ui/extern/issue-64655-allow-unwind-when-calling-panic-directly.rs64
-rw-r--r--tests/ui/extern/issue-64655-extern-rust-must-allow-unwind.rs83
-rw-r--r--tests/ui/extern/issue-80074.rs10
-rw-r--r--tests/ui/extern/issue-95829.rs10
-rw-r--r--tests/ui/extern/issue-95829.stderr32
-rw-r--r--tests/ui/extern/no-mangle-associated-fn.rs37
-rw-r--r--tests/ui/extern/not-in-block.rs6
-rw-r--r--tests/ui/extern/not-in-block.stderr32
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
+