Skip to content

Commit 094a7be

Browse files
committed
Support C++ constructor for shared type
1 parent 64e5e41 commit 094a7be

File tree

13 files changed

+269
-103
lines changed

13 files changed

+269
-103
lines changed

gen/src/write.rs

Lines changed: 163 additions & 89 deletions
Original file line numberDiff line numberDiff line change
@@ -271,16 +271,29 @@ fn write_struct<'a>(out: &mut OutFile<'a>, strct: &'a Struct, methods: &[&Extern
271271

272272
out.next_section();
273273

274+
// default move/copy constructors/assignments for trivially copyable types
275+
// used for indirect return
276+
if out.types.structs_with_constructors.contains(&strct.name.rust) {
277+
writeln!(out, " {0}() noexcept = default;", strct.name.cxx);
278+
writeln!(out, " {0}(const {0}&) noexcept = default;", strct.name.cxx);
279+
writeln!(out, " {0}({0}&&) noexcept = default;", strct.name.cxx);
280+
writeln!(out, " {0}& operator=(const {0}&) noexcept = default;", strct.name.cxx);
281+
writeln!(out, " {0}& operator=({0}&&) noexcept = default;", strct.name.cxx);
282+
}
283+
274284
for method in methods {
275285
if !method.doc.is_empty() {
276286
out.next_section();
277287
}
278288
write_doc(out, " ", &method.doc);
279289
write!(out, " ");
280290
let sig = &method.sig;
281-
let local_name = method.name.cxx.to_string();
291+
let local_name = match (&method.self_type, sig.constructor) {
292+
(Some(self_type), true) => out.types.resolve(self_type).name.cxx.to_string(),
293+
_ => method.name.cxx.to_string(),
294+
};
282295
let indirect_call = false;
283-
if method.self_type.is_some() {
296+
if method.self_type.is_some() && !method.sig.constructor {
284297
write!(out, "static ");
285298
}
286299
write_rust_function_shim_decl(out, &local_name, sig, &None, indirect_call);
@@ -375,7 +388,7 @@ fn write_opaque_type<'a>(out: &mut OutFile<'a>, ety: &'a ExternType, methods: &[
375388
let sig = &method.sig;
376389
let local_name = method.name.cxx.to_string();
377390
let indirect_call = false;
378-
if method.self_type.is_some() {
391+
if method.self_type.is_some() && !method.sig.constructor {
379392
write!(out, "static ");
380393
}
381394
write_rust_function_shim_decl(out, &local_name, sig, &None, indirect_call);
@@ -754,51 +767,61 @@ fn write_cxx_function_shim<'a>(out: &mut OutFile<'a>, efn: &'a ExternFn) {
754767
if !efn.args.is_empty() || efn.receiver.is_some() {
755768
write!(out, ", ");
756769
}
757-
write_indirect_return_type_space(out, efn.ret.as_ref().unwrap());
770+
if efn.sig.constructor {
771+
write!(
772+
out,
773+
"{} ",
774+
out.types.resolve(efn.self_type.as_ref().unwrap()).name.cxx
775+
);
776+
} else {
777+
write_indirect_return_type_space(out, efn.ret.as_ref().unwrap());
778+
}
758779
write!(out, "*return$");
759780
}
760781
writeln!(out, ") noexcept {{");
761-
write!(out, " ");
762-
write_return_type(out, &efn.ret);
763-
match &efn.receiver {
764-
None => write!(out, "(*{}$)(", efn.name.rust),
765-
Some(receiver) => write!(
766-
out,
767-
"({}::*{}$)(",
768-
out.types.resolve(&receiver.ty).name.to_fully_qualified(),
769-
efn.name.rust,
770-
),
771-
}
772-
for (i, arg) in efn.args.iter().enumerate() {
773-
if i > 0 {
774-
write!(out, ", ");
782+
if !efn.sig.constructor {
783+
write!(out, " ");
784+
write_return_type(out, &efn.ret);
785+
match &efn.receiver {
786+
None => write!(out, "(*{}$)(", efn.name.rust),
787+
Some(receiver) => write!(
788+
out,
789+
"({}::*{}$)(",
790+
out.types.resolve(&receiver.ty).name.to_fully_qualified(),
791+
efn.name.rust,
792+
),
775793
}
776-
write_type(out, &arg.ty);
777-
}
778-
write!(out, ")");
779-
if let Some(receiver) = &efn.receiver {
780-
if !receiver.mutable {
781-
write!(out, " const");
794+
for (i, arg) in efn.args.iter().enumerate() {
795+
if i > 0 {
796+
write!(out, ", ");
797+
}
798+
write_type(out, &arg.ty);
782799
}
800+
write!(out, ")");
801+
if let Some(receiver) = &efn.receiver {
802+
if !receiver.mutable {
803+
write!(out, " const");
804+
}
805+
}
806+
write!(out, " = ");
807+
match (&efn.receiver, &efn.self_type) {
808+
(None, None) => write!(out, "{}", efn.name.to_fully_qualified()),
809+
(Some(receiver), None) => write!(
810+
out,
811+
"&{}::{}",
812+
out.types.resolve(&receiver.ty).name.to_fully_qualified(),
813+
efn.name.cxx,
814+
),
815+
(None, Some(self_type)) => write!(
816+
out,
817+
"&{}::{}",
818+
out.types.resolve(self_type).name.to_fully_qualified(),
819+
efn.name.cxx,
820+
),
821+
_ => unreachable!("receiver and self_type are mutually exclusive"),
822+
}
823+
writeln!(out, ";");
783824
}
784-
write!(out, " = ");
785-
match (&efn.receiver, &efn.self_type) {
786-
(None, None) => write!(out, "{}", efn.name.to_fully_qualified()),
787-
(Some(receiver), None) => write!(
788-
out,
789-
"&{}::{}",
790-
out.types.resolve(&receiver.ty).name.to_fully_qualified(),
791-
efn.name.cxx,
792-
),
793-
(None, Some(self_type)) => write!(
794-
out,
795-
"&{}::{}",
796-
out.types.resolve(self_type).name.to_fully_qualified(),
797-
efn.name.cxx,
798-
),
799-
_ => unreachable!("receiver and self_type are mutually exclusive"),
800-
}
801-
writeln!(out, ";");
802825
write!(out, " ");
803826
if efn.throws {
804827
out.builtin.ptr_len = true;
@@ -811,28 +834,38 @@ fn write_cxx_function_shim<'a>(out: &mut OutFile<'a>, efn: &'a ExternFn) {
811834
if indirect_return {
812835
out.include.new = true;
813836
write!(out, "new (return$) ");
814-
write_indirect_return_type(out, efn.ret.as_ref().unwrap());
837+
if efn.sig.constructor {
838+
write!(
839+
out,
840+
"{}",
841+
out.types.resolve(efn.self_type.as_ref().unwrap()).name.cxx
842+
);
843+
} else {
844+
write_indirect_return_type(out, efn.ret.as_ref().unwrap());
845+
}
815846
write!(out, "(");
816847
} else if efn.ret.is_some() {
817848
write!(out, "return ");
818849
}
819-
match &efn.ret {
820-
Some(Type::Ref(_)) => write!(out, "&"),
821-
Some(Type::Str(_)) if !indirect_return => {
822-
out.builtin.rust_str_repr = true;
823-
write!(out, "::rust::impl<::rust::Str>::repr(");
850+
if !efn.sig.constructor {
851+
match &efn.ret {
852+
Some(Type::Ref(_)) => write!(out, "&"),
853+
Some(Type::Str(_)) if !indirect_return => {
854+
out.builtin.rust_str_repr = true;
855+
write!(out, "::rust::impl<::rust::Str>::repr(");
856+
}
857+
Some(ty @ Type::SliceRef(_)) if !indirect_return => {
858+
out.builtin.rust_slice_repr = true;
859+
write!(out, "::rust::impl<");
860+
write_type(out, ty);
861+
write!(out, ">::repr(");
862+
}
863+
_ => {}
824864
}
825-
Some(ty @ Type::SliceRef(_)) if !indirect_return => {
826-
out.builtin.rust_slice_repr = true;
827-
write!(out, "::rust::impl<");
828-
write_type(out, ty);
829-
write!(out, ">::repr(");
865+
match &efn.receiver {
866+
None => write!(out, "{}$(", efn.name.rust),
867+
Some(_) => write!(out, "(self.*{}$)(", efn.name.rust),
830868
}
831-
_ => {}
832-
}
833-
match &efn.receiver {
834-
None => write!(out, "{}$(", efn.name.rust),
835-
Some(_) => write!(out, "(self.*{}$)(", efn.name.rust),
836869
}
837870
for (i, arg) in efn.args.iter().enumerate() {
838871
if i > 0 {
@@ -862,7 +895,9 @@ fn write_cxx_function_shim<'a>(out: &mut OutFile<'a>, efn: &'a ExternFn) {
862895
write!(out, "{}", arg.name.cxx);
863896
}
864897
}
865-
write!(out, ")");
898+
if !efn.sig.constructor {
899+
write!(out, ")");
900+
}
866901
match &efn.ret {
867902
Some(Type::RustBox(_)) => write!(out, ".into_raw()"),
868903
Some(Type::UniquePtr(_)) => write!(out, ".release()"),
@@ -892,27 +927,36 @@ fn write_cxx_function_shim<'a>(out: &mut OutFile<'a>, efn: &'a ExternFn) {
892927
fn write_function_pointer_trampoline(out: &mut OutFile, efn: &ExternFn, var: &Pair, f: &Signature) {
893928
let r_trampoline = mangle::r_trampoline(efn, var, out.types);
894929
let indirect_call = true;
895-
write_rust_function_decl_impl(out, &r_trampoline, f, indirect_call);
930+
write_rust_function_decl_impl(out, &r_trampoline, f, &efn.self_type, indirect_call);
896931

897932
out.next_section();
898933
let c_trampoline = mangle::c_trampoline(efn, var, out.types).to_string();
899934
let doc = Doc::new();
900-
write_rust_function_shim_impl(out, &c_trampoline, f, &efn.self_type, &doc, &r_trampoline, indirect_call);
935+
write_rust_function_shim_impl(
936+
out,
937+
&c_trampoline,
938+
f,
939+
&efn.self_type,
940+
&doc,
941+
&r_trampoline,
942+
indirect_call,
943+
);
901944
}
902945

903946
fn write_rust_function_decl<'a>(out: &mut OutFile<'a>, efn: &'a ExternFn) {
904947
out.set_namespace(&efn.name.namespace);
905948
out.begin_block(Block::ExternC);
906949
let link_name = mangle::extern_fn(efn, out.types);
907950
let indirect_call = false;
908-
write_rust_function_decl_impl(out, &link_name, efn, indirect_call);
951+
write_rust_function_decl_impl(out, &link_name, efn, &efn.self_type, indirect_call);
909952
out.end_block(Block::ExternC);
910953
}
911954

912955
fn write_rust_function_decl_impl(
913956
out: &mut OutFile,
914957
link_name: &Symbol,
915958
sig: &Signature,
959+
self_type: &Option<Ident>,
916960
indirect_call: bool,
917961
) {
918962
out.next_section();
@@ -947,15 +991,23 @@ fn write_rust_function_decl_impl(
947991
if needs_comma {
948992
write!(out, ", ");
949993
}
950-
match sig.ret.as_ref().unwrap() {
951-
Type::Ref(ret) => {
952-
write_type_space(out, &ret.inner);
953-
if !ret.mutable {
954-
write!(out, "const ");
994+
if sig.constructor {
995+
write!(
996+
out,
997+
"{} ",
998+
out.types.resolve(self_type.as_ref().unwrap()).name.cxx
999+
);
1000+
} else {
1001+
match sig.ret.as_ref().unwrap() {
1002+
Type::Ref(ret) => {
1003+
write_type_space(out, &ret.inner);
1004+
if !ret.mutable {
1005+
write!(out, "const ");
1006+
}
1007+
write!(out, "*");
9551008
}
956-
write!(out, "*");
1009+
ret => write_type_space(out, ret),
9571010
}
958-
ret => write_type_space(out, ret),
9591011
}
9601012
write!(out, "*return$");
9611013
needs_comma = true;
@@ -982,7 +1034,15 @@ fn write_rust_function_shim<'a>(out: &mut OutFile<'a>, efn: &'a ExternFn) {
9821034
let doc = &efn.doc;
9831035
let invoke = mangle::extern_fn(efn, out.types);
9841036
let indirect_call = false;
985-
write_rust_function_shim_impl(out, &local_name, efn, &efn.self_type, doc, &invoke, indirect_call);
1037+
write_rust_function_shim_impl(
1038+
out,
1039+
&local_name,
1040+
efn,
1041+
&efn.self_type,
1042+
doc,
1043+
&invoke,
1044+
indirect_call,
1045+
);
9861046
}
9871047

9881048
fn write_rust_function_shim_decl(
@@ -993,12 +1053,18 @@ fn write_rust_function_shim_decl(
9931053
indirect_call: bool,
9941054
) {
9951055
begin_function_definition(out);
996-
write_return_type(out, &sig.ret);
1056+
if !sig.constructor {
1057+
write_return_type(out, &sig.ret);
1058+
}
9971059
if let Some(self_type) = self_type {
998-
write!(out, "{}::{}(", out.types.resolve(self_type).name.cxx, local_name);
1060+
let cxx_name = &out.types.resolve(self_type).name.cxx;
1061+
if sig.constructor {
1062+
write!(out, "{}::{}(", cxx_name, cxx_name);
1063+
} else {
1064+
write!(out, "{}::{}(", cxx_name, local_name);
1065+
}
9991066
} else {
10001067
write!(out, "{}(", local_name);
1001-
10021068
}
10031069
for (i, arg) in sig.args.iter().enumerate() {
10041070
if i > 0 {
@@ -1059,20 +1125,22 @@ fn write_rust_function_shim_impl(
10591125
write!(out, " ");
10601126
let indirect_return = indirect_return(sig, out.types);
10611127
if indirect_return {
1062-
out.builtin.maybe_uninit = true;
1063-
write!(out, "::rust::MaybeUninit<");
1064-
match sig.ret.as_ref().unwrap() {
1065-
Type::Ref(ret) => {
1066-
write_type_space(out, &ret.inner);
1067-
if !ret.mutable {
1068-
write!(out, "const ");
1128+
if !sig.constructor {
1129+
out.builtin.maybe_uninit = true;
1130+
write!(out, "::rust::MaybeUninit<");
1131+
match sig.ret.as_ref().unwrap() {
1132+
Type::Ref(ret) => {
1133+
write_type_space(out, &ret.inner);
1134+
if !ret.mutable {
1135+
write!(out, "const ");
1136+
}
1137+
write!(out, "*");
10691138
}
1070-
write!(out, "*");
1139+
ret => write_type(out, ret),
10711140
}
1072-
ret => write_type(out, ret),
1141+
writeln!(out, "> return$;");
1142+
write!(out, " ");
10731143
}
1074-
writeln!(out, "> return$;");
1075-
write!(out, " ");
10761144
} else if let Some(ret) = &sig.ret {
10771145
write!(out, "return ");
10781146
match ret {
@@ -1128,7 +1196,11 @@ fn write_rust_function_shim_impl(
11281196
if needs_comma {
11291197
write!(out, ", ");
11301198
}
1131-
write!(out, "&return$.value");
1199+
if sig.constructor {
1200+
write!(out, "this");
1201+
} else {
1202+
write!(out, "&return$.value");
1203+
}
11321204
needs_comma = true;
11331205
}
11341206
if indirect_call {
@@ -1152,7 +1224,7 @@ fn write_rust_function_shim_impl(
11521224
writeln!(out, " throw ::rust::impl<::rust::Error>::error(error$);");
11531225
writeln!(out, " }}");
11541226
}
1155-
if indirect_return {
1227+
if indirect_return && !sig.constructor {
11561228
write!(out, " return ");
11571229
match sig.ret.as_ref().unwrap() {
11581230
Type::Ref(_) => write!(out, "*return$.value"),
@@ -1174,9 +1246,11 @@ fn write_return_type(out: &mut OutFile, ty: &Option<Type>) {
11741246
}
11751247

11761248
fn indirect_return(sig: &Signature, types: &Types) -> bool {
1177-
sig.ret
1178-
.as_ref()
1179-
.is_some_and(|ret| sig.throws || types.needs_indirect_abi(ret))
1249+
sig.constructor
1250+
|| sig
1251+
.ret
1252+
.as_ref()
1253+
.is_some_and(|ret| sig.throws || types.needs_indirect_abi(ret))
11801254
}
11811255

11821256
fn write_indirect_return_type(out: &mut OutFile, ty: &Type) {

0 commit comments

Comments
 (0)