Skip to content

Commit

Permalink
Fix to make incorrect return type into error (#169)
Browse files Browse the repository at this point in the history
This commit introduces a compile time error for incorrect return types.

For example, the following will now fail to compile:

```rust
#[swift_bridge::bridge]
mod ffi {
    extern "Rust" {
        fn get_reference() -> SomeType;
    }
}

fn get_reference() -> &'static SomeType {
    &SomeType
}
```

Before this commit the above example would compile and calling `get_reference` would cause undefined behavior.
  • Loading branch information
MikuroXina committed Feb 15, 2023
1 parent e5a0c89 commit e7aef34
Show file tree
Hide file tree
Showing 10 changed files with 98 additions and 13 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -211,7 +211,10 @@ impl BridgeableType for OpaqueForeignType {
.generics
.angle_bracketed_concrete_generics_tokens(types);
quote! {
Box::into_raw(Box::new(#expression)) as *mut super::#ty_name #generics
Box::into_raw(Box::new({
let val: super::#ty_name #generics = #expression;
val
})) as *mut super::#ty_name #generics
}
}
} else {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -564,13 +564,19 @@ mod extern_rust_async_function_returns_result_opaque {
Ok(ok) => {
swift_bridge::result::ResultPtrAndPtr {
is_ok: true,
ok_or_err: Box::into_raw(Box::new(ok)) as *mut super::OkType as *mut std::ffi::c_void
ok_or_err: Box::into_raw(Box::new({
let val: super::OkType = ok;
val
})) as *mut super::OkType as *mut std::ffi::c_void
}
}
Err(err) => {
swift_bridge::result::ResultPtrAndPtr {
is_ok: false,
ok_or_err: Box::into_raw(Box::new(err)) as *mut super::ErrorType as *mut std::ffi::c_void
ok_or_err: Box::into_raw(Box::new({
let val: super::ErrorType = err;
val
})) as *mut super::ErrorType as *mut std::ffi::c_void
}
}
};
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -411,7 +411,10 @@ mod test_swift_takes_callback_return_opaque_rust_type {
quote! {
#[export_name = "__swift_bridge__$some_function$param0"]
pub extern "C" fn some_function_param0(some_function_callback: *mut Box<dyn FnOnce() -> super::ARustType>) -> *mut super::ARustType {
Box::into_raw(Box::new(unsafe { Box::from_raw(some_function_callback)() })) as *mut super::ARustType
Box::into_raw(Box::new({
let val: super::ARustType = unsafe { Box::from_raw(some_function_callback)() };
val
})) as *mut super::ARustType
}

#[export_name = "__swift_bridge__$some_function$_free$param0"]
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -23,7 +23,10 @@ mod test_extern_rust_function_owned_opaque_rust_type_return {
ExpectedRustTokens::Contains(quote! {
#[export_name = "__swift_bridge__$some_function"]
pub extern "C" fn __swift_bridge__some_function () -> *mut super::SomeType {
Box::into_raw(Box::new(super::some_function())) as *mut super::SomeType
Box::into_raw(Box::new({
let val: super::SomeType = super::some_function();
val
})) as *mut super::SomeType
}
})
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -218,7 +218,10 @@ mod generic_opaque_rust_type_return {
ExpectedRustTokens::Contains(quote! {
#[export_name = "__swift_bridge__$some_function"]
pub extern "C" fn __swift_bridge__some_function () -> *mut super::SomeType<u32> {
Box::into_raw(Box::new(super::some_function())) as *mut super::SomeType<u32>
Box::into_raw(Box::new({
let val: super::SomeType<u32> = super::some_function();
val
})) as *mut super::SomeType<u32>
}
})
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -126,7 +126,7 @@ extension HashableTypeRef: Hashable{
fn expected_c_header() -> ExpectedCHeader {
ExpectedCHeader::ContainsManyAfterTrim(vec![
r#"
uint64_t __swift_bridge__$HashableType$_hash(void* self);
uint64_t __swift_bridge__$HashableType$_hash(void* self);
"#,
r#"
"#,
Expand Down Expand Up @@ -416,7 +416,10 @@ mod extern_swift_freestanding_fn_with_owned_opaque_rust_type_arg {
fn expected_rust_tokens() -> ExpectedRustTokens {
ExpectedRustTokens::Contains(quote! {
pub fn some_function (arg: super::MyType) {
unsafe { __swift_bridge__some_function( Box::into_raw(Box::new(arg)) as *mut super::MyType ) }
unsafe { __swift_bridge__some_function( Box::into_raw(Box::new({
let val: super::MyType = arg;
val
})) as *mut super::MyType ) }
}

extern "C" {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -151,13 +151,19 @@ mod extern_rust_fn_return_result_opaque_rust {
Ok(ok) => {
swift_bridge::result::ResultPtrAndPtr {
is_ok: true,
ok_or_err: Box::into_raw(Box::new(ok)) as *mut super::SomeType as *mut std::ffi::c_void
ok_or_err: Box::into_raw(Box::new({
let val: super::SomeType = ok;
val
})) as *mut super::SomeType as *mut std::ffi::c_void
}
}
Err(err) => {
swift_bridge::result::ResultPtrAndPtr {
is_ok: false,
ok_or_err: Box::into_raw(Box::new(err)) as *mut super::SomeType as *mut std::ffi::c_void
ok_or_err: Box::into_raw(Box::new({
let val: super::SomeType = err;
val
})) as *mut super::SomeType as *mut std::ffi::c_void
}
}
}
Expand Down
15 changes: 12 additions & 3 deletions crates/swift-bridge-ir/src/codegen/generate_rust_tokens.rs
Original file line number Diff line number Diff line change
Expand Up @@ -507,7 +507,10 @@ mod tests {
let expected_func = quote! {
#[export_name = "__swift_bridge__$some_function"]
pub extern "C" fn __swift_bridge__some_function () -> *mut super::Foo {
Box::into_raw(Box::new(super::another_function())) as *mut super::Foo
Box::into_raw(Box::new({
let val: super::Foo = super::another_function();
val
})) as *mut super::Foo
}
};

Expand All @@ -531,7 +534,10 @@ mod tests {
let expected_func = quote! {
#[export_name = "__swift_bridge__$some_function"]
pub extern "C" fn __swift_bridge__some_function () -> *mut super::Foo {
Box::into_raw(Box::new(super::some_function().into())) as *mut super::Foo
Box::into_raw(Box::new({
let val: super::Foo = super::some_function().into();
val
})) as *mut super::Foo
}
};

Expand Down Expand Up @@ -630,7 +636,10 @@ mod tests {
let expected = quote! {
#[export_name = "__swift_bridge__$SomeType$new"]
pub extern "C" fn __swift_bridge__SomeType_new () -> *mut super::SomeType {
Box::into_raw(Box::new(super::SomeType::new())) as *mut super::SomeType
Box::into_raw(Box::new({
let val: super::SomeType = super::SomeType::new();
val
})) as *mut super::SomeType
}
};

Expand Down
26 changes: 26 additions & 0 deletions crates/swift-bridge-macro/tests/ui/incorrect-return-type.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,26 @@
//! # To Run
//! cargo test -p swift-bridge-macro -- ui trybuild=incorrect-return-type.rs

pub struct SomeType;

#[swift_bridge::bridge]
mod ffi {
extern "Rust" {
type SomeType;

#[swift_bridge(rust_name = "some_function")]
fn fn1() -> SomeType;
#[swift_bridge(rust_name = "another_function")]
fn fn2() -> SomeType;
}
}

fn some_function() -> &'static SomeType {
&SomeType
}

fn another_function() -> Option<SomeType> {
None
}

fn main() {}
23 changes: 23 additions & 0 deletions crates/swift-bridge-macro/tests/ui/incorrect-return-type.stderr
Original file line number Diff line number Diff line change
@@ -0,0 +1,23 @@
error[E0308]: mismatched types
--> tests/ui/incorrect-return-type.rs:6:1
|
6 | #[swift_bridge::bridge]
| ^^^^^^^^^^^^^^^^^^^^^^^
| |
| expected struct `SomeType`, found `&SomeType`
| expected due to this
|
= note: this error originates in the attribute macro `swift_bridge::bridge` (in Nightly builds, run with -Z macro-backtrace for more info)

error[E0308]: mismatched types
--> tests/ui/incorrect-return-type.rs:6:1
|
6 | #[swift_bridge::bridge]
| ^^^^^^^^^^^^^^^^^^^^^^^
| |
| expected struct `SomeType`, found enum `Option`
| expected due to this
|
= note: expected struct `SomeType`
found enum `Option<SomeType>`
= note: this error originates in the attribute macro `swift_bridge::bridge` (in Nightly builds, run with -Z macro-backtrace for more info)

0 comments on commit e7aef34

Please sign in to comment.