Skip to content

Commit

Permalink
Parse unsafe attributes
Browse files Browse the repository at this point in the history
  • Loading branch information
Coekjan committed Oct 27, 2024
1 parent 3ed9434 commit 73ce88c
Show file tree
Hide file tree
Showing 17 changed files with 105 additions and 10 deletions.
4 changes: 2 additions & 2 deletions Cargo.lock

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

72 changes: 65 additions & 7 deletions src/bindgen/utilities.rs
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@

#![allow(clippy::redundant_closure_call)]

use syn::ext::IdentExt;
use syn::{ext::IdentExt, parse::Parser};

pub trait IterHelpers: Iterator {
fn try_skip_map<F, T, E>(&mut self, f: F) -> Result<Vec<T>, E>
Expand Down Expand Up @@ -38,12 +38,10 @@ impl SynItemHelpers for syn::ItemFn {
fn exported_name(&self) -> Option<String> {
self.attrs
.attr_name_value_lookup("export_name")
.or_else(|| self.unsafe_attr_name_value_lookup("export_name"))
.or_else(|| {
if self.is_no_mangle() {
Some(self.sig.ident.unraw().to_string())
} else {
None
}
self.is_no_mangle()
.then(|| self.sig.ident.unraw().to_string())
})
}
}
Expand Down Expand Up @@ -150,6 +148,29 @@ pub trait SynAttributeHelpers {
})
}

/// Searches for attributes like `#[unsafe(test)]`.
/// Example:
/// - `item.has_unsafe_attr_word("test")` => `#[unsafe(test)]`
fn has_unsafe_attr_word(&self, name: &str) -> bool {
self.attrs().iter().filter_map(|attr| {
match &attr.meta {
syn::Meta::List(list) if list.path.is_ident("unsafe") => Some(list.tokens.clone()),
_ => None,
}
}).any(|tokens| {
let parser = syn::punctuated::Punctuated::<proc_macro2::TokenStream, syn::Token![,]>::parse_terminated;
let Ok(args) = parser.parse2(tokens) else {
return false;
};
args.into_iter().any(|arg| {
match syn::parse2::<syn::Path>(arg) {
Ok(path) => path.is_ident(name),
Err(_) => false,
}
})
})
}

fn find_deprecated_note(&self) -> Option<String> {
let attrs = self.attrs();
// #[deprecated = ""]
Expand Down Expand Up @@ -194,7 +215,7 @@ pub trait SynAttributeHelpers {
}

fn is_no_mangle(&self) -> bool {
self.has_attr_word("no_mangle")
self.has_attr_word("no_mangle") || self.has_unsafe_attr_word("no_mangle")
}

/// Sees whether we should skip parsing a given item.
Expand Down Expand Up @@ -231,6 +252,43 @@ pub trait SynAttributeHelpers {
.next()
}

fn unsafe_attr_name_value_lookup(&self, name: &str) -> Option<String> {
self.attrs()
.iter()
.filter_map(|attr| {
let syn::Meta::List(syn::MetaList { path, tokens, .. }) = &attr.meta else {
return None;
};
if path.is_ident("unsafe") {
let parser = syn::punctuated::Punctuated::<
proc_macro2::TokenStream,
syn::Token![,],
>::parse_terminated;
let Ok(args) = parser.parse2(tokens.clone()) else {
return None;
};
for arg in args {
match syn::parse2::<syn::MetaNameValue>(arg) {
Ok(syn::MetaNameValue {
path,
value:
syn::Expr::Lit(syn::ExprLit {
lit: syn::Lit::Str(lit),
..
}),
..
}) if path.is_ident(name) => {
return Some(lit.value());
}
_ => {}
}
}
}
None
})
.next()
}

fn get_comment_lines(&self) -> Vec<String> {
let mut comment = Vec::new();

Expand Down
2 changes: 2 additions & 0 deletions tests/expectations/export_name.c
Original file line number Diff line number Diff line change
Expand Up @@ -4,3 +4,5 @@
#include <stdlib.h>

void do_the_thing_with_export_name(void);

void do_the_thing_with_unsafe_export_name(void);
2 changes: 2 additions & 0 deletions tests/expectations/export_name.compat.c
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,8 @@ extern "C" {

void do_the_thing_with_export_name(void);

void do_the_thing_with_unsafe_export_name(void);

#ifdef __cplusplus
} // extern "C"
#endif // __cplusplus
2 changes: 2 additions & 0 deletions tests/expectations/export_name.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -8,4 +8,6 @@ extern "C" {

void do_the_thing_with_export_name();

void do_the_thing_with_unsafe_export_name();

} // extern "C"
2 changes: 2 additions & 0 deletions tests/expectations/export_name.pyx
Original file line number Diff line number Diff line change
Expand Up @@ -7,3 +7,5 @@ cdef extern from *:
cdef extern from *:

void do_the_thing_with_export_name();

void do_the_thing_with_unsafe_export_name();
2 changes: 2 additions & 0 deletions tests/expectations/mangle.c
Original file line number Diff line number Diff line change
Expand Up @@ -15,3 +15,5 @@ typedef struct {
typedef FooU8 Boo;

void root(Boo x, Bar y);

void unsafe_root(Boo x, Bar y);
2 changes: 2 additions & 0 deletions tests/expectations/mangle.compat.c
Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,8 @@ extern "C" {

void root(Boo x, Bar y);

void unsafe_root(Boo x, Bar y);

#ifdef __cplusplus
} // extern "C"
#endif // __cplusplus
2 changes: 2 additions & 0 deletions tests/expectations/mangle.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -20,4 +20,6 @@ extern "C" {

void root(Boo x, Bar y);

void unsafe_root(Boo x, Bar y);

} // extern "C"
2 changes: 2 additions & 0 deletions tests/expectations/mangle.pyx
Original file line number Diff line number Diff line change
Expand Up @@ -16,3 +16,5 @@ cdef extern from *:
ctypedef FooU8 Boo;

void root(Boo x, Bar y);

void unsafe_root(Boo x, Bar y);
2 changes: 2 additions & 0 deletions tests/expectations/mangle_both.c
Original file line number Diff line number Diff line change
Expand Up @@ -15,3 +15,5 @@ typedef struct FooU8 {
typedef struct FooU8 Boo;

void root(Boo x, enum Bar y);

void unsafe_root(Boo x, enum Bar y);
2 changes: 2 additions & 0 deletions tests/expectations/mangle_both.compat.c
Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,8 @@ extern "C" {

void root(Boo x, enum Bar y);

void unsafe_root(Boo x, enum Bar y);

#ifdef __cplusplus
} // extern "C"
#endif // __cplusplus
2 changes: 2 additions & 0 deletions tests/expectations/mangle_tag.c
Original file line number Diff line number Diff line change
Expand Up @@ -15,3 +15,5 @@ struct FooU8 {
typedef struct FooU8 Boo;

void root(Boo x, enum Bar y);

void unsafe_root(Boo x, enum Bar y);
2 changes: 2 additions & 0 deletions tests/expectations/mangle_tag.compat.c
Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,8 @@ extern "C" {

void root(Boo x, enum Bar y);

void unsafe_root(Boo x, enum Bar y);

#ifdef __cplusplus
} // extern "C"
#endif // __cplusplus
2 changes: 2 additions & 0 deletions tests/expectations/mangle_tag.pyx
Original file line number Diff line number Diff line change
Expand Up @@ -16,3 +16,5 @@ cdef extern from *:
ctypedef FooU8 Boo;

void root(Boo x, Bar y);

void unsafe_root(Boo x, Bar y);
7 changes: 6 additions & 1 deletion tests/rust/export_name.rs
Original file line number Diff line number Diff line change
@@ -1,4 +1,9 @@
#[export_name = "do_the_thing_with_export_name"]
pub extern "C" fn do_the_thing() {
println!("doing the thing!");
}
}

#[unsafe(export_name = "do_the_thing_with_unsafe_export_name")]
pub extern "C" fn unsafe_do_the_thing() {
println!("doing the thing!");
}
6 changes: 6 additions & 0 deletions tests/rust/mangle.rs
Original file line number Diff line number Diff line change
Expand Up @@ -17,3 +17,9 @@ pub extern "C" fn root(
x: Boo,
y: Bar,
) { }

#[unsafe(no_mangle)]
pub extern "C" fn unsafe_root(
x: Boo,
y: Bar,
) { }

0 comments on commit 73ce88c

Please sign in to comment.