From 5c91efe7291b30b1f3aaaa183e00dcbed6f4550b Mon Sep 17 00:00:00 2001 From: VKachemtsev Date: Fri, 12 Jun 2020 04:01:50 +0700 Subject: [PATCH 1/6] Allow function aliases --- demo-cxx/demo.cc | 4 ++++ demo-cxx/demo.h | 3 +++ demo-rs/src/main.rs | 9 ++++++++- macro/src/expand.rs | 1 + syntax/attrs.rs | 14 +++++++++++++- syntax/mod.rs | 1 + syntax/parse.rs | 5 +++++ 7 files changed, 35 insertions(+), 2 deletions(-) diff --git a/demo-cxx/demo.cc b/demo-cxx/demo.cc index 21bdad43b..c8efa7535 100644 --- a/demo-cxx/demo.cc +++ b/demo-cxx/demo.cc @@ -9,10 +9,14 @@ ThingC::ThingC(std::string appname) : appname(std::move(appname)) {} ThingC::~ThingC() { std::cout << "done with ThingC" << std::endl; } +void ThingC::camelCaseMethod() const { std::cout << "camelCaseMethod" << std::endl; } + std::unique_ptr make_demo(rust::Str appname) { return std::make_unique(std::string(appname)); } +void camelCaseFunction() { std::cout << "camelCaseFunction" << std::endl; } + const std::string &get_name(const ThingC &thing) { return thing.appname; } void do_thing(SharedThing state) { print_r(*state.y); } diff --git a/demo-cxx/demo.h b/demo-cxx/demo.h index fafc4743a..5a651aee7 100644 --- a/demo-cxx/demo.h +++ b/demo-cxx/demo.h @@ -11,11 +11,14 @@ class ThingC { ThingC(std::string appname); ~ThingC(); + void camelCaseMethod() const; + std::string appname; }; struct SharedThing; +void camelCaseFunction(); std::unique_ptr make_demo(rust::Str appname); const std::string &get_name(const ThingC &thing); void do_thing(SharedThing state); diff --git a/demo-rs/src/main.rs b/demo-rs/src/main.rs index 66dfc7997..e65d9b8d7 100644 --- a/demo-rs/src/main.rs +++ b/demo-rs/src/main.rs @@ -10,6 +10,10 @@ mod ffi { include!("demo-cxx/demo.h"); type ThingC; + #[alias(snake_case_method)] + fn camelCaseMethod(&self); + #[alias(snake_case_function)] + fn camelCaseFunction(); fn make_demo(appname: &str) -> UniquePtr; fn get_name(thing: &ThingC) -> &CxxString; fn do_thing(state: SharedThing); @@ -30,7 +34,10 @@ fn print_r(r: &ThingR) { fn main() { let x = ffi::make_demo("demo of cxx::bridge"); println!("this is a {}", ffi::get_name(x.as_ref().unwrap())); - + + x.snake_case_method(); + ffi::snake_case_function(); + ffi::do_thing(ffi::SharedThing { z: 222, y: Box::new(ThingR(333)), diff --git a/macro/src/expand.rs b/macro/src/expand.rs index f28d955f1..11822dace 100644 --- a/macro/src/expand.rs +++ b/macro/src/expand.rs @@ -362,6 +362,7 @@ fn expand_cxx_function_shim(namespace: &Namespace, efn: &ExternFn, types: &Types }) } .unwrap_or(call); + let ident = if let Some(alias) = &efn.alias { alias } else { ident }; let function_shim = quote! { #doc pub fn #ident(#(#all_args,)*) #ret { diff --git a/syntax/attrs.rs b/syntax/attrs.rs index 4c76641cc..6c9d7811b 100644 --- a/syntax/attrs.rs +++ b/syntax/attrs.rs @@ -10,6 +10,7 @@ pub struct Parser<'a> { pub doc: Option<&'a mut Doc>, pub derives: Option<&'a mut Vec>, pub repr: Option<&'a mut Option>, + pub alias: Option<&'a mut Option>, } pub(super) fn parse_doc(cx: &mut Errors, attrs: &[Attribute]) -> Doc { @@ -57,8 +58,19 @@ pub(super) fn parse(cx: &mut Errors, attrs: &[Attribute], mut parser: Parser) { } Err(err) => return cx.push(err), } + } else if attr.path.is_ident("alias") { + match attr.parse_args_with(|input: ParseStream| input.parse()) { + Ok(alias) => { + if let Some(a) = &mut parser.alias { + **a = Some(alias); + continue; + } + } + Err(err) => return cx.push(err), + } + } else { + return cx.error(attr, "unsupported attribute"); } - return cx.error(attr, "unsupported attribute"); } } diff --git a/syntax/mod.rs b/syntax/mod.rs index 88c96e8cf..fff8311d0 100644 --- a/syntax/mod.rs +++ b/syntax/mod.rs @@ -70,6 +70,7 @@ pub struct ExternFn { pub lang: Lang, pub doc: Doc, pub ident: Ident, + pub alias: Option, pub sig: Signature, pub semi_token: Token![;], } diff --git a/syntax/parse.rs b/syntax/parse.rs index a1d31cfa7..9af565ff1 100644 --- a/syntax/parse.rs +++ b/syntax/parse.rs @@ -327,6 +327,10 @@ fn parse_extern_fn(cx: &mut Errors, foreign_fn: &ForeignItemFn, lang: Lang) -> R let doc = attrs::parse_doc(cx, &foreign_fn.attrs); let fn_token = foreign_fn.sig.fn_token; let ident = foreign_fn.sig.ident.clone(); + let mut alias = None; + if let Lang::Cxx = lang { + attrs::parse(cx, &foreign_fn.attrs, attrs::Parser { alias: Some(&mut alias), ..Default::default() }); + } let paren_token = foreign_fn.sig.paren_token; let semi_token = foreign_fn.semi_token; let api_function = match lang { @@ -338,6 +342,7 @@ fn parse_extern_fn(cx: &mut Errors, foreign_fn: &ForeignItemFn, lang: Lang) -> R lang, doc, ident, + alias, sig: Signature { fn_token, receiver, From 8f7891cd8194e100a7baabfbe18124c0ff0b5818 Mon Sep 17 00:00:00 2001 From: VKachemtsev Date: Sat, 13 Jun 2020 01:01:33 +0700 Subject: [PATCH 2/6] Function overloading --- demo-cxx/demo.cc | 4 ++++ demo-cxx/demo.h | 4 ++++ demo-rs/src/main.rs | 12 ++++++++++++ gen/src/write.rs | 14 ++++++++------ macro/src/expand.rs | 8 ++++---- syntax/ident.rs | 3 ++- syntax/mangle.rs | 5 +++-- syntax/types.rs | 2 +- 8 files changed, 38 insertions(+), 14 deletions(-) diff --git a/demo-cxx/demo.cc b/demo-cxx/demo.cc index c8efa7535..0735abe4c 100644 --- a/demo-cxx/demo.cc +++ b/demo-cxx/demo.cc @@ -10,12 +10,16 @@ ThingC::ThingC(std::string appname) : appname(std::move(appname)) {} ThingC::~ThingC() { std::cout << "done with ThingC" << std::endl; } void ThingC::camelCaseMethod() const { std::cout << "camelCaseMethod" << std::endl; } +void ThingC::overloadedMethod(int x) const { std::cout << "overloadedMethod: int x = " << x << std::endl; } +void ThingC::overloadedMethod(float x) const { std::cout << "overloadedMethod: float x = " << x << std::endl; } std::unique_ptr make_demo(rust::Str appname) { return std::make_unique(std::string(appname)); } void camelCaseFunction() { std::cout << "camelCaseFunction" << std::endl; } +void overloadedFunction(int x) { std::cout << "overloadedFunction: int x = " << x << std::endl; } +void overloadedFunction(float x) { std::cout << "overloadedFunction: float x = " << x << std::endl; } const std::string &get_name(const ThingC &thing) { return thing.appname; } diff --git a/demo-cxx/demo.h b/demo-cxx/demo.h index 5a651aee7..c65e0bd83 100644 --- a/demo-cxx/demo.h +++ b/demo-cxx/demo.h @@ -12,6 +12,8 @@ class ThingC { ~ThingC(); void camelCaseMethod() const; + void overloadedMethod(int x) const; + void overloadedMethod(float x) const; std::string appname; }; @@ -19,6 +21,8 @@ class ThingC { struct SharedThing; void camelCaseFunction(); +void overloadedFunction(int x); +void overloadedFunction(float x); std::unique_ptr make_demo(rust::Str appname); const std::string &get_name(const ThingC &thing); void do_thing(SharedThing state); diff --git a/demo-rs/src/main.rs b/demo-rs/src/main.rs index e65d9b8d7..28475859d 100644 --- a/demo-rs/src/main.rs +++ b/demo-rs/src/main.rs @@ -14,6 +14,14 @@ mod ffi { fn camelCaseMethod(&self); #[alias(snake_case_function)] fn camelCaseFunction(); + #[alias(i32_method)] + fn overloadedMethod(&self, x: i32); + #[alias(f32_method)] + fn overloadedMethod(&self, x: f32); + #[alias(i32_function)] + fn overloadedFunction(x: i32); + #[alias(f32_function)] + fn overloadedFunction(x: f32); fn make_demo(appname: &str) -> UniquePtr; fn get_name(thing: &ThingC) -> &CxxString; fn do_thing(state: SharedThing); @@ -37,6 +45,10 @@ fn main() { x.snake_case_method(); ffi::snake_case_function(); + x.i32_method(10); + x.f32_method(10.5); + ffi::i32_function(10); + ffi::f32_function(10.5); ffi::do_thing(ffi::SharedThing { z: 222, diff --git a/gen/src/write.rs b/gen/src/write.rs index 2cf9faf6e..9405c5ed5 100644 --- a/gen/src/write.rs +++ b/gen/src/write.rs @@ -433,9 +433,10 @@ fn write_cxx_function_shim(out: &mut OutFile, efn: &ExternFn, types: &Types) { writeln!(out, ") noexcept {{"); write!(out, " "); write_return_type(out, &efn.ret); + let ident = if let Some(alias) = &efn.alias { alias } else { &efn.ident }; match &efn.receiver { - None => write!(out, "(*{}$)(", efn.ident), - Some(receiver) => write!(out, "({}::*{}$)(", receiver.ty, efn.ident), + None => write!(out, "(*{}$)(", ident), + Some(receiver) => write!(out, "({}::*{}$)(", receiver.ty, ident), } for (i, arg) in efn.args.iter().enumerate() { if i > 0 { @@ -478,8 +479,8 @@ fn write_cxx_function_shim(out: &mut OutFile, efn: &ExternFn, types: &Types) { _ => {} } match &efn.receiver { - None => write!(out, "{}$(", efn.ident), - Some(_) => write!(out, "(self.*{}$)(", efn.ident), + None => write!(out, "{}$(", ident), + Some(_) => write!(out, "(self.*{}$)(", ident), } for (i, arg) in efn.args.iter().enumerate() { if i > 0 { @@ -612,9 +613,10 @@ fn write_rust_function_shim(out: &mut OutFile, efn: &ExternFn, types: &Types) { for line in efn.doc.to_string().lines() { writeln!(out, "//{}", line); } + let ident = if let Some(alias) = &efn.alias { alias } else { &efn.ident }; let local_name = match &efn.sig.receiver { - None => efn.ident.to_string(), - Some(receiver) => format!("{}::{}", receiver.ty, efn.ident), + None => ident.to_string(), + Some(receiver) => format!("{}::{}", receiver.ty, ident), }; let invoke = mangle::extern_fn(&out.namespace, efn); let indirect_call = false; diff --git a/macro/src/expand.rs b/macro/src/expand.rs index 11822dace..9405105e0 100644 --- a/macro/src/expand.rs +++ b/macro/src/expand.rs @@ -185,7 +185,7 @@ fn expand_cxx_type(namespace: &Namespace, ety: &ExternType) -> TokenStream { } fn expand_cxx_function_decl(namespace: &Namespace, efn: &ExternFn, types: &Types) -> TokenStream { - let ident = &efn.ident; + let ident = if let Some(alias) = &efn.alias { alias } else { &efn.ident }; let receiver = efn.receiver.iter().map(|receiver| { let receiver_type = receiver.ty(); quote!(_: #receiver_type) @@ -225,7 +225,7 @@ fn expand_cxx_function_decl(namespace: &Namespace, efn: &ExternFn, types: &Types } fn expand_cxx_function_shim(namespace: &Namespace, efn: &ExternFn, types: &Types) -> TokenStream { - let ident = &efn.ident; + let ident = if let Some(alias) = &efn.alias { alias } else { &efn.ident }; let doc = &efn.doc; let decl = expand_cxx_function_decl(namespace, efn, types); let receiver = efn.receiver.iter().map(|receiver| { @@ -362,7 +362,6 @@ fn expand_cxx_function_shim(namespace: &Namespace, efn: &ExternFn, types: &Types }) } .unwrap_or(call); - let ident = if let Some(alias) = &efn.alias { alias } else { ident }; let function_shim = quote! { #doc pub fn #ident(#(#all_args,)*) #ret { @@ -395,7 +394,8 @@ fn expand_function_pointer_trampoline( let c_trampoline = mangle::c_trampoline(namespace, efn, var); let r_trampoline = mangle::r_trampoline(namespace, efn, var); let local_name = parse_quote!(__); - let catch_unwind_label = format!("::{}::{}", efn.ident, var); + let ident = if let Some(alias) = &efn.alias { alias } else { &efn.ident }; + let catch_unwind_label = format!("::{}::{}", ident, var); let shim = expand_rust_function_shim_impl( sig, types, diff --git a/syntax/ident.rs b/syntax/ident.rs index 7545e92ce..bd5632744 100644 --- a/syntax/ident.rs +++ b/syntax/ident.rs @@ -37,7 +37,8 @@ pub(crate) fn check_all(cx: &mut Check, namespace: &Namespace, apis: &[Api]) { check(cx, &ety.ident); } Api::CxxFunction(efn) | Api::RustFunction(efn) => { - check(cx, &efn.ident); + let ident = if let Some(alias) = &efn.alias { alias } else { &efn.ident }; + check(cx, ident); for arg in &efn.args { check(cx, &arg.ident); } diff --git a/syntax/mangle.rs b/syntax/mangle.rs index c9392dba1..9dc034cb4 100644 --- a/syntax/mangle.rs +++ b/syntax/mangle.rs @@ -12,9 +12,10 @@ macro_rules! join { } pub fn extern_fn(namespace: &Namespace, efn: &ExternFn) -> Symbol { + let ident = if let Some(alias) = &efn.alias { alias } else { &efn.ident }; match &efn.receiver { - Some(receiver) => join!(namespace, CXXBRIDGE, receiver.ty, efn.ident), - None => join!(namespace, CXXBRIDGE, efn.ident), + Some(receiver) => join!(namespace, CXXBRIDGE, receiver.ty, ident), + None => join!(namespace, CXXBRIDGE, ident), } } diff --git a/syntax/types.rs b/syntax/types.rs index ba9bc7890..e98bbe5f8 100644 --- a/syntax/types.rs +++ b/syntax/types.rs @@ -87,7 +87,7 @@ impl<'a> Types<'a> { rust.insert(ident); } Api::CxxFunction(efn) | Api::RustFunction(efn) => { - let ident = &efn.ident; + let ident = if let Some(alias) = &efn.alias { alias } else { &efn.ident }; if !function_names.insert((&efn.receiver, ident)) { duplicate_name(cx, efn, ident); } From f70508bb5f42071bb8c5e26b86733347d7ad999f Mon Sep 17 00:00:00 2001 From: VKachemtsev Date: Sat, 13 Jun 2020 03:04:16 +0700 Subject: [PATCH 3/6] rust_name function attribute --- demo-cxx/demo.cc | 8 -------- demo-cxx/demo.h | 7 ------- demo-rs/src/main.rs | 21 +-------------------- syntax/attrs.rs | 10 ++++++++-- tests/ffi/lib.rs | 9 +++++++++ tests/ffi/tests.cc | 16 ++++++++++++++++ tests/ffi/tests.h | 5 +++++ tests/test.rs | 9 +++++++++ 8 files changed, 48 insertions(+), 37 deletions(-) diff --git a/demo-cxx/demo.cc b/demo-cxx/demo.cc index 0735abe4c..21bdad43b 100644 --- a/demo-cxx/demo.cc +++ b/demo-cxx/demo.cc @@ -9,18 +9,10 @@ ThingC::ThingC(std::string appname) : appname(std::move(appname)) {} ThingC::~ThingC() { std::cout << "done with ThingC" << std::endl; } -void ThingC::camelCaseMethod() const { std::cout << "camelCaseMethod" << std::endl; } -void ThingC::overloadedMethod(int x) const { std::cout << "overloadedMethod: int x = " << x << std::endl; } -void ThingC::overloadedMethod(float x) const { std::cout << "overloadedMethod: float x = " << x << std::endl; } - std::unique_ptr make_demo(rust::Str appname) { return std::make_unique(std::string(appname)); } -void camelCaseFunction() { std::cout << "camelCaseFunction" << std::endl; } -void overloadedFunction(int x) { std::cout << "overloadedFunction: int x = " << x << std::endl; } -void overloadedFunction(float x) { std::cout << "overloadedFunction: float x = " << x << std::endl; } - const std::string &get_name(const ThingC &thing) { return thing.appname; } void do_thing(SharedThing state) { print_r(*state.y); } diff --git a/demo-cxx/demo.h b/demo-cxx/demo.h index c65e0bd83..fafc4743a 100644 --- a/demo-cxx/demo.h +++ b/demo-cxx/demo.h @@ -11,18 +11,11 @@ class ThingC { ThingC(std::string appname); ~ThingC(); - void camelCaseMethod() const; - void overloadedMethod(int x) const; - void overloadedMethod(float x) const; - std::string appname; }; struct SharedThing; -void camelCaseFunction(); -void overloadedFunction(int x); -void overloadedFunction(float x); std::unique_ptr make_demo(rust::Str appname); const std::string &get_name(const ThingC &thing); void do_thing(SharedThing state); diff --git a/demo-rs/src/main.rs b/demo-rs/src/main.rs index 28475859d..66dfc7997 100644 --- a/demo-rs/src/main.rs +++ b/demo-rs/src/main.rs @@ -10,18 +10,6 @@ mod ffi { include!("demo-cxx/demo.h"); type ThingC; - #[alias(snake_case_method)] - fn camelCaseMethod(&self); - #[alias(snake_case_function)] - fn camelCaseFunction(); - #[alias(i32_method)] - fn overloadedMethod(&self, x: i32); - #[alias(f32_method)] - fn overloadedMethod(&self, x: f32); - #[alias(i32_function)] - fn overloadedFunction(x: i32); - #[alias(f32_function)] - fn overloadedFunction(x: f32); fn make_demo(appname: &str) -> UniquePtr; fn get_name(thing: &ThingC) -> &CxxString; fn do_thing(state: SharedThing); @@ -42,14 +30,7 @@ fn print_r(r: &ThingR) { fn main() { let x = ffi::make_demo("demo of cxx::bridge"); println!("this is a {}", ffi::get_name(x.as_ref().unwrap())); - - x.snake_case_method(); - ffi::snake_case_function(); - x.i32_method(10); - x.f32_method(10.5); - ffi::i32_function(10); - ffi::f32_function(10.5); - + ffi::do_thing(ffi::SharedThing { z: 222, y: Box::new(ThingR(333)), diff --git a/syntax/attrs.rs b/syntax/attrs.rs index 6c9d7811b..c6b3564fe 100644 --- a/syntax/attrs.rs +++ b/syntax/attrs.rs @@ -58,8 +58,8 @@ pub(super) fn parse(cx: &mut Errors, attrs: &[Attribute], mut parser: Parser) { } Err(err) => return cx.push(err), } - } else if attr.path.is_ident("alias") { - match attr.parse_args_with(|input: ParseStream| input.parse()) { + } else if attr.path.is_ident("rust_name") { + match parse_rust_name_attribute.parse2(attr.tokens.clone()) { Ok(alias) => { if let Some(a) = &mut parser.alias { **a = Some(alias); @@ -74,6 +74,12 @@ pub(super) fn parse(cx: &mut Errors, attrs: &[Attribute], mut parser: Parser) { } } +fn parse_rust_name_attribute(input: ParseStream) -> Result { + input.parse::()?; + let lit: LitStr = input.parse()?; + Ok(lit.parse::()?) +} + fn parse_doc_attribute(input: ParseStream) -> Result { input.parse::()?; let lit: LitStr = input.parse()?; diff --git a/tests/ffi/lib.rs b/tests/ffi/lib.rs index 51716e0f5..608624f12 100644 --- a/tests/ffi/lib.rs +++ b/tests/ffi/lib.rs @@ -85,6 +85,15 @@ pub mod ffi { fn set2(&mut self, n: usize) -> usize; fn set_succeed(&mut self, n: usize) -> Result; fn get_fail(&mut self) -> Result; + + #[rust_name = "i32_overloaded_method"] + fn cOverloadedMethod(&self, x: i32) -> String; + #[rust_name = "str_overloaded_method"] + fn cOverloadedMethod(&self, x: &str) -> String; + #[rust_name = "i32_overloaded_function"] + fn cOverloadedFunction(x: i32) -> String; + #[rust_name = "str_overloaded_function"] + fn cOverloadedFunction(x: &str) -> String; } extern "C" { diff --git a/tests/ffi/tests.cc b/tests/ffi/tests.cc index 677a55d5e..d87872d26 100644 --- a/tests/ffi/tests.cc +++ b/tests/ffi/tests.cc @@ -296,6 +296,22 @@ extern "C" std::string *cxx_test_suite_get_unique_ptr_string() noexcept { return std::unique_ptr(new std::string("2020")).release(); } +rust::String C::cOverloadedMethod(int32_t x) const { + return rust::String(std::to_string(x)); +} + +rust::String C::cOverloadedMethod(rust::Str x) const { + return rust::String(std::string(x)); +} + +rust::String cOverloadedFunction(int x) { + return rust::String(std::to_string(x)); +} + +rust::String cOverloadedFunction(rust::Str x) { + return rust::String(std::string(x)); +} + extern "C" const char *cxx_run_test() noexcept { #define STRINGIFY(x) #x #define TOSTRING(x) STRINGIFY(x) diff --git a/tests/ffi/tests.h b/tests/ffi/tests.h index c1a08d2f8..4b1bcd999 100644 --- a/tests/ffi/tests.h +++ b/tests/ffi/tests.h @@ -19,6 +19,8 @@ class C { size_t set_succeed(size_t n); size_t get_fail(); const std::vector &get_v() const; + rust::String cOverloadedMethod(int32_t x) const; + rust::String cOverloadedMethod(rust::Str x) const; private: size_t n; @@ -84,4 +86,7 @@ std::unique_ptr c_try_return_unique_ptr_string(); rust::Vec c_try_return_rust_vec(); const rust::Vec &c_try_return_ref_rust_vec(const C &c); +rust::String cOverloadedFunction(int32_t x); +rust::String cOverloadedFunction(rust::Str x); + } // namespace tests diff --git a/tests/test.rs b/tests/test.rs index ecfec84ca..9b649d4d3 100644 --- a/tests/test.rs +++ b/tests/test.rs @@ -178,3 +178,12 @@ extern "C" fn cxx_test_suite_get_box() -> *mut cxx_test_suite::R { unsafe extern "C" fn cxx_test_suite_r_is_correct(r: *const cxx_test_suite::R) -> bool { *r == 2020 } + +#[test] +fn test_rust_name_attribute() { + assert_eq!("2020".to_string(), ffi::i32_overloaded_function(2020)); + assert_eq!("2020".to_string(), ffi::str_overloaded_function("2020")); + let unique_ptr = ffi::c_return_unique_ptr(); + assert_eq!("2020".to_string(), unique_ptr.i32_overloaded_method(2020)); + assert_eq!("2020".to_string(), unique_ptr.str_overloaded_method("2020")); +} From 2aceb7e44c68a4fe9a404a501e97a433b2959dd3 Mon Sep 17 00:00:00 2001 From: VKachemtsev Date: Sat, 13 Jun 2020 04:51:22 +0700 Subject: [PATCH 4/6] cxx_name function attribute --- syntax/attrs.rs | 2 +- syntax/parse.rs | 4 +--- tests/ffi/lib.rs | 7 +++++++ tests/ffi/tests.cc | 2 ++ 4 files changed, 11 insertions(+), 4 deletions(-) diff --git a/syntax/attrs.rs b/syntax/attrs.rs index c6b3564fe..d90743341 100644 --- a/syntax/attrs.rs +++ b/syntax/attrs.rs @@ -58,7 +58,7 @@ pub(super) fn parse(cx: &mut Errors, attrs: &[Attribute], mut parser: Parser) { } Err(err) => return cx.push(err), } - } else if attr.path.is_ident("rust_name") { + } else if attr.path.is_ident("rust_name") || attr.path.is_ident("cxx_name") { match parse_rust_name_attribute.parse2(attr.tokens.clone()) { Ok(alias) => { if let Some(a) = &mut parser.alias { diff --git a/syntax/parse.rs b/syntax/parse.rs index 9af565ff1..fc0d1425c 100644 --- a/syntax/parse.rs +++ b/syntax/parse.rs @@ -328,9 +328,7 @@ fn parse_extern_fn(cx: &mut Errors, foreign_fn: &ForeignItemFn, lang: Lang) -> R let fn_token = foreign_fn.sig.fn_token; let ident = foreign_fn.sig.ident.clone(); let mut alias = None; - if let Lang::Cxx = lang { - attrs::parse(cx, &foreign_fn.attrs, attrs::Parser { alias: Some(&mut alias), ..Default::default() }); - } + attrs::parse(cx, &foreign_fn.attrs, attrs::Parser { alias: Some(&mut alias), ..Default::default() }); let paren_token = foreign_fn.sig.paren_token; let semi_token = foreign_fn.semi_token; let api_function = match lang { diff --git a/tests/ffi/lib.rs b/tests/ffi/lib.rs index 608624f12..f30dde610 100644 --- a/tests/ffi/lib.rs +++ b/tests/ffi/lib.rs @@ -145,6 +145,9 @@ pub mod ffi { fn r_return_r2(n: usize) -> Box; fn get(self: &R2) -> usize; fn set(self: &mut R2, n: usize) -> usize; + + #[cxx_name = "rAliasedFunction"] + fn r_aliased_function(x: i32) -> String; } } @@ -308,3 +311,7 @@ fn r_fail_return_primitive() -> Result { fn r_return_r2(n: usize) -> Box { Box::new(R2(n)) } + +fn r_aliased_function(x: i32) -> String { + x.to_string() +} diff --git a/tests/ffi/tests.cc b/tests/ffi/tests.cc index d87872d26..422b092fc 100644 --- a/tests/ffi/tests.cc +++ b/tests/ffi/tests.cc @@ -362,6 +362,8 @@ extern "C" const char *cxx_run_test() noexcept { ASSERT(r2->get() == 2021); ASSERT(r2->set(2020) == 2020); ASSERT(r2->get() == 2020); + + ASSERT(std::string(rAliasedFunction(2020)) == "2020"); cxx_test_suite_set_correct(); return nullptr; From f81a2d7ea6989fd7ee7eccf03bf24294576cabba Mon Sep 17 00:00:00 2001 From: VKachemtsev Date: Sat, 13 Jun 2020 05:08:31 +0700 Subject: [PATCH 5/6] rename parse function --- syntax/attrs.rs | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/syntax/attrs.rs b/syntax/attrs.rs index d90743341..fa23f821f 100644 --- a/syntax/attrs.rs +++ b/syntax/attrs.rs @@ -59,7 +59,7 @@ pub(super) fn parse(cx: &mut Errors, attrs: &[Attribute], mut parser: Parser) { Err(err) => return cx.push(err), } } else if attr.path.is_ident("rust_name") || attr.path.is_ident("cxx_name") { - match parse_rust_name_attribute.parse2(attr.tokens.clone()) { + match parse_function_alias_attribute.parse2(attr.tokens.clone()) { Ok(alias) => { if let Some(a) = &mut parser.alias { **a = Some(alias); @@ -74,7 +74,7 @@ pub(super) fn parse(cx: &mut Errors, attrs: &[Attribute], mut parser: Parser) { } } -fn parse_rust_name_attribute(input: ParseStream) -> Result { +fn parse_function_alias_attribute(input: ParseStream) -> Result { input.parse::()?; let lit: LitStr = input.parse()?; Ok(lit.parse::()?) From fa9799bf57f5bbc02050501b0b43901407c2bd00 Mon Sep 17 00:00:00 2001 From: VKachemtsev Date: Sat, 13 Jun 2020 08:23:28 +0700 Subject: [PATCH 6/6] attribute context validation --- syntax/attrs.rs | 4 ++-- syntax/parse.rs | 14 +++++++++++++- 2 files changed, 15 insertions(+), 3 deletions(-) diff --git a/syntax/attrs.rs b/syntax/attrs.rs index fa23f821f..63a293ed1 100644 --- a/syntax/attrs.rs +++ b/syntax/attrs.rs @@ -10,7 +10,7 @@ pub struct Parser<'a> { pub doc: Option<&'a mut Doc>, pub derives: Option<&'a mut Vec>, pub repr: Option<&'a mut Option>, - pub alias: Option<&'a mut Option>, + pub alias: Option<&'a mut Option<(Ident, bool)>>, } pub(super) fn parse_doc(cx: &mut Errors, attrs: &[Attribute]) -> Doc { @@ -62,7 +62,7 @@ pub(super) fn parse(cx: &mut Errors, attrs: &[Attribute], mut parser: Parser) { match parse_function_alias_attribute.parse2(attr.tokens.clone()) { Ok(alias) => { if let Some(a) = &mut parser.alias { - **a = Some(alias); + **a = Some((alias, attr.path.is_ident("rust_name"))); continue; } } diff --git a/syntax/parse.rs b/syntax/parse.rs index fc0d1425c..b64842d21 100644 --- a/syntax/parse.rs +++ b/syntax/parse.rs @@ -327,8 +327,20 @@ fn parse_extern_fn(cx: &mut Errors, foreign_fn: &ForeignItemFn, lang: Lang) -> R let doc = attrs::parse_doc(cx, &foreign_fn.attrs); let fn_token = foreign_fn.sig.fn_token; let ident = foreign_fn.sig.ident.clone(); + let mut attr = None; + attrs::parse(cx, &foreign_fn.attrs, attrs::Parser { alias: Some(&mut attr), ..Default::default() }); let mut alias = None; - attrs::parse(cx, &foreign_fn.attrs, attrs::Parser { alias: Some(&mut alias), ..Default::default() }); + if let Some((ident, is_rust)) = attr { + match lang { + Lang::Cxx if !is_rust => { + return Err(Error::new_spanned(foreign_fn, "C/C++ functions with 'cxx_name' are not allowed")); + }, + Lang::Rust if is_rust => { + return Err(Error::new_spanned(foreign_fn, "Rust functions with 'rust_name' are not allowed")); + }, + _ => alias = Some(ident), + } + } let paren_token = foreign_fn.sig.paren_token; let semi_token = foreign_fn.semi_token; let api_function = match lang {