Skip to content

Commit 89b54c0

Browse files
committed
Add the --override-abi option.
This option can be used from the CLI with the <abi>:<regex> syntax and it overrides the ABI of a function if it matches <regex>. Fixes rust-lang#2257 as the `".*"` regex can be used to match every function.
1 parent a2fe04c commit 89b54c0

File tree

7 files changed

+189
-79
lines changed

7 files changed

+189
-79
lines changed

bindgen-cli/options.rs

+15
Original file line numberDiff line numberDiff line change
@@ -568,6 +568,12 @@ where
568568
Arg::new("merge-extern-blocks")
569569
.long("merge-extern-blocks")
570570
.help("Deduplicates extern blocks."),
571+
Arg::new("override-abi")
572+
.long("override-abi")
573+
.help("Overrides the ABI of functions matching <regex>. The <override> value must be of the shape <abi>:<regex> where <abi> can be one of C, stdcall, fastcall, thiscall, aapcs or win64.")
574+
.value_name("override")
575+
.multiple_occurrences(true)
576+
.number_of_values(1),
571577
Arg::new("V")
572578
.long("version")
573579
.help("Prints the version, and exits"),
@@ -1088,5 +1094,14 @@ where
10881094
builder = builder.merge_extern_blocks(true);
10891095
}
10901096

1097+
if let Some(abi_overrides) = matches.values_of("override-abi") {
1098+
for abi_override in abi_overrides {
1099+
let (abi_str, regex) =
1100+
abi_override.split_once(":").expect("Invalid ABI override");
1101+
let abi = abi_str.parse().unwrap();
1102+
builder = builder.override_abi(abi, regex);
1103+
}
1104+
}
1105+
10911106
Ok((builder, output, verbose))
10921107
}

bindgen-tests/tests/expectations/tests/abi-override.rs

+16
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,5 @@
1+
// bindgen-flags: --override-abi=fastcall:foo --override-abi=aapcs:bar
2+
3+
void foo();
4+
void bar();
5+
void baz();

bindgen/codegen/dyngen.rs

+3-3
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
use crate::codegen;
2-
use crate::ir::function::Abi;
2+
use crate::ir::function::ClangAbi;
33
use proc_macro2::Ident;
44

55
/// Used to build the output tokens for dynamic bindings.
@@ -113,10 +113,10 @@ impl DynamicItems {
113113
}
114114

115115
#[allow(clippy::too_many_arguments)]
116-
pub fn push(
116+
pub(crate) fn push(
117117
&mut self,
118118
ident: Ident,
119-
abi: Abi,
119+
abi: ClangAbi,
120120
is_variadic: bool,
121121
is_required: bool,
122122
args: Vec<proc_macro2::TokenStream>,

bindgen/codegen/mod.rs

+32-21
Original file line numberDiff line numberDiff line change
@@ -32,7 +32,9 @@ use crate::ir::derive::{
3232
};
3333
use crate::ir::dot;
3434
use crate::ir::enum_ty::{Enum, EnumVariant, EnumVariantValue};
35-
use crate::ir::function::{Abi, Function, FunctionKind, FunctionSig, Linkage};
35+
use crate::ir::function::{
36+
Abi, ClangAbi, Function, FunctionKind, FunctionSig, Linkage,
37+
};
3638
use crate::ir::int::IntKind;
3739
use crate::ir::item::{IsOpaque, Item, ItemCanonicalName, ItemCanonicalPath};
3840
use crate::ir::item_kind::ItemKind;
@@ -2475,9 +2477,13 @@ impl MethodCodegen for Method {
24752477
_ => panic!("How in the world?"),
24762478
};
24772479

2478-
let supported_abi = match signature.abi() {
2479-
Abi::ThisCall => ctx.options().rust_features().thiscall_abi,
2480-
Abi::Vectorcall => ctx.options().rust_features().vectorcall_abi,
2480+
let supported_abi = match signature.abi(ctx, Some(&*name)) {
2481+
ClangAbi::Known(Abi::ThisCall) => {
2482+
ctx.options().rust_features().thiscall_abi
2483+
}
2484+
ClangAbi::Known(Abi::Vectorcall) => {
2485+
ctx.options().rust_features().vectorcall_abi
2486+
}
24812487
_ => true,
24822488
};
24832489

@@ -3791,7 +3797,8 @@ impl TryToRustTy for Type {
37913797
// sizeof(NonZero<_>) optimization with opaque blobs (because
37923798
// they aren't NonZero), so don't *ever* use an or_opaque
37933799
// variant here.
3794-
let ty = fs.try_to_rust_ty(ctx, &())?;
3800+
let ty = fs
3801+
.try_to_rust_ty(ctx, &self.name().map(|x| x.to_string()))?;
37953802

37963803
let prefix = ctx.trait_prefix();
37973804
Ok(quote! {
@@ -3981,24 +3988,26 @@ impl TryToRustTy for TemplateInstantiation {
39813988
}
39823989

39833990
impl TryToRustTy for FunctionSig {
3984-
type Extra = ();
3991+
type Extra = Option<String>;
39853992

39863993
fn try_to_rust_ty(
39873994
&self,
39883995
ctx: &BindgenContext,
3989-
_: &(),
3996+
name: &Option<String>,
39903997
) -> error::Result<proc_macro2::TokenStream> {
39913998
// TODO: we might want to consider ignoring the reference return value.
39923999
let ret = utils::fnsig_return_ty(ctx, self);
39934000
let arguments = utils::fnsig_arguments(ctx, self);
3994-
let abi = self.abi();
4001+
let abi = self.abi(ctx, name.as_deref());
39954002

39964003
match abi {
3997-
Abi::ThisCall if !ctx.options().rust_features().thiscall_abi => {
4004+
ClangAbi::Known(Abi::ThisCall)
4005+
if !ctx.options().rust_features().thiscall_abi =>
4006+
{
39984007
warn!("Skipping function with thiscall ABI that isn't supported by the configured Rust target");
39994008
Ok(proc_macro2::TokenStream::new())
40004009
}
4001-
Abi::Vectorcall
4010+
ClangAbi::Known(Abi::Vectorcall)
40024011
if !ctx.options().rust_features().vectorcall_abi =>
40034012
{
40044013
warn!("Skipping function with vectorcall ABI that isn't supported by the configured Rust target");
@@ -4102,22 +4111,24 @@ impl CodeGenerator for Function {
41024111
attributes.push(attributes::doc(comment));
41034112
}
41044113

4105-
let abi = match signature.abi() {
4106-
Abi::ThisCall if !ctx.options().rust_features().thiscall_abi => {
4114+
let abi = match signature.abi(ctx, Some(name)) {
4115+
ClangAbi::Known(Abi::ThisCall)
4116+
if !ctx.options().rust_features().thiscall_abi =>
4117+
{
41074118
warn!("Skipping function with thiscall ABI that isn't supported by the configured Rust target");
41084119
return None;
41094120
}
4110-
Abi::Vectorcall
4121+
ClangAbi::Known(Abi::Vectorcall)
41114122
if !ctx.options().rust_features().vectorcall_abi =>
41124123
{
41134124
warn!("Skipping function with vectorcall ABI that isn't supported by the configured Rust target");
41144125
return None;
41154126
}
4116-
Abi::Win64 if signature.is_variadic() => {
4127+
ClangAbi::Known(Abi::Win64) if signature.is_variadic() => {
41174128
warn!("Skipping variadic function with Win64 ABI that isn't supported");
41184129
return None;
41194130
}
4120-
Abi::Unknown(unknown_abi) => {
4131+
ClangAbi::Unknown(unknown_abi) => {
41214132
panic!(
41224133
"Invalid or unknown abi {:?} for function {:?} ({:?})",
41234134
unknown_abi, canonical_name, self
@@ -4515,7 +4526,7 @@ pub(crate) fn codegen(
45154526
pub mod utils {
45164527
use super::{error, ToRustTyOrOpaque};
45174528
use crate::ir::context::BindgenContext;
4518-
use crate::ir::function::{Abi, FunctionSig};
4529+
use crate::ir::function::{Abi, ClangAbi, FunctionSig};
45194530
use crate::ir::item::{Item, ItemCanonicalPath};
45204531
use crate::ir::ty::TypeKind;
45214532
use proc_macro2;
@@ -4976,10 +4987,10 @@ pub mod utils {
49764987
// Returns true if `canonical_name` will end up as `mangled_name` at the
49774988
// machine code level, i.e. after LLVM has applied any target specific
49784989
// mangling.
4979-
pub fn names_will_be_identical_after_mangling(
4990+
pub(crate) fn names_will_be_identical_after_mangling(
49804991
canonical_name: &str,
49814992
mangled_name: &str,
4982-
call_conv: Option<Abi>,
4993+
call_conv: Option<ClangAbi>,
49834994
) -> bool {
49844995
// If the mangled name and the canonical name are the same then no
49854996
// mangling can have happened between the two versions.
@@ -4992,13 +5003,13 @@ pub mod utils {
49925003
let mangled_name = mangled_name.as_bytes();
49935004

49945005
let (mangling_prefix, expect_suffix) = match call_conv {
4995-
Some(Abi::C) |
5006+
Some(ClangAbi::Known(Abi::C)) |
49965007
// None is the case for global variables
49975008
None => {
49985009
(b'_', false)
49995010
}
5000-
Some(Abi::Stdcall) => (b'_', true),
5001-
Some(Abi::Fastcall) => (b'@', true),
5011+
Some(ClangAbi::Known(Abi::Stdcall)) => (b'_', true),
5012+
Some(ClangAbi::Known(Abi::Fastcall)) => (b'@', true),
50025013

50035014
// This is something we don't recognize, stay on the safe side
50045015
// by emitting the `#[link_name]` attribute

0 commit comments

Comments
 (0)