Skip to content
Merged
Show file tree
Hide file tree
Changes from 4 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
12 changes: 10 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,11 @@ 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 +33,7 @@ impl Fn {
library: library.to_string(),
params,
return_type,
extern_c,
})
}

Expand All @@ -53,9 +55,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;
})
}
}
17 changes: 16 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,22 @@ 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