Skip to content

Commit 0e8a115

Browse files
committed
Support C++ constructor for shared type
1 parent 64e5e41 commit 0e8a115

File tree

13 files changed

+267
-103
lines changed

13 files changed

+267
-103
lines changed

Diff for: gen/src/write.rs

+161-89
Original file line numberDiff line numberDiff line change
@@ -271,16 +271,27 @@ 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}() noexcept = default;", strct.name.cxx);
278+
writeln!(out, " {0}({0}&&) noexcept = default;", strct.name.cxx);
279+
writeln!(out, " {0}& operator=({0}&&) noexcept = default;", strct.name.cxx);
280+
}
281+
274282
for method in methods {
275283
if !method.doc.is_empty() {
276284
out.next_section();
277285
}
278286
write_doc(out, " ", &method.doc);
279287
write!(out, " ");
280288
let sig = &method.sig;
281-
let local_name = method.name.cxx.to_string();
289+
let local_name = match (&method.self_type, sig.constructor) {
290+
(Some(self_type), true) => out.types.resolve(self_type).name.cxx.to_string(),
291+
_ => method.name.cxx.to_string(),
292+
};
282293
let indirect_call = false;
283-
if method.self_type.is_some() {
294+
if method.self_type.is_some() && !method.sig.constructor {
284295
write!(out, "static ");
285296
}
286297
write_rust_function_shim_decl(out, &local_name, sig, &None, indirect_call);
@@ -375,7 +386,7 @@ fn write_opaque_type<'a>(out: &mut OutFile<'a>, ety: &'a ExternType, methods: &[
375386
let sig = &method.sig;
376387
let local_name = method.name.cxx.to_string();
377388
let indirect_call = false;
378-
if method.self_type.is_some() {
389+
if method.self_type.is_some() && !method.sig.constructor {
379390
write!(out, "static ");
380391
}
381392
write_rust_function_shim_decl(out, &local_name, sig, &None, indirect_call);
@@ -754,51 +765,61 @@ fn write_cxx_function_shim<'a>(out: &mut OutFile<'a>, efn: &'a ExternFn) {
754765
if !efn.args.is_empty() || efn.receiver.is_some() {
755766
write!(out, ", ");
756767
}
757-
write_indirect_return_type_space(out, efn.ret.as_ref().unwrap());
768+
if efn.sig.constructor {
769+
write!(
770+
out,
771+
"{} ",
772+
out.types.resolve(efn.self_type.as_ref().unwrap()).name.cxx
773+
);
774+
} else {
775+
write_indirect_return_type_space(out, efn.ret.as_ref().unwrap());
776+
}
758777
write!(out, "*return$");
759778
}
760779
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, ", ");
780+
if !efn.sig.constructor {
781+
write!(out, " ");
782+
write_return_type(out, &efn.ret);
783+
match &efn.receiver {
784+
None => write!(out, "(*{}$)(", efn.name.rust),
785+
Some(receiver) => write!(
786+
out,
787+
"({}::*{}$)(",
788+
out.types.resolve(&receiver.ty).name.to_fully_qualified(),
789+
efn.name.rust,
790+
),
775791
}
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");
792+
for (i, arg) in efn.args.iter().enumerate() {
793+
if i > 0 {
794+
write!(out, ", ");
795+
}
796+
write_type(out, &arg.ty);
782797
}
798+
write!(out, ")");
799+
if let Some(receiver) = &efn.receiver {
800+
if !receiver.mutable {
801+
write!(out, " const");
802+
}
803+
}
804+
write!(out, " = ");
805+
match (&efn.receiver, &efn.self_type) {
806+
(None, None) => write!(out, "{}", efn.name.to_fully_qualified()),
807+
(Some(receiver), None) => write!(
808+
out,
809+
"&{}::{}",
810+
out.types.resolve(&receiver.ty).name.to_fully_qualified(),
811+
efn.name.cxx,
812+
),
813+
(None, Some(self_type)) => write!(
814+
out,
815+
"&{}::{}",
816+
out.types.resolve(self_type).name.to_fully_qualified(),
817+
efn.name.cxx,
818+
),
819+
_ => unreachable!("receiver and self_type are mutually exclusive"),
820+
}
821+
writeln!(out, ";");
783822
}
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, ";");
802823
write!(out, " ");
803824
if efn.throws {
804825
out.builtin.ptr_len = true;
@@ -811,28 +832,38 @@ fn write_cxx_function_shim<'a>(out: &mut OutFile<'a>, efn: &'a ExternFn) {
811832
if indirect_return {
812833
out.include.new = true;
813834
write!(out, "new (return$) ");
814-
write_indirect_return_type(out, efn.ret.as_ref().unwrap());
835+
if efn.sig.constructor {
836+
write!(
837+
out,
838+
"{}",
839+
out.types.resolve(efn.self_type.as_ref().unwrap()).name.cxx
840+
);
841+
} else {
842+
write_indirect_return_type(out, efn.ret.as_ref().unwrap());
843+
}
815844
write!(out, "(");
816845
} else if efn.ret.is_some() {
817846
write!(out, "return ");
818847
}
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(");
848+
if !efn.sig.constructor {
849+
match &efn.ret {
850+
Some(Type::Ref(_)) => write!(out, "&"),
851+
Some(Type::Str(_)) if !indirect_return => {
852+
out.builtin.rust_str_repr = true;
853+
write!(out, "::rust::impl<::rust::Str>::repr(");
854+
}
855+
Some(ty @ Type::SliceRef(_)) if !indirect_return => {
856+
out.builtin.rust_slice_repr = true;
857+
write!(out, "::rust::impl<");
858+
write_type(out, ty);
859+
write!(out, ">::repr(");
860+
}
861+
_ => {}
824862
}
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(");
863+
match &efn.receiver {
864+
None => write!(out, "{}$(", efn.name.rust),
865+
Some(_) => write!(out, "(self.*{}$)(", efn.name.rust),
830866
}
831-
_ => {}
832-
}
833-
match &efn.receiver {
834-
None => write!(out, "{}$(", efn.name.rust),
835-
Some(_) => write!(out, "(self.*{}$)(", efn.name.rust),
836867
}
837868
for (i, arg) in efn.args.iter().enumerate() {
838869
if i > 0 {
@@ -862,7 +893,9 @@ fn write_cxx_function_shim<'a>(out: &mut OutFile<'a>, efn: &'a ExternFn) {
862893
write!(out, "{}", arg.name.cxx);
863894
}
864895
}
865-
write!(out, ")");
896+
if !efn.sig.constructor {
897+
write!(out, ")");
898+
}
866899
match &efn.ret {
867900
Some(Type::RustBox(_)) => write!(out, ".into_raw()"),
868901
Some(Type::UniquePtr(_)) => write!(out, ".release()"),
@@ -892,27 +925,36 @@ fn write_cxx_function_shim<'a>(out: &mut OutFile<'a>, efn: &'a ExternFn) {
892925
fn write_function_pointer_trampoline(out: &mut OutFile, efn: &ExternFn, var: &Pair, f: &Signature) {
893926
let r_trampoline = mangle::r_trampoline(efn, var, out.types);
894927
let indirect_call = true;
895-
write_rust_function_decl_impl(out, &r_trampoline, f, indirect_call);
928+
write_rust_function_decl_impl(out, &r_trampoline, f, &efn.self_type, indirect_call);
896929

897930
out.next_section();
898931
let c_trampoline = mangle::c_trampoline(efn, var, out.types).to_string();
899932
let doc = Doc::new();
900-
write_rust_function_shim_impl(out, &c_trampoline, f, &efn.self_type, &doc, &r_trampoline, indirect_call);
933+
write_rust_function_shim_impl(
934+
out,
935+
&c_trampoline,
936+
f,
937+
&efn.self_type,
938+
&doc,
939+
&r_trampoline,
940+
indirect_call,
941+
);
901942
}
902943

903944
fn write_rust_function_decl<'a>(out: &mut OutFile<'a>, efn: &'a ExternFn) {
904945
out.set_namespace(&efn.name.namespace);
905946
out.begin_block(Block::ExternC);
906947
let link_name = mangle::extern_fn(efn, out.types);
907948
let indirect_call = false;
908-
write_rust_function_decl_impl(out, &link_name, efn, indirect_call);
949+
write_rust_function_decl_impl(out, &link_name, efn, &efn.self_type, indirect_call);
909950
out.end_block(Block::ExternC);
910951
}
911952

912953
fn write_rust_function_decl_impl(
913954
out: &mut OutFile,
914955
link_name: &Symbol,
915956
sig: &Signature,
957+
self_type: &Option<Ident>,
916958
indirect_call: bool,
917959
) {
918960
out.next_section();
@@ -947,15 +989,23 @@ fn write_rust_function_decl_impl(
947989
if needs_comma {
948990
write!(out, ", ");
949991
}
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 ");
992+
if sig.constructor {
993+
write!(
994+
out,
995+
"{} ",
996+
out.types.resolve(self_type.as_ref().unwrap()).name.cxx
997+
);
998+
} else {
999+
match sig.ret.as_ref().unwrap() {
1000+
Type::Ref(ret) => {
1001+
write_type_space(out, &ret.inner);
1002+
if !ret.mutable {
1003+
write!(out, "const ");
1004+
}
1005+
write!(out, "*");
9551006
}
956-
write!(out, "*");
1007+
ret => write_type_space(out, ret),
9571008
}
958-
ret => write_type_space(out, ret),
9591009
}
9601010
write!(out, "*return$");
9611011
needs_comma = true;
@@ -982,7 +1032,15 @@ fn write_rust_function_shim<'a>(out: &mut OutFile<'a>, efn: &'a ExternFn) {
9821032
let doc = &efn.doc;
9831033
let invoke = mangle::extern_fn(efn, out.types);
9841034
let indirect_call = false;
985-
write_rust_function_shim_impl(out, &local_name, efn, &efn.self_type, doc, &invoke, indirect_call);
1035+
write_rust_function_shim_impl(
1036+
out,
1037+
&local_name,
1038+
efn,
1039+
&efn.self_type,
1040+
doc,
1041+
&invoke,
1042+
indirect_call,
1043+
);
9861044
}
9871045

9881046
fn write_rust_function_shim_decl(
@@ -993,12 +1051,18 @@ fn write_rust_function_shim_decl(
9931051
indirect_call: bool,
9941052
) {
9951053
begin_function_definition(out);
996-
write_return_type(out, &sig.ret);
1054+
if !sig.constructor {
1055+
write_return_type(out, &sig.ret);
1056+
}
9971057
if let Some(self_type) = self_type {
998-
write!(out, "{}::{}(", out.types.resolve(self_type).name.cxx, local_name);
1058+
let cxx_name = &out.types.resolve(self_type).name.cxx;
1059+
if sig.constructor {
1060+
write!(out, "{}::{}(", cxx_name, cxx_name);
1061+
} else {
1062+
write!(out, "{}::{}(", cxx_name, local_name);
1063+
}
9991064
} else {
10001065
write!(out, "{}(", local_name);
1001-
10021066
}
10031067
for (i, arg) in sig.args.iter().enumerate() {
10041068
if i > 0 {
@@ -1059,20 +1123,22 @@ fn write_rust_function_shim_impl(
10591123
write!(out, " ");
10601124
let indirect_return = indirect_return(sig, out.types);
10611125
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 ");
1126+
if !sig.constructor {
1127+
out.builtin.maybe_uninit = true;
1128+
write!(out, "::rust::MaybeUninit<");
1129+
match sig.ret.as_ref().unwrap() {
1130+
Type::Ref(ret) => {
1131+
write_type_space(out, &ret.inner);
1132+
if !ret.mutable {
1133+
write!(out, "const ");
1134+
}
1135+
write!(out, "*");
10691136
}
1070-
write!(out, "*");
1137+
ret => write_type(out, ret),
10711138
}
1072-
ret => write_type(out, ret),
1139+
writeln!(out, "> return$;");
1140+
write!(out, " ");
10731141
}
1074-
writeln!(out, "> return$;");
1075-
write!(out, " ");
10761142
} else if let Some(ret) = &sig.ret {
10771143
write!(out, "return ");
10781144
match ret {
@@ -1128,7 +1194,11 @@ fn write_rust_function_shim_impl(
11281194
if needs_comma {
11291195
write!(out, ", ");
11301196
}
1131-
write!(out, "&return$.value");
1197+
if sig.constructor {
1198+
write!(out, "this");
1199+
} else {
1200+
write!(out, "&return$.value");
1201+
}
11321202
needs_comma = true;
11331203
}
11341204
if indirect_call {
@@ -1152,7 +1222,7 @@ fn write_rust_function_shim_impl(
11521222
writeln!(out, " throw ::rust::impl<::rust::Error>::error(error$);");
11531223
writeln!(out, " }}");
11541224
}
1155-
if indirect_return {
1225+
if indirect_return && !sig.constructor {
11561226
write!(out, " return ");
11571227
match sig.ret.as_ref().unwrap() {
11581228
Type::Ref(_) => write!(out, "*return$.value"),
@@ -1174,9 +1244,11 @@ fn write_return_type(out: &mut OutFile, ty: &Option<Type>) {
11741244
}
11751245

11761246
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))
1247+
sig.constructor
1248+
|| sig
1249+
.ret
1250+
.as_ref()
1251+
.is_some_and(|ret| sig.throws || types.needs_indirect_abi(ret))
11801252
}
11811253

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

0 commit comments

Comments
 (0)