diff options
| author | bors <bors@rust-lang.org> | 2016-09-01 11:56:51 -0700 |
|---|---|---|
| committer | GitHub <noreply@github.com> | 2016-09-01 11:56:51 -0700 |
| commit | 933f4717104aba3af71ced7e5a513f8c0bd6077a (patch) | |
| tree | 6a90d940e178680a5678c9fd92b0c92b4702bfb9 | |
| parent | 147371f58f1a99e32524d61af1d86b2e1e0a503b (diff) | |
| parent | 3d766a077944f167dbd412538af4c6957943374d (diff) | |
| download | rust-933f4717104aba3af71ced7e5a513f8c0bd6077a.tar.gz rust-933f4717104aba3af71ced7e5a513f8c0bd6077a.zip | |
Auto merge of #34494 - CensoredUsername:allow_sysV64_abi, r=nagisa
Allow specification of the system V AMD64 ABI constraint. This can be specified using `extern "sysV64" fn` on all platforms. This ABI is used as the C ABI on unix platforms, but can only be specified there using extern "C". It was impossible to specify on other platforms. Meanwhile the win64 ABI, which was the extern "C" ABI on the windows platform could be specified on other platforms using extern "win64". This pull request adds the the "sysV64" ABI constraint which exposes this calling convention on platforms where it is not the C ABI.
| -rw-r--r-- | src/doc/book/ffi.md | 1 | ||||
| -rw-r--r-- | src/doc/reference.md | 4 | ||||
| -rw-r--r-- | src/librustc_llvm/ffi.rs | 1 | ||||
| -rw-r--r-- | src/librustc_trans/abi.rs | 5 | ||||
| -rw-r--r-- | src/libsyntax/abi.rs | 2 | ||||
| -rw-r--r-- | src/libsyntax/feature_gate.rs | 23 | ||||
| -rw-r--r-- | src/test/codegen/abi-sysv64.rs | 24 | ||||
| -rw-r--r-- | src/test/compile-fail/feature-gate-abi-sysv64.rs | 19 | ||||
| -rw-r--r-- | src/test/run-pass/abi-sysv64-arg-passing.rs | 341 | ||||
| -rw-r--r-- | src/test/run-pass/abi-sysv64-register-usage.rs | 106 | ||||
| -rw-r--r-- | src/test/ui/codemap_tests/unicode.stderr | 2 |
11 files changed, 519 insertions, 9 deletions
diff --git a/src/doc/book/ffi.md b/src/doc/book/ffi.md index ca104ff29ac..1dea15311ce 100644 --- a/src/doc/book/ffi.md +++ b/src/doc/book/ffi.md @@ -539,6 +539,7 @@ This is currently hidden behind the `abi_vectorcall` gate and is subject to chan * `system` * `C` * `win64` +* `sysv64` Most of the abis in this list are self-explanatory, but the `system` abi may seem a little odd. This constraint selects whatever the appropriate ABI is for diff --git a/src/doc/reference.md b/src/doc/reference.md index be3559a5880..ec2d3e2822e 100644 --- a/src/doc/reference.md +++ b/src/doc/reference.md @@ -1677,6 +1677,7 @@ There are also some platform-specific ABI strings: * `extern "cdecl"` -- The default for x86\_32 C code. * `extern "stdcall"` -- The default for the Win32 API on x86\_32. * `extern "win64"` -- The default for C code on x86\_64 Windows. +* `extern "sysv64"` -- The default for C code on non-Windows x86\_64. * `extern "aapcs"` -- The default for ARM. * `extern "fastcall"` -- The `fastcall` ABI -- corresponds to MSVC's `__fastcall` and GCC and clang's `__attribute__((fastcall))` @@ -2485,6 +2486,9 @@ The currently implemented features of the reference compiler are: * - `dotdot_in_tuple_patterns` - Allows `..` in tuple (struct) patterns. +* - `abi_sysv64` - Allows the usage of the system V AMD64 calling convention + (e.g. `extern "sysv64" func fn_();`) + If a feature is promoted to a language feature, then all existing programs will start to receive compilation warnings about `#![feature]` directives which enabled the new feature (because the directive is no longer necessary). However, if a diff --git a/src/librustc_llvm/ffi.rs b/src/librustc_llvm/ffi.rs index 754910c246d..92fe568a72c 100644 --- a/src/librustc_llvm/ffi.rs +++ b/src/librustc_llvm/ffi.rs @@ -42,6 +42,7 @@ pub enum CallConv { ColdCallConv = 9, X86StdcallCallConv = 64, X86FastcallCallConv = 65, + X86_64_SysV = 78, X86_64_Win64 = 79, X86_VectorCall = 80 } diff --git a/src/librustc_trans/abi.rs b/src/librustc_trans/abi.rs index 3a7fde6a36b..7f209dde27d 100644 --- a/src/librustc_trans/abi.rs +++ b/src/librustc_trans/abi.rs @@ -269,6 +269,7 @@ impl FnType { Vectorcall => llvm::X86_VectorCall, C => llvm::CCallConv, Win64 => llvm::X86_64_Win64, + SysV64 => llvm::X86_64_SysV, // These API constants ought to be more specific... Cdecl => llvm::CCallConv, @@ -483,7 +484,9 @@ impl FnType { match &ccx.sess().target.target.arch[..] { "x86" => cabi_x86::compute_abi_info(ccx, self), - "x86_64" => if ccx.sess().target.target.options.is_like_windows { + "x86_64" => if abi == Abi::SysV64 { + cabi_x86_64::compute_abi_info(ccx, self); + } else if abi == Abi::Win64 || ccx.sess().target.target.options.is_like_windows { cabi_x86_win64::compute_abi_info(ccx, self); } else { cabi_x86_64::compute_abi_info(ccx, self); diff --git a/src/libsyntax/abi.rs b/src/libsyntax/abi.rs index c959e2108f5..64a71133a8c 100644 --- a/src/libsyntax/abi.rs +++ b/src/libsyntax/abi.rs @@ -39,6 +39,7 @@ pub enum Abi { Vectorcall, Aapcs, Win64, + SysV64, // Multiplatform ABIs second Rust, @@ -86,6 +87,7 @@ const AbiDatas: &'static [AbiData] = &[ AbiData {abi: Abi::Vectorcall, name: "vectorcall"}, AbiData {abi: Abi::Aapcs, name: "aapcs" }, AbiData {abi: Abi::Win64, name: "win64" }, + AbiData {abi: Abi::SysV64, name: "sysv64" }, // Cross-platform ABIs // diff --git a/src/libsyntax/feature_gate.rs b/src/libsyntax/feature_gate.rs index 1e15c156356..e224e30b1a2 100644 --- a/src/libsyntax/feature_gate.rs +++ b/src/libsyntax/feature_gate.rs @@ -281,7 +281,11 @@ declare_features! ( (active, never_type, "1.13.0", Some(35121)), // Allows all literals in attribute lists and values of key-value pairs. - (active, attr_literals, "1.13.0", Some(34981)) + (active, attr_literals, "1.13.0", Some(34981)), + + // Allows the sysV64 ABI to be specified on all platforms + // instead of just the platforms on which it is the C ABI + (active, abi_sysv64, "1.13.0", Some(36167)) ); declare_features! ( @@ -811,21 +815,26 @@ macro_rules! gate_feature_post { impl<'a> PostExpansionVisitor<'a> { fn check_abi(&self, abi: Abi, span: Span) { match abi { - Abi::RustIntrinsic => + Abi::RustIntrinsic => { gate_feature_post!(&self, intrinsics, span, - "intrinsics are subject to change"), + "intrinsics are subject to change"); + }, Abi::PlatformIntrinsic => { gate_feature_post!(&self, platform_intrinsics, span, - "platform intrinsics are experimental and possibly buggy") + "platform intrinsics are experimental and possibly buggy"); }, Abi::Vectorcall => { gate_feature_post!(&self, abi_vectorcall, span, - "vectorcall is experimental and subject to change") - } + "vectorcall is experimental and subject to change"); + }, Abi::RustCall => { gate_feature_post!(&self, unboxed_closures, span, "rust-call ABI is subject to change"); - } + }, + Abi::SysV64 => { + gate_feature_post!(&self, abi_sysv64, span, + "sysv64 ABI is experimental and subject to change"); + }, _ => {} } } diff --git a/src/test/codegen/abi-sysv64.rs b/src/test/codegen/abi-sysv64.rs new file mode 100644 index 00000000000..2b8e8a1b6b2 --- /dev/null +++ b/src/test/codegen/abi-sysv64.rs @@ -0,0 +1,24 @@ +// Copyright 2016 The Rust Project Developers. See the COPYRIGHT +// file at the top-level directory of this distribution and at +// http://rust-lang.org/COPYRIGHT. +// +// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or +// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license +// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your +// option. This file may not be copied, modified, or distributed +// except according to those terms. + +// Checks if the correct annotation for the sysv64 ABI is passed to +// llvm. Also checks that the abi-sysv64 feature gate allows usage +// of the sysv64 abi. + +// compile-flags: -C no-prepopulate-passes + +#![crate_type = "lib"] +#![feature(abi_sysv64)] + +// CHECK: define x86_64_sysvcc i64 @has_sysv64_abi +#[no_mangle] +pub extern "sysv64" fn has_sysv64_abi(a: i64) -> i64 { + a * 2 +} diff --git a/src/test/compile-fail/feature-gate-abi-sysv64.rs b/src/test/compile-fail/feature-gate-abi-sysv64.rs new file mode 100644 index 00000000000..2a4aae8c06b --- /dev/null +++ b/src/test/compile-fail/feature-gate-abi-sysv64.rs @@ -0,0 +1,19 @@ +// Copyright 2016 The Rust Project Developers. See the COPYRIGHT +// file at the top-level directory of this distribution and at +// http://rust-lang.org/COPYRIGHT. +// +// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or +// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license +// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your +// option. This file may not be copied, modified, or distributed +// except according to those terms. + +// Test that the sysv64 ABI cannot be used when abi-sysv64 feature +// gate is not used. + +extern "sysv64" fn foo() {} +//~^ ERROR sysv64 ABI is experimental and subject to change + +fn main() { + foo(); +} diff --git a/src/test/run-pass/abi-sysv64-arg-passing.rs b/src/test/run-pass/abi-sysv64-arg-passing.rs new file mode 100644 index 00000000000..989155bdfd9 --- /dev/null +++ b/src/test/run-pass/abi-sysv64-arg-passing.rs @@ -0,0 +1,341 @@ +// Copyright 2016 The Rust Project Developers. See the COPYRIGHT +// file at the top-level directory of this distribution and at +// http://rust-lang.org/COPYRIGHT. +// +// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or +// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license +// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your +// option. This file may not be copied, modified, or distributed +// except according to those terms. + +// Checks if the "sysv64" calling convention behaves the same as the +// "C" calling convention on platforms where both should be the same + +// This file contains versions of the following run-pass tests with +// the calling convention changed to "sysv64" + +// cabi-int-widening +// extern-pass-char +// extern-pass-u32 +// extern-pass-u64 +// extern-pass-double +// extern-pass-empty +// extern-pass-TwoU8s +// extern-pass-TwoU16s +// extern-pass-TwoU32s +// extern-pass-TwoU64s +// extern-return-TwoU8s +// extern-return-TwoU16s +// extern-return-TwoU32s +// extern-return-TwoU64s +// foreign-fn-with-byval +// issue-28676 +// struct-return + +// ignore-android +// ignore-arm +// ignore-aarch64 +// ignore-windows + +// note: windows is ignored as rust_test_helpers does not have the sysv64 abi on windows + +#![feature(abi_sysv64)] +#[allow(dead_code)] +#[allow(improper_ctypes)] + +#[cfg(target_arch = "x86_64")] +mod tests { + #[repr(C)] + #[derive(Copy, Clone, PartialEq, Debug)] + pub struct TwoU8s { + one: u8, two: u8 + } + + #[repr(C)] + #[derive(Copy, Clone, PartialEq, Debug)] + pub struct TwoU16s { + one: u16, two: u16 + } + + #[repr(C)] + #[derive(Copy, Clone, PartialEq, Debug)] + pub struct TwoU32s { + one: u32, two: u32 + } + + #[repr(C)] + #[derive(Copy, Clone, PartialEq, Debug)] + pub struct TwoU64s { + one: u64, two: u64 + } + + #[repr(C)] + pub struct ManyInts { + arg1: i8, + arg2: i16, + arg3: i32, + arg4: i16, + arg5: i8, + arg6: TwoU8s, + } + + #[repr(C)] + pub struct Empty; + + #[repr(C)] + #[derive(Copy, Clone)] + pub struct S { + x: u64, + y: u64, + z: u64, + } + + #[repr(C)] + #[derive(Copy, Clone)] + pub struct Quad { a: u64, b: u64, c: u64, d: u64 } + + #[repr(C)] + #[derive(Copy, Clone)] + pub struct Floats { a: f64, b: u8, c: f64 } + + #[link(name = "rust_test_helpers")] + extern "sysv64" { + pub fn rust_int8_to_int32(_: i8) -> i32; + pub fn rust_dbg_extern_identity_u8(v: u8) -> u8; + pub fn rust_dbg_extern_identity_u32(v: u32) -> u32; + pub fn rust_dbg_extern_identity_u64(v: u64) -> u64; + pub fn rust_dbg_extern_identity_double(v: f64) -> f64; + pub fn rust_dbg_extern_empty_struct(v1: ManyInts, e: Empty, v2: ManyInts); + pub fn rust_dbg_extern_identity_TwoU8s(v: TwoU8s) -> TwoU8s; + pub fn rust_dbg_extern_identity_TwoU16s(v: TwoU16s) -> TwoU16s; + pub fn rust_dbg_extern_identity_TwoU32s(v: TwoU32s) -> TwoU32s; + pub fn rust_dbg_extern_identity_TwoU64s(v: TwoU64s) -> TwoU64s; + pub fn rust_dbg_extern_return_TwoU8s() -> TwoU8s; + pub fn rust_dbg_extern_return_TwoU16s() -> TwoU16s; + pub fn rust_dbg_extern_return_TwoU32s() -> TwoU32s; + pub fn rust_dbg_extern_return_TwoU64s() -> TwoU64s; + pub fn get_x(x: S) -> u64; + pub fn get_y(x: S) -> u64; + pub fn get_z(x: S) -> u64; + pub fn get_c_many_params(_: *const (), _: *const (), + _: *const (), _: *const (), f: Quad) -> u64; + pub fn rust_dbg_abi_1(q: Quad) -> Quad; + pub fn rust_dbg_abi_2(f: Floats) -> Floats; + } + + pub fn cabi_int_widening() { + let x = unsafe { + rust_int8_to_int32(-1) + }; + + assert!(x == -1); + } + + pub fn extern_pass_char() { + unsafe { + assert_eq!(22, rust_dbg_extern_identity_u8(22)); + } + } + + pub fn extern_pass_u32() { + unsafe { + assert_eq!(22, rust_dbg_extern_identity_u32(22)); + } + } + + pub fn extern_pass_u64() { + unsafe { + assert_eq!(22, rust_dbg_extern_identity_u64(22)); + } + } + + pub fn extern_pass_double() { + unsafe { + assert_eq!(22.0_f64, rust_dbg_extern_identity_double(22.0_f64)); + } + } + + pub fn extern_pass_empty() { + unsafe { + let x = ManyInts { + arg1: 2, + arg2: 3, + arg3: 4, + arg4: 5, + arg5: 6, + arg6: TwoU8s { one: 7, two: 8, } + }; + let y = ManyInts { + arg1: 1, + arg2: 2, + arg3: 3, + arg4: 4, + arg5: 5, + arg6: TwoU8s { one: 6, two: 7, } + }; + let empty = Empty; + rust_dbg_extern_empty_struct(x, empty, y); + } + } + + pub fn extern_pass_twou8s() { + unsafe { + let x = TwoU8s {one: 22, two: 23}; + let y = rust_dbg_extern_identity_TwoU8s(x); + assert_eq!(x, y); + } + } + + pub fn extern_pass_twou16s() { + unsafe { + let x = TwoU16s {one: 22, two: 23}; + let y = rust_dbg_extern_identity_TwoU16s(x); + assert_eq!(x, y); + } + } + + pub fn extern_pass_twou32s() { + unsafe { + let x = TwoU32s {one: 22, two: 23}; + let y = rust_dbg_extern_identity_TwoU32s(x); + assert_eq!(x, y); + } + } + + pub fn extern_pass_twou64s() { + unsafe { + let x = TwoU64s {one: 22, two: 23}; + let y = rust_dbg_extern_identity_TwoU64s(x); + assert_eq!(x, y); + } + } + + pub fn extern_return_twou8s() { + unsafe { + let y = rust_dbg_extern_return_TwoU8s(); + assert_eq!(y.one, 10); + assert_eq!(y.two, 20); + } + } + + pub fn extern_return_twou16s() { + unsafe { + let y = rust_dbg_extern_return_TwoU16s(); + assert_eq!(y.one, 10); + assert_eq!(y.two, 20); + } + } + + pub fn extern_return_twou32s() { + unsafe { + let y = rust_dbg_extern_return_TwoU32s(); + assert_eq!(y.one, 10); + assert_eq!(y.two, 20); + } + } + + pub fn extern_return_twou64s() { + unsafe { + let y = rust_dbg_extern_return_TwoU64s(); + assert_eq!(y.one, 10); + assert_eq!(y.two, 20); + } + } + + #[inline(never)] + fn indirect_call(func: unsafe extern "sysv64" fn(s: S) -> u64, s: S) -> u64 { + unsafe { + func(s) + } + } + + pub fn foreign_fn_with_byval() { + let s = S { x: 1, y: 2, z: 3 }; + assert_eq!(s.x, indirect_call(get_x, s)); + assert_eq!(s.y, indirect_call(get_y, s)); + assert_eq!(s.z, indirect_call(get_z, s)); + } + + fn test() { + use std::ptr; + unsafe { + let null = ptr::null(); + let q = Quad { + a: 1, + b: 2, + c: 3, + d: 4 + }; + assert_eq!(get_c_many_params(null, null, null, null, q), q.c); + } + } + + pub fn issue_28676() { + test(); + } + + fn test1() { + unsafe { + let q = Quad { a: 0xaaaa_aaaa_aaaa_aaaa, + b: 0xbbbb_bbbb_bbbb_bbbb, + c: 0xcccc_cccc_cccc_cccc, + d: 0xdddd_dddd_dddd_dddd }; + let qq = rust_dbg_abi_1(q); + println!("a: {:x}", qq.a as usize); + println!("b: {:x}", qq.b as usize); + println!("c: {:x}", qq.c as usize); + println!("d: {:x}", qq.d as usize); + assert_eq!(qq.a, q.c + 1); + assert_eq!(qq.b, q.d - 1); + assert_eq!(qq.c, q.a + 1); + assert_eq!(qq.d, q.b - 1); + } + } + + fn test2() { + unsafe { + let f = Floats { a: 1.234567890e-15_f64, + b: 0b_1010_1010, + c: 1.0987654321e-15_f64 }; + let ff = rust_dbg_abi_2(f); + println!("a: {}", ff.a as f64); + println!("b: {}", ff.b as usize); + println!("c: {}", ff.c as f64); + assert_eq!(ff.a, f.c + 1.0f64); + assert_eq!(ff.b, 0xff); + assert_eq!(ff.c, f.a - 1.0f64); + } + } + + pub fn struct_return() { + test1(); + test2(); + } +} + +#[cfg(target_arch = "x86_64")] +fn main() { + use tests::*; + cabi_int_widening(); + extern_pass_char(); + extern_pass_u32(); + extern_pass_u64(); + extern_pass_double(); + extern_pass_empty(); + extern_pass_twou8s(); + extern_pass_twou16s(); + extern_pass_twou32s(); + extern_pass_twou64s(); + extern_return_twou8s(); + extern_return_twou16s(); + extern_return_twou32s(); + extern_return_twou64s(); + foreign_fn_with_byval(); + issue_28676(); + struct_return(); +} + +#[cfg(not(target_arch = "x86_64"))] +fn main() { + +} diff --git a/src/test/run-pass/abi-sysv64-register-usage.rs b/src/test/run-pass/abi-sysv64-register-usage.rs new file mode 100644 index 00000000000..7e3b32122ac --- /dev/null +++ b/src/test/run-pass/abi-sysv64-register-usage.rs @@ -0,0 +1,106 @@ +// Copyright 2016 The Rust Project Developers. See the COPYRIGHT +// file at the top-level directory of this distribution and at +// http://rust-lang.org/COPYRIGHT. +// +// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or +// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license +// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your +// option. This file may not be copied, modified, or distributed +// except according to those terms. + +// Checks if the correct registers are being used to pass arguments +// when the sysv64 ABI is specified. + +// ignore-android +// ignore-arm +// ignore-aarch64 + +#![feature(abi_sysv64)] +#![feature(asm)] + +#[cfg(target_arch = "x86_64")] +pub extern "sysv64" fn all_the_registers(rdi: i64, rsi: i64, rdx: i64, + rcx: i64, r8 : i64, r9 : i64, + xmm0: f32, xmm1: f32, xmm2: f32, + xmm3: f32, xmm4: f32, xmm5: f32, + xmm6: f32, xmm7: f32) -> i64 { + assert_eq!(rdi, 1); + assert_eq!(rsi, 2); + assert_eq!(rdx, 3); + assert_eq!(rcx, 4); + assert_eq!(r8, 5); + assert_eq!(r9, 6); + assert_eq!(xmm0, 1.0f32); + assert_eq!(xmm1, 2.0f32); + assert_eq!(xmm2, 4.0f32); + assert_eq!(xmm3, 8.0f32); + assert_eq!(xmm4, 16.0f32); + assert_eq!(xmm5, 32.0f32); + assert_eq!(xmm6, 64.0f32); + assert_eq!(xmm7, 128.0f32); + 42 +} + +// this struct contains 8 i64's, while only 6 can be passed in registers. +#[cfg(target_arch = "x86_64")] +#[derive(PartialEq, Eq, Debug)] +pub struct LargeStruct(i64, i64, i64, i64, i64, i64, i64, i64); + +#[cfg(target_arch = "x86_64")] +#[inline(never)] +pub extern "sysv64" fn large_struct_by_val(mut foo: LargeStruct) -> LargeStruct { + foo.0 *= 1; + foo.1 *= 2; + foo.2 *= 3; + foo.3 *= 4; + foo.4 *= 5; + foo.5 *= 6; + foo.6 *= 7; + foo.7 *= 8; + foo +} + +#[cfg(target_arch = "x86_64")] +pub fn main() { + let result: i64; + unsafe { + asm!("mov rdi, 1; + mov rsi, 2; + mov rdx, 3; + mov rcx, 4; + mov r8, 5; + mov r9, 6; + mov eax, 0x3F800000; + movd xmm0, eax; + mov eax, 0x40000000; + movd xmm1, eax; + mov eax, 0x40800000; + movd xmm2, eax; + mov eax, 0x41000000; + movd xmm3, eax; + mov eax, 0x41800000; + movd xmm4, eax; + mov eax, 0x42000000; + movd xmm5, eax; + mov eax, 0x42800000; + movd xmm6, eax; + mov eax, 0x43000000; + movd xmm7, eax; + call r10 + " + : "={rax}"(result) + : "{r10}"(all_the_registers as usize) + : "rdi", "rsi", "rdx", "rcx", "r8", "r9", "r11", "cc", "memory" + : "intel", "alignstack" + ) + } + assert_eq!(result, 42); + + assert_eq!( + large_struct_by_val(LargeStruct(1, 2, 3, 4, 5, 6, 7, 8)), + LargeStruct(1, 4, 9, 16, 25, 36, 49, 64) + ); +} + +#[cfg(not(target_arch = "x86_64"))] +pub fn main() {} \ No newline at end of file diff --git a/src/test/ui/codemap_tests/unicode.stderr b/src/test/ui/codemap_tests/unicode.stderr index aa42ae341c5..a748e13ecf1 100644 --- a/src/test/ui/codemap_tests/unicode.stderr +++ b/src/test/ui/codemap_tests/unicode.stderr @@ -1,4 +1,4 @@ -error: invalid ABI: expected one of [cdecl, stdcall, fastcall, vectorcall, aapcs, win64, Rust, C, system, rust-intrinsic, rust-call, platform-intrinsic], found `路濫狼á́́` +error: invalid ABI: expected one of [cdecl, stdcall, fastcall, vectorcall, aapcs, win64, sysv64, Rust, C, system, rust-intrinsic, rust-call, platform-intrinsic], found `路濫狼á́́` --> $DIR/unicode.rs:11:8 | 11 | extern "路濫狼á́́" fn foo() {} |
