Skip to content
Open
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
2 changes: 0 additions & 2 deletions demo/include/blobstore.h
Original file line number Diff line number Diff line change
Expand Up @@ -20,7 +20,5 @@ class BlobstoreClient {
std::shared_ptr<impl> impl;
};

std::unique_ptr<BlobstoreClient> new_blobstore_client();

} // namespace blobstore
} // namespace org
4 changes: 0 additions & 4 deletions demo/src/blobstore.cc
Original file line number Diff line number Diff line change
Expand Up @@ -63,9 +63,5 @@ BlobMetadata BlobstoreClient::metadata(uint64_t blobid) const {
return metadata;
}

std::unique_ptr<BlobstoreClient> new_blobstore_client() {
return std::make_unique<BlobstoreClient>();
}

} // namespace blobstore
} // namespace org
1 change: 1 addition & 0 deletions demo/src/main.rs
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,7 @@ mod ffi {

type BlobstoreClient;

#[constructor]
fn new_blobstore_client() -> UniquePtr<BlobstoreClient>;
fn put(&self, parts: &mut MultiBuf) -> u64;
fn tag(&self, blobid: u64, tag: &str);
Expand Down
82 changes: 57 additions & 25 deletions gen/src/write.rs
Original file line number Diff line number Diff line change
Expand Up @@ -899,6 +899,42 @@ fn write_cxx_function_shim<'a>(out: &mut OutFile<'a>, efn: &'a ExternFn) {
Lang::Rust => unreachable!(),
}
writeln!(out, " {{");

if efn.is_constructor {
write_constructor_function_body(out, efn);
} else {
write_default_function_body(out, efn, indirect_return);
}
writeln!(out, "}}");
for arg in &efn.args {
if let Type::Fn(f) = &arg.ty {
let var = &arg.name;
write_function_pointer_trampoline(out, efn, var, f);
}
}
out.end_block(Block::ExternC);
}

fn write_constructor_function_body<'a>(out: &mut OutFile<'a>, efn: &'a ExternFn) {
write!(out, " return new ");
if let Some(Type::UniquePtr(ty)) = &efn.sig.ret {
write_type_to_generic_writer(out, &ty.inner, out.types)
} else {
panic!(
"Constructor: '{}' must return a UniquePtr<T>",
efn.name.rust
);
}
write!(out, "(");
write_args_punctuated(out, efn);
writeln!(out, ");");
}

fn write_default_function_body<'a>(
out: &mut OutFile<'a>,
efn: &'a ExternFn,
indirect_return: bool,
) {
write!(out, " ");
write_return_type(out, &efn.ret);
match efn.receiver() {
Expand Down Expand Up @@ -968,6 +1004,27 @@ fn write_cxx_function_shim<'a>(out: &mut OutFile<'a>, efn: &'a ExternFn) {
None => write!(out, "{}$(", efn.name.rust),
Some(_) => write!(out, "(self.*{}$)(", efn.name.rust),
}
write_args_punctuated(out, efn);
write!(out, ")");
match &efn.ret {
Some(Type::RustBox(_)) => write!(out, ".into_raw()"),
Some(Type::UniquePtr(_)) => write!(out, ".release()"),
Some(Type::Str(_) | Type::SliceRef(_)) if !indirect_return => write!(out, ")"),
_ => {}
}
if indirect_return {
write!(out, ")");
}
writeln!(out, ";");
if efn.throws {
writeln!(out, " throw$.ptr = nullptr;");
writeln!(out, " }},");
writeln!(out, " ::rust::detail::Fail(throw$));");
writeln!(out, " return throw$;");
}
}

fn write_args_punctuated<'a>(out: &mut OutFile<'a>, efn: &'a ExternFn) {
for (i, arg) in efn.args.iter().enumerate() {
if i > 0 {
write!(out, ", ");
Expand Down Expand Up @@ -996,31 +1053,6 @@ fn write_cxx_function_shim<'a>(out: &mut OutFile<'a>, efn: &'a ExternFn) {
write!(out, "{}", arg.name.cxx);
}
}
write!(out, ")");
match &efn.ret {
Some(Type::RustBox(_)) => write!(out, ".into_raw()"),
Some(Type::UniquePtr(_)) => write!(out, ".release()"),
Some(Type::Str(_) | Type::SliceRef(_)) if !indirect_return => write!(out, ")"),
_ => {}
}
if indirect_return {
write!(out, ")");
}
writeln!(out, ";");
if efn.throws {
writeln!(out, " throw$.ptr = nullptr;");
writeln!(out, " }},");
writeln!(out, " ::rust::detail::Fail(throw$));");
writeln!(out, " return throw$;");
}
writeln!(out, "}}");
for arg in &efn.args {
if let Type::Fn(f) = &arg.ty {
let var = &arg.name;
write_function_pointer_trampoline(out, efn, var, f);
}
}
out.end_block(Block::ExternC);
}

fn write_function_pointer_trampoline(out: &mut OutFile, efn: &ExternFn, var: &Pair, f: &Signature) {
Expand Down
6 changes: 6 additions & 0 deletions syntax/attrs.rs
Original file line number Diff line number Diff line change
Expand Up @@ -36,6 +36,7 @@ pub(crate) struct Parser<'a> {
pub cxx_name: Option<&'a mut Option<ForeignName>>,
pub rust_name: Option<&'a mut Option<Ident>>,
pub self_type: Option<&'a mut Option<Ident>>,
pub is_constructor: Option<&'a mut bool>,
pub ignore_unrecognized: bool,

// Suppress clippy needless_update lint ("struct update has no effect, all
Expand Down Expand Up @@ -192,6 +193,11 @@ pub(crate) fn parse(cx: &mut Errors, attrs: Vec<Attribute>, mut parser: Parser)
other_attrs.lint.push(attr);
continue;
}
} else if attr_path.is_ident("constructor") {
if let Some(constructor) = &mut parser.is_constructor {
**constructor = true;
continue;
}
}
if !parser.ignore_unrecognized {
cx.error(attr, "unsupported attribute");
Expand Down
2 changes: 2 additions & 0 deletions syntax/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -150,6 +150,8 @@ pub(crate) struct ExternFn {
pub attrs: OtherAttrs,
#[cfg_attr(not(proc_macro), expect(dead_code))]
pub visibility: Token![pub],
#[cfg_attr(proc_macro, expect(dead_code))]
pub is_constructor: bool,
pub name: Pair,
pub sig: Signature,
pub semi_token: Token![;],
Expand Down
3 changes: 3 additions & 0 deletions syntax/parse.rs
Original file line number Diff line number Diff line change
Expand Up @@ -547,6 +547,7 @@ fn parse_extern_fn(
let mut rust_name = None;
let mut self_type = None;
let mut attrs = attrs.clone();
let mut is_constructor = false;
attrs.extend(attrs::parse(
cx,
mem::take(&mut foreign_fn.attrs),
Expand All @@ -557,6 +558,7 @@ fn parse_extern_fn(
cxx_name: Some(&mut cxx_name),
rust_name: Some(&mut rust_name),
self_type: Some(&mut self_type),
is_constructor: Some(&mut is_constructor),
..Default::default()
},
));
Expand Down Expand Up @@ -725,6 +727,7 @@ fn parse_extern_fn(
paren_token,
throws_tokens,
},
is_constructor,
semi_token,
trusted,
}))
Expand Down
7 changes: 7 additions & 0 deletions tests/ffi/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -112,6 +112,13 @@ pub mod ffi {
unsafe extern "C++" {
type C;

#[constructor]
fn new_c_0_args() -> UniquePtr<C>;
#[constructor]
fn new_c_1_args(n: usize) -> UniquePtr<C>;
#[constructor]
fn new_c_2_args(n: usize, m: usize) -> UniquePtr<C>;

fn c_return_primitive() -> usize;
fn c_return_shared() -> Shared;
fn c_return_box() -> Box<R>;
Expand Down
2 changes: 2 additions & 0 deletions tests/ffi/tests.cc
Original file line number Diff line number Diff line change
Expand Up @@ -27,7 +27,9 @@ static_assert(4 == alignof(OveralignedStruct), "expected 4 byte alignment");

static constexpr char SLICE_DATA[] = "2020";

C::C() : n(0) {}
C::C(size_t n) : n(n) {}
C::C(size_t n, size_t m) : n(n + m) {}

size_t C::get() const { return this->n; }

Expand Down
2 changes: 2 additions & 0 deletions tests/ffi/tests.h
Original file line number Diff line number Diff line change
Expand Up @@ -54,7 +54,9 @@ enum class Enum : uint16_t;

class C {
public:
C();
C(size_t n);
C(size_t n, size_t m);
size_t get() const;
size_t set(size_t n);
size_t get2() const;
Expand Down