Skip to content

Commit 8ec6711

Browse files
committed
Support C++ constructor for shared type
1 parent 64e5e41 commit 8ec6711

File tree

14 files changed

+271
-104
lines changed

14 files changed

+271
-104
lines changed

gen/src/write.rs

+160-89
Original file line numberDiff line numberDiff line change
@@ -271,16 +271,26 @@ fn write_struct<'a>(out: &mut OutFile<'a>, strct: &'a Struct, methods: &[&Extern
271271

272272
out.next_section();
273273

274+
// default move 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}({0}&&) noexcept = default;", strct.name.cxx);
278+
writeln!(out, " {0}& operator=({0}&&) noexcept = default;", strct.name.cxx);
279+
}
280+
274281
for method in methods {
275282
if !method.doc.is_empty() {
276283
out.next_section();
277284
}
278285
write_doc(out, " ", &method.doc);
279286
write!(out, " ");
280287
let sig = &method.sig;
281-
let local_name = method.name.cxx.to_string();
288+
let local_name = match (&method.self_type, sig.constructor) {
289+
(Some(self_type), true) => out.types.resolve(self_type).name.cxx.to_string(),
290+
_ => method.name.cxx.to_string(),
291+
};
282292
let indirect_call = false;
283-
if method.self_type.is_some() {
293+
if method.self_type.is_some() && !method.sig.constructor {
284294
write!(out, "static ");
285295
}
286296
write_rust_function_shim_decl(out, &local_name, sig, &None, indirect_call);
@@ -375,7 +385,7 @@ fn write_opaque_type<'a>(out: &mut OutFile<'a>, ety: &'a ExternType, methods: &[
375385
let sig = &method.sig;
376386
let local_name = method.name.cxx.to_string();
377387
let indirect_call = false;
378-
if method.self_type.is_some() {
388+
if method.self_type.is_some() && !method.sig.constructor {
379389
write!(out, "static ");
380390
}
381391
write_rust_function_shim_decl(out, &local_name, sig, &None, indirect_call);
@@ -754,51 +764,61 @@ fn write_cxx_function_shim<'a>(out: &mut OutFile<'a>, efn: &'a ExternFn) {
754764
if !efn.args.is_empty() || efn.receiver.is_some() {
755765
write!(out, ", ");
756766
}
757-
write_indirect_return_type_space(out, efn.ret.as_ref().unwrap());
767+
if efn.sig.constructor {
768+
write!(
769+
out,
770+
"{} ",
771+
out.types.resolve(efn.self_type.as_ref().unwrap()).name.cxx
772+
);
773+
} else {
774+
write_indirect_return_type_space(out, efn.ret.as_ref().unwrap());
775+
}
758776
write!(out, "*return$");
759777
}
760778
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, ", ");
779+
if !efn.sig.constructor {
780+
write!(out, " ");
781+
write_return_type(out, &efn.ret);
782+
match &efn.receiver {
783+
None => write!(out, "(*{}$)(", efn.name.rust),
784+
Some(receiver) => write!(
785+
out,
786+
"({}::*{}$)(",
787+
out.types.resolve(&receiver.ty).name.to_fully_qualified(),
788+
efn.name.rust,
789+
),
775790
}
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");
791+
for (i, arg) in efn.args.iter().enumerate() {
792+
if i > 0 {
793+
write!(out, ", ");
794+
}
795+
write_type(out, &arg.ty);
782796
}
797+
write!(out, ")");
798+
if let Some(receiver) = &efn.receiver {
799+
if !receiver.mutable {
800+
write!(out, " const");
801+
}
802+
}
803+
write!(out, " = ");
804+
match (&efn.receiver, &efn.self_type) {
805+
(None, None) => write!(out, "{}", efn.name.to_fully_qualified()),
806+
(Some(receiver), None) => write!(
807+
out,
808+
"&{}::{}",
809+
out.types.resolve(&receiver.ty).name.to_fully_qualified(),
810+
efn.name.cxx,
811+
),
812+
(None, Some(self_type)) => write!(
813+
out,
814+
"&{}::{}",
815+
out.types.resolve(self_type).name.to_fully_qualified(),
816+
efn.name.cxx,
817+
),
818+
_ => unreachable!("receiver and self_type are mutually exclusive"),
819+
}
820+
writeln!(out, ";");
783821
}
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, ";");
802822
write!(out, " ");
803823
if efn.throws {
804824
out.builtin.ptr_len = true;
@@ -811,28 +831,38 @@ fn write_cxx_function_shim<'a>(out: &mut OutFile<'a>, efn: &'a ExternFn) {
811831
if indirect_return {
812832
out.include.new = true;
813833
write!(out, "new (return$) ");
814-
write_indirect_return_type(out, efn.ret.as_ref().unwrap());
834+
if efn.sig.constructor {
835+
write!(
836+
out,
837+
"{}",
838+
out.types.resolve(efn.self_type.as_ref().unwrap()).name.cxx
839+
);
840+
} else {
841+
write_indirect_return_type(out, efn.ret.as_ref().unwrap());
842+
}
815843
write!(out, "(");
816844
} else if efn.ret.is_some() {
817845
write!(out, "return ");
818846
}
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(");
847+
if !efn.sig.constructor {
848+
match &efn.ret {
849+
Some(Type::Ref(_)) => write!(out, "&"),
850+
Some(Type::Str(_)) if !indirect_return => {
851+
out.builtin.rust_str_repr = true;
852+
write!(out, "::rust::impl<::rust::Str>::repr(");
853+
}
854+
Some(ty @ Type::SliceRef(_)) if !indirect_return => {
855+
out.builtin.rust_slice_repr = true;
856+
write!(out, "::rust::impl<");
857+
write_type(out, ty);
858+
write!(out, ">::repr(");
859+
}
860+
_ => {}
824861
}
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(");
862+
match &efn.receiver {
863+
None => write!(out, "{}$(", efn.name.rust),
864+
Some(_) => write!(out, "(self.*{}$)(", efn.name.rust),
830865
}
831-
_ => {}
832-
}
833-
match &efn.receiver {
834-
None => write!(out, "{}$(", efn.name.rust),
835-
Some(_) => write!(out, "(self.*{}$)(", efn.name.rust),
836866
}
837867
for (i, arg) in efn.args.iter().enumerate() {
838868
if i > 0 {
@@ -862,7 +892,9 @@ fn write_cxx_function_shim<'a>(out: &mut OutFile<'a>, efn: &'a ExternFn) {
862892
write!(out, "{}", arg.name.cxx);
863893
}
864894
}
865-
write!(out, ")");
895+
if !efn.sig.constructor {
896+
write!(out, ")");
897+
}
866898
match &efn.ret {
867899
Some(Type::RustBox(_)) => write!(out, ".into_raw()"),
868900
Some(Type::UniquePtr(_)) => write!(out, ".release()"),
@@ -892,27 +924,36 @@ fn write_cxx_function_shim<'a>(out: &mut OutFile<'a>, efn: &'a ExternFn) {
892924
fn write_function_pointer_trampoline(out: &mut OutFile, efn: &ExternFn, var: &Pair, f: &Signature) {
893925
let r_trampoline = mangle::r_trampoline(efn, var, out.types);
894926
let indirect_call = true;
895-
write_rust_function_decl_impl(out, &r_trampoline, f, indirect_call);
927+
write_rust_function_decl_impl(out, &r_trampoline, f, &efn.self_type, indirect_call);
896928

897929
out.next_section();
898930
let c_trampoline = mangle::c_trampoline(efn, var, out.types).to_string();
899931
let doc = Doc::new();
900-
write_rust_function_shim_impl(out, &c_trampoline, f, &efn.self_type, &doc, &r_trampoline, indirect_call);
932+
write_rust_function_shim_impl(
933+
out,
934+
&c_trampoline,
935+
f,
936+
&efn.self_type,
937+
&doc,
938+
&r_trampoline,
939+
indirect_call,
940+
);
901941
}
902942

903943
fn write_rust_function_decl<'a>(out: &mut OutFile<'a>, efn: &'a ExternFn) {
904944
out.set_namespace(&efn.name.namespace);
905945
out.begin_block(Block::ExternC);
906946
let link_name = mangle::extern_fn(efn, out.types);
907947
let indirect_call = false;
908-
write_rust_function_decl_impl(out, &link_name, efn, indirect_call);
948+
write_rust_function_decl_impl(out, &link_name, efn, &efn.self_type, indirect_call);
909949
out.end_block(Block::ExternC);
910950
}
911951

912952
fn write_rust_function_decl_impl(
913953
out: &mut OutFile,
914954
link_name: &Symbol,
915955
sig: &Signature,
956+
self_type: &Option<Ident>,
916957
indirect_call: bool,
917958
) {
918959
out.next_section();
@@ -947,15 +988,23 @@ fn write_rust_function_decl_impl(
947988
if needs_comma {
948989
write!(out, ", ");
949990
}
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 ");
991+
if sig.constructor {
992+
write!(
993+
out,
994+
"{} ",
995+
out.types.resolve(self_type.as_ref().unwrap()).name.cxx
996+
);
997+
} else {
998+
match sig.ret.as_ref().unwrap() {
999+
Type::Ref(ret) => {
1000+
write_type_space(out, &ret.inner);
1001+
if !ret.mutable {
1002+
write!(out, "const ");
1003+
}
1004+
write!(out, "*");
9551005
}
956-
write!(out, "*");
1006+
ret => write_type_space(out, ret),
9571007
}
958-
ret => write_type_space(out, ret),
9591008
}
9601009
write!(out, "*return$");
9611010
needs_comma = true;
@@ -982,7 +1031,15 @@ fn write_rust_function_shim<'a>(out: &mut OutFile<'a>, efn: &'a ExternFn) {
9821031
let doc = &efn.doc;
9831032
let invoke = mangle::extern_fn(efn, out.types);
9841033
let indirect_call = false;
985-
write_rust_function_shim_impl(out, &local_name, efn, &efn.self_type, doc, &invoke, indirect_call);
1034+
write_rust_function_shim_impl(
1035+
out,
1036+
&local_name,
1037+
efn,
1038+
&efn.self_type,
1039+
doc,
1040+
&invoke,
1041+
indirect_call,
1042+
);
9861043
}
9871044

9881045
fn write_rust_function_shim_decl(
@@ -993,12 +1050,18 @@ fn write_rust_function_shim_decl(
9931050
indirect_call: bool,
9941051
) {
9951052
begin_function_definition(out);
996-
write_return_type(out, &sig.ret);
1053+
if !sig.constructor {
1054+
write_return_type(out, &sig.ret);
1055+
}
9971056
if let Some(self_type) = self_type {
998-
write!(out, "{}::{}(", out.types.resolve(self_type).name.cxx, local_name);
1057+
let cxx_name = &out.types.resolve(self_type).name.cxx;
1058+
if sig.constructor {
1059+
write!(out, "{}::{}(", cxx_name, cxx_name);
1060+
} else {
1061+
write!(out, "{}::{}(", cxx_name, local_name);
1062+
}
9991063
} else {
10001064
write!(out, "{}(", local_name);
1001-
10021065
}
10031066
for (i, arg) in sig.args.iter().enumerate() {
10041067
if i > 0 {
@@ -1059,20 +1122,22 @@ fn write_rust_function_shim_impl(
10591122
write!(out, " ");
10601123
let indirect_return = indirect_return(sig, out.types);
10611124
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 ");
1125+
if !sig.constructor {
1126+
out.builtin.maybe_uninit = true;
1127+
write!(out, "::rust::MaybeUninit<");
1128+
match sig.ret.as_ref().unwrap() {
1129+
Type::Ref(ret) => {
1130+
write_type_space(out, &ret.inner);
1131+
if !ret.mutable {
1132+
write!(out, "const ");
1133+
}
1134+
write!(out, "*");
10691135
}
1070-
write!(out, "*");
1136+
ret => write_type(out, ret),
10711137
}
1072-
ret => write_type(out, ret),
1138+
writeln!(out, "> return$;");
1139+
write!(out, " ");
10731140
}
1074-
writeln!(out, "> return$;");
1075-
write!(out, " ");
10761141
} else if let Some(ret) = &sig.ret {
10771142
write!(out, "return ");
10781143
match ret {
@@ -1128,7 +1193,11 @@ fn write_rust_function_shim_impl(
11281193
if needs_comma {
11291194
write!(out, ", ");
11301195
}
1131-
write!(out, "&return$.value");
1196+
if sig.constructor {
1197+
write!(out, "this");
1198+
} else {
1199+
write!(out, "&return$.value");
1200+
}
11321201
needs_comma = true;
11331202
}
11341203
if indirect_call {
@@ -1152,7 +1221,7 @@ fn write_rust_function_shim_impl(
11521221
writeln!(out, " throw ::rust::impl<::rust::Error>::error(error$);");
11531222
writeln!(out, " }}");
11541223
}
1155-
if indirect_return {
1224+
if indirect_return && !sig.constructor {
11561225
write!(out, " return ");
11571226
match sig.ret.as_ref().unwrap() {
11581227
Type::Ref(_) => write!(out, "*return$.value"),
@@ -1174,9 +1243,11 @@ fn write_return_type(out: &mut OutFile, ty: &Option<Type>) {
11741243
}
11751244

11761245
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))
1246+
sig.constructor
1247+
|| sig
1248+
.ret
1249+
.as_ref()
1250+
.is_some_and(|ret| sig.throws || types.needs_indirect_abi(ret))
11801251
}
11811252

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

0 commit comments

Comments
 (0)