Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
4 changes: 4 additions & 0 deletions crates/libs/rdl/src/clang/cx.rs
Original file line number Diff line number Diff line change
Expand Up @@ -289,6 +289,10 @@ impl Cursor {
pub fn result_type(&self) -> Type {
Type(unsafe { clang_getCursorResultType(self.0) })
}

pub fn language(&self) -> CXLanguageKind {
unsafe { clang_getCursorLanguage(self.0) }
}
}

pub struct Type(CXType);
Expand Down
17 changes: 15 additions & 2 deletions crates/libs/rdl/src/clang/fn.rs
Original file line number Diff line number Diff line change
Expand Up @@ -7,10 +7,16 @@ pub struct Fn {
pub library: String,
pub params: Vec<Param>,
pub return_type: metadata::Type,
pub extern_c: bool,
}

impl Fn {
pub fn parse(cursor: Cursor, namespace: &str, library: &str) -> Result<Self, Error> {
pub fn parse(
cursor: Cursor,
namespace: &str,
library: &str,
extern_c: bool,
) -> Result<Self, Error> {
let name = cursor.name();
let return_type = cursor.result_type().to_type(namespace);

Expand All @@ -32,6 +38,7 @@ impl Fn {
library: library.to_string(),
params,
return_type,
extern_c,
})
}

Expand All @@ -53,9 +60,15 @@ impl Fn {
}
};

let abi = if self.extern_c {
quote! { "C" }
} else {
quote! {}
};

Ok(quote! {
#[library(#library)]
extern fn #name(#(#params),*) #return_type;
extern #abi fn #name(#(#params),*) #return_type;
})
}
}
27 changes: 26 additions & 1 deletion crates/libs/rdl/src/clang/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -203,7 +203,32 @@ impl Clang {
}
}
CXCursor_FunctionDecl if !child.is_definition() => {
collector.insert(Item::Fn(Fn::parse(child, &self.namespace, &self.library)?));
collector.insert(Item::Fn(Fn::parse(
child,
&self.namespace,
&self.library,
false,
)?));
}
// Recurse into `extern "C" { }` or `extern "C++" { }` blocks so
// that function declarations inside them are collected with the
// correct ABI annotation.
CXCursor_LinkageSpec => {
for inner in child.children() {
if !inner.is_from_main_file() {
continue;
}
if inner.kind() == CXCursor_FunctionDecl && !inner.is_definition() {
// A function inside `extern "C" { }` has C language linkage.
let extern_c = inner.language() == CXLanguage_C;
collector.insert(Item::Fn(Fn::parse(
inner,
&self.namespace,
&self.library,
extern_c,
)?));
}
}
}
CXCursor_MacroDefinition => {
if let Some(c) = Const::parse(child, &self.namespace, tu)? {
Expand Down
5 changes: 5 additions & 0 deletions crates/tests/libs/clang/roundtrip/fn_extern_c.h
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
extern "C"
{
unsigned int GetTickCount();
void SetLastErrorEx(unsigned a, signed b);
}
7 changes: 7 additions & 0 deletions crates/tests/libs/clang/roundtrip/fn_extern_c.rdl
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
#[win32]
mod Test {
#[library("test.dll")]
extern "C" fn GetTickCount() -> u32;
#[library("test.dll")]
extern "C" fn SetLastErrorEx(a: u32, b: i32);
}
Loading