Rollup merge of #97971 - Soveu:varargs, r=jackh726
Enable varargs support for calling conventions other than C or cdecl This patch makes it possible to use varargs for calling conventions, which are either based on C (efiapi) or C is based on them (sysv64 and win64). Also pinging ``@phlopsi,`` because he noticed first this oversight when writing a library for UEFI.
This commit is contained in:
commit
9911229650
12 changed files with 174 additions and 35 deletions
|
@ -388,6 +388,9 @@ declare_features! (
|
|||
(active, exclusive_range_pattern, "1.11.0", Some(37854), None),
|
||||
/// Allows exhaustive pattern matching on types that contain uninhabited types.
|
||||
(active, exhaustive_patterns, "1.13.0", Some(51085), None),
|
||||
/// Allows using `efiapi`, `sysv64` and `win64` as calling convention
|
||||
/// for functions with varargs.
|
||||
(active, extended_varargs_abi_support, "1.65.0", Some(100189), None),
|
||||
/// Allows defining `extern type`s.
|
||||
(active, extern_types, "1.23.0", Some(43467), None),
|
||||
/// Allows the use of `#[ffi_const]` on foreign functions.
|
||||
|
|
|
@ -106,7 +106,7 @@ use rustc_middle::middle;
|
|||
use rustc_middle::ty::query::Providers;
|
||||
use rustc_middle::ty::{self, Ty, TyCtxt};
|
||||
use rustc_middle::util;
|
||||
use rustc_session::config::EntryFnType;
|
||||
use rustc_session::{config::EntryFnType, parse::feature_err};
|
||||
use rustc_span::{symbol::sym, Span, DUMMY_SP};
|
||||
use rustc_target::spec::abi::Abi;
|
||||
use rustc_trait_selection::traits::error_reporting::TypeErrCtxtExt as _;
|
||||
|
@ -118,20 +118,40 @@ use astconv::AstConv;
|
|||
use bounds::Bounds;
|
||||
|
||||
fn require_c_abi_if_c_variadic(tcx: TyCtxt<'_>, decl: &hir::FnDecl<'_>, abi: Abi, span: Span) {
|
||||
match (decl.c_variadic, abi) {
|
||||
// The function has the correct calling convention, or isn't a "C-variadic" function.
|
||||
(false, _) | (true, Abi::C { .. }) | (true, Abi::Cdecl { .. }) => {}
|
||||
// The function is a "C-variadic" function with an incorrect calling convention.
|
||||
(true, _) => {
|
||||
let mut err = struct_span_err!(
|
||||
tcx.sess,
|
||||
span,
|
||||
E0045,
|
||||
"C-variadic function must have C or cdecl calling convention"
|
||||
);
|
||||
err.span_label(span, "C-variadics require C or cdecl calling convention").emit();
|
||||
}
|
||||
const ERROR_HEAD: &str = "C-variadic function must have a compatible calling convention";
|
||||
const CONVENTIONS_UNSTABLE: &str = "`C`, `cdecl`, `win64`, `sysv64` or `efiapi`";
|
||||
const CONVENTIONS_STABLE: &str = "`C` or `cdecl`";
|
||||
const UNSTABLE_EXPLAIN: &str =
|
||||
"using calling conventions other than `C` or `cdecl` for varargs functions is unstable";
|
||||
|
||||
if !decl.c_variadic || matches!(abi, Abi::C { .. } | Abi::Cdecl { .. }) {
|
||||
return;
|
||||
}
|
||||
|
||||
let extended_abi_support = tcx.features().extended_varargs_abi_support;
|
||||
let conventions = match (extended_abi_support, abi.supports_varargs()) {
|
||||
// User enabled additional ABI support for varargs and function ABI matches those ones.
|
||||
(true, true) => return,
|
||||
|
||||
// Using this ABI would be ok, if the feature for additional ABI support was enabled.
|
||||
// Return CONVENTIONS_STABLE, because we want the other error to look the same.
|
||||
(false, true) => {
|
||||
feature_err(
|
||||
&tcx.sess.parse_sess,
|
||||
sym::extended_varargs_abi_support,
|
||||
span,
|
||||
UNSTABLE_EXPLAIN,
|
||||
)
|
||||
.emit();
|
||||
CONVENTIONS_STABLE
|
||||
}
|
||||
|
||||
(false, false) => CONVENTIONS_STABLE,
|
||||
(true, false) => CONVENTIONS_UNSTABLE,
|
||||
};
|
||||
|
||||
let mut err = struct_span_err!(tcx.sess, span, E0045, "{}, like {}", ERROR_HEAD, conventions);
|
||||
err.span_label(span, ERROR_HEAD).emit();
|
||||
}
|
||||
|
||||
fn require_same_types<'tcx>(
|
||||
|
|
|
@ -694,6 +694,7 @@ symbols! {
|
|||
export_name,
|
||||
expr,
|
||||
extended_key_value_attributes,
|
||||
extended_varargs_abi_support,
|
||||
extern_absolute_paths,
|
||||
extern_crate_item_prelude,
|
||||
extern_crate_self,
|
||||
|
|
|
@ -40,6 +40,28 @@ pub enum Abi {
|
|||
RustCold,
|
||||
}
|
||||
|
||||
impl Abi {
|
||||
pub fn supports_varargs(self) -> bool {
|
||||
// * C and Cdecl obviously support varargs.
|
||||
// * C can be based on SysV64 or Win64, so they must support varargs.
|
||||
// * EfiApi is based on Win64 or C, so it also supports it.
|
||||
//
|
||||
// * Stdcall does not, because it would be impossible for the callee to clean
|
||||
// up the arguments. (callee doesn't know how many arguments are there)
|
||||
// * Same for Fastcall, Vectorcall and Thiscall.
|
||||
// * System can become Stdcall, so is also a no-no.
|
||||
// * Other calling conventions are related to hardware or the compiler itself.
|
||||
match self {
|
||||
Self::C { .. }
|
||||
| Self::Cdecl { .. }
|
||||
| Self::Win64 { .. }
|
||||
| Self::SysV64 { .. }
|
||||
| Self::EfiApi => true,
|
||||
_ => false,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Copy, Clone)]
|
||||
pub struct AbiData {
|
||||
abi: Abi,
|
||||
|
|
|
@ -0,0 +1,10 @@
|
|||
# `extended_varargs_abi_support`
|
||||
|
||||
The tracking issue for this feature is: [#100189]
|
||||
|
||||
[#100189]: https://github.com/rust-lang/rust/issues/100189
|
||||
|
||||
------------------------
|
||||
|
||||
This feature adds the possibility of using `sysv64`, `win64` or `efiapi` calling
|
||||
conventions on functions with varargs.
|
|
@ -0,0 +1,19 @@
|
|||
#![feature(abi_efiapi)]
|
||||
|
||||
fn efiapi(f: extern "efiapi" fn(usize, ...)) {
|
||||
//~^ ERROR: C-variadic function must have a compatible calling convention, like `C` or `cdecl`
|
||||
//~^^ ERROR: using calling conventions other than `C` or `cdecl` for varargs functions is unstable
|
||||
f(22, 44);
|
||||
}
|
||||
fn sysv(f: extern "sysv64" fn(usize, ...)) {
|
||||
//~^ ERROR: C-variadic function must have a compatible calling convention, like `C` or `cdecl`
|
||||
//~^^ ERROR: using calling conventions other than `C` or `cdecl` for varargs functions is unstable
|
||||
f(22, 44);
|
||||
}
|
||||
fn win(f: extern "win64" fn(usize, ...)) {
|
||||
//~^ ERROR: C-variadic function must have a compatible calling convention, like `C` or `cdecl`
|
||||
//~^^ ERROR: using calling conventions other than `C` or `cdecl` for varargs functions is unstable
|
||||
f(22, 44);
|
||||
}
|
||||
|
||||
fn main() {}
|
|
@ -0,0 +1,49 @@
|
|||
error[E0658]: using calling conventions other than `C` or `cdecl` for varargs functions is unstable
|
||||
--> $DIR/feature-gate-extended_varargs_abi_support.rs:3:14
|
||||
|
|
||||
LL | fn efiapi(f: extern "efiapi" fn(usize, ...)) {
|
||||
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
|
||||
|
|
||||
= note: see issue #100189 <https://github.com/rust-lang/rust/issues/100189> for more information
|
||||
= help: add `#![feature(extended_varargs_abi_support)]` to the crate attributes to enable
|
||||
|
||||
error[E0045]: C-variadic function must have a compatible calling convention, like `C` or `cdecl`
|
||||
--> $DIR/feature-gate-extended_varargs_abi_support.rs:3:14
|
||||
|
|
||||
LL | fn efiapi(f: extern "efiapi" fn(usize, ...)) {
|
||||
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ C-variadic function must have a compatible calling convention
|
||||
|
||||
error[E0658]: using calling conventions other than `C` or `cdecl` for varargs functions is unstable
|
||||
--> $DIR/feature-gate-extended_varargs_abi_support.rs:8:12
|
||||
|
|
||||
LL | fn sysv(f: extern "sysv64" fn(usize, ...)) {
|
||||
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
|
||||
|
|
||||
= note: see issue #100189 <https://github.com/rust-lang/rust/issues/100189> for more information
|
||||
= help: add `#![feature(extended_varargs_abi_support)]` to the crate attributes to enable
|
||||
|
||||
error[E0045]: C-variadic function must have a compatible calling convention, like `C` or `cdecl`
|
||||
--> $DIR/feature-gate-extended_varargs_abi_support.rs:8:12
|
||||
|
|
||||
LL | fn sysv(f: extern "sysv64" fn(usize, ...)) {
|
||||
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ C-variadic function must have a compatible calling convention
|
||||
|
||||
error[E0658]: using calling conventions other than `C` or `cdecl` for varargs functions is unstable
|
||||
--> $DIR/feature-gate-extended_varargs_abi_support.rs:13:11
|
||||
|
|
||||
LL | fn win(f: extern "win64" fn(usize, ...)) {
|
||||
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
|
||||
|
|
||||
= note: see issue #100189 <https://github.com/rust-lang/rust/issues/100189> for more information
|
||||
= help: add `#![feature(extended_varargs_abi_support)]` to the crate attributes to enable
|
||||
|
||||
error[E0045]: C-variadic function must have a compatible calling convention, like `C` or `cdecl`
|
||||
--> $DIR/feature-gate-extended_varargs_abi_support.rs:13:11
|
||||
|
|
||||
LL | fn win(f: extern "win64" fn(usize, ...)) {
|
||||
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ C-variadic function must have a compatible calling convention
|
||||
|
||||
error: aborting due to 6 previous errors
|
||||
|
||||
Some errors have detailed explanations: E0045, E0658.
|
||||
For more information about an error, try `rustc --explain E0045`.
|
|
@ -6,7 +6,9 @@
|
|||
trait Sized { }
|
||||
|
||||
extern "stdcall" {
|
||||
fn printf(_: *const u8, ...); //~ ERROR: variadic function must have C or cdecl calling
|
||||
fn printf(_: *const u8, ...);
|
||||
//~^ ERROR: C-variadic function must have a compatible calling convention,
|
||||
// like C, cdecl, win64, sysv64 or efiapi
|
||||
}
|
||||
|
||||
extern "C" {
|
||||
|
|
|
@ -1,17 +1,17 @@
|
|||
error[E0045]: C-variadic function must have C or cdecl calling convention
|
||||
error[E0045]: C-variadic function must have a compatible calling convention, like `C` or `cdecl`
|
||||
--> $DIR/variadic-ffi-1.rs:9:5
|
||||
|
|
||||
LL | fn printf(_: *const u8, ...);
|
||||
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ C-variadics require C or cdecl calling convention
|
||||
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ C-variadic function must have a compatible calling convention
|
||||
|
||||
error[E0060]: this function takes at least 2 arguments but 0 arguments were supplied
|
||||
--> $DIR/variadic-ffi-1.rs:20:9
|
||||
--> $DIR/variadic-ffi-1.rs:22:9
|
||||
|
|
||||
LL | foo();
|
||||
| ^^^-- two arguments of type `isize` and `u8` are missing
|
||||
|
|
||||
note: function defined here
|
||||
--> $DIR/variadic-ffi-1.rs:13:8
|
||||
--> $DIR/variadic-ffi-1.rs:15:8
|
||||
|
|
||||
LL | fn foo(f: isize, x: u8, ...);
|
||||
| ^^^
|
||||
|
@ -21,13 +21,13 @@ LL | foo(/* isize */, /* u8 */);
|
|||
| ~~~~~~~~~~~~~~~~~~~~~~~
|
||||
|
||||
error[E0060]: this function takes at least 2 arguments but 1 argument was supplied
|
||||
--> $DIR/variadic-ffi-1.rs:21:9
|
||||
--> $DIR/variadic-ffi-1.rs:23:9
|
||||
|
|
||||
LL | foo(1);
|
||||
| ^^^--- an argument of type `u8` is missing
|
||||
|
|
||||
note: function defined here
|
||||
--> $DIR/variadic-ffi-1.rs:13:8
|
||||
--> $DIR/variadic-ffi-1.rs:15:8
|
||||
|
|
||||
LL | fn foo(f: isize, x: u8, ...);
|
||||
| ^^^
|
||||
|
@ -37,7 +37,7 @@ LL | foo(1, /* u8 */);
|
|||
| ~~~~~~~~~~~~~
|
||||
|
||||
error[E0308]: mismatched types
|
||||
--> $DIR/variadic-ffi-1.rs:23:56
|
||||
--> $DIR/variadic-ffi-1.rs:25:56
|
||||
|
|
||||
LL | let x: unsafe extern "C" fn(f: isize, x: u8) = foo;
|
||||
| ------------------------------------- ^^^ expected non-variadic fn, found variadic function
|
||||
|
@ -48,7 +48,7 @@ LL | let x: unsafe extern "C" fn(f: isize, x: u8) = foo;
|
|||
found fn item `unsafe extern "C" fn(_, _, ...) {foo}`
|
||||
|
||||
error[E0308]: mismatched types
|
||||
--> $DIR/variadic-ffi-1.rs:24:54
|
||||
--> $DIR/variadic-ffi-1.rs:26:54
|
||||
|
|
||||
LL | let y: extern "C" fn(f: isize, x: u8, ...) = bar;
|
||||
| ----------------------------------- ^^^ expected variadic fn, found non-variadic function
|
||||
|
@ -59,37 +59,37 @@ LL | let y: extern "C" fn(f: isize, x: u8, ...) = bar;
|
|||
found fn item `extern "C" fn(_, _) {bar}`
|
||||
|
||||
error[E0617]: can't pass `f32` to variadic function
|
||||
--> $DIR/variadic-ffi-1.rs:26:19
|
||||
--> $DIR/variadic-ffi-1.rs:28:19
|
||||
|
|
||||
LL | foo(1, 2, 3f32);
|
||||
| ^^^^ help: cast the value to `c_double`: `3f32 as c_double`
|
||||
|
||||
error[E0617]: can't pass `bool` to variadic function
|
||||
--> $DIR/variadic-ffi-1.rs:27:19
|
||||
--> $DIR/variadic-ffi-1.rs:29:19
|
||||
|
|
||||
LL | foo(1, 2, true);
|
||||
| ^^^^ help: cast the value to `c_int`: `true as c_int`
|
||||
|
||||
error[E0617]: can't pass `i8` to variadic function
|
||||
--> $DIR/variadic-ffi-1.rs:28:19
|
||||
--> $DIR/variadic-ffi-1.rs:30:19
|
||||
|
|
||||
LL | foo(1, 2, 1i8);
|
||||
| ^^^ help: cast the value to `c_int`: `1i8 as c_int`
|
||||
|
||||
error[E0617]: can't pass `u8` to variadic function
|
||||
--> $DIR/variadic-ffi-1.rs:29:19
|
||||
--> $DIR/variadic-ffi-1.rs:31:19
|
||||
|
|
||||
LL | foo(1, 2, 1u8);
|
||||
| ^^^ help: cast the value to `c_uint`: `1u8 as c_uint`
|
||||
|
||||
error[E0617]: can't pass `i16` to variadic function
|
||||
--> $DIR/variadic-ffi-1.rs:30:19
|
||||
--> $DIR/variadic-ffi-1.rs:32:19
|
||||
|
|
||||
LL | foo(1, 2, 1i16);
|
||||
| ^^^^ help: cast the value to `c_int`: `1i16 as c_int`
|
||||
|
||||
error[E0617]: can't pass `u16` to variadic function
|
||||
--> $DIR/variadic-ffi-1.rs:31:19
|
||||
--> $DIR/variadic-ffi-1.rs:33:19
|
||||
|
|
||||
LL | foo(1, 2, 1u16);
|
||||
| ^^^^ help: cast the value to `c_uint`: `1u16 as c_uint`
|
||||
|
|
|
@ -1,7 +1,20 @@
|
|||
// ignore-arm stdcall isn't supported
|
||||
#![feature(extended_varargs_abi_support)]
|
||||
#![feature(abi_efiapi)]
|
||||
|
||||
fn baz(f: extern "stdcall" fn(usize, ...)) {
|
||||
//~^ ERROR: variadic function must have C or cdecl calling convention
|
||||
//~^ ERROR: C-variadic function must have a compatible calling convention,
|
||||
// like C, cdecl, win64, sysv64 or efiapi
|
||||
f(22, 44);
|
||||
}
|
||||
|
||||
fn sysv(f: extern "sysv64" fn(usize, ...)) {
|
||||
f(22, 44);
|
||||
}
|
||||
fn win(f: extern "win64" fn(usize, ...)) {
|
||||
f(22, 44);
|
||||
}
|
||||
fn efiapi(f: extern "efiapi" fn(usize, ...)) {
|
||||
f(22, 44);
|
||||
}
|
||||
|
||||
|
|
|
@ -1,8 +1,8 @@
|
|||
error[E0045]: C-variadic function must have C or cdecl calling convention
|
||||
--> $DIR/variadic-ffi-2.rs:3:11
|
||||
error[E0045]: C-variadic function must have a compatible calling convention, like `C`, `cdecl`, `win64`, `sysv64` or `efiapi`
|
||||
--> $DIR/variadic-ffi-2.rs:5:11
|
||||
|
|
||||
LL | fn baz(f: extern "stdcall" fn(usize, ...)) {
|
||||
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ C-variadics require C or cdecl calling convention
|
||||
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ C-variadic function must have a compatible calling convention
|
||||
|
||||
error: aborting due to previous error
|
||||
|
||||
|
|
|
@ -1,8 +1,8 @@
|
|||
error[E0045]: C-variadic function must have C or cdecl calling convention
|
||||
error[E0045]: C-variadic function must have a compatible calling convention, like `C` or `cdecl`
|
||||
--> $DIR/E0045.rs:1:17
|
||||
|
|
||||
LL | extern "Rust" { fn foo(x: u8, ...); }
|
||||
| ^^^^^^^^^^^^^^^^^^^ C-variadics require C or cdecl calling convention
|
||||
| ^^^^^^^^^^^^^^^^^^^ C-variadic function must have a compatible calling convention
|
||||
|
||||
error: aborting due to previous error
|
||||
|
||||
|
|
Loading…
Add table
Reference in a new issue