Skip to content

Commit 5de0a5c

Browse files
committed
Support C++ constructor for shared type
1 parent 64e5e41 commit 5de0a5c

File tree

10 files changed

+225
-101
lines changed

10 files changed

+225
-101
lines changed

Diff for: gen/src/write.rs

+153-89
Original file line numberDiff line numberDiff line change
@@ -278,9 +278,12 @@ fn write_struct<'a>(out: &mut OutFile<'a>, strct: &'a Struct, methods: &[&Extern
278278
write_doc(out, " ", &method.doc);
279279
write!(out, " ");
280280
let sig = &method.sig;
281-
let local_name = method.name.cxx.to_string();
281+
let local_name = match (&method.self_type, sig.constructor) {
282+
(Some(self_type), true) => out.types.resolve(self_type).name.cxx.to_string(),
283+
_ => method.name.cxx.to_string(),
284+
};
282285
let indirect_call = false;
283-
if method.self_type.is_some() {
286+
if method.self_type.is_some() && !method.sig.constructor {
284287
write!(out, "static ");
285288
}
286289
write_rust_function_shim_decl(out, &local_name, sig, &None, indirect_call);
@@ -375,7 +378,7 @@ fn write_opaque_type<'a>(out: &mut OutFile<'a>, ety: &'a ExternType, methods: &[
375378
let sig = &method.sig;
376379
let local_name = method.name.cxx.to_string();
377380
let indirect_call = false;
378-
if method.self_type.is_some() {
381+
if method.self_type.is_some() && !method.sig.constructor {
379382
write!(out, "static ");
380383
}
381384
write_rust_function_shim_decl(out, &local_name, sig, &None, indirect_call);
@@ -754,51 +757,61 @@ fn write_cxx_function_shim<'a>(out: &mut OutFile<'a>, efn: &'a ExternFn) {
754757
if !efn.args.is_empty() || efn.receiver.is_some() {
755758
write!(out, ", ");
756759
}
757-
write_indirect_return_type_space(out, efn.ret.as_ref().unwrap());
760+
if efn.sig.constructor {
761+
write!(
762+
out,
763+
"{} ",
764+
out.types.resolve(efn.self_type.as_ref().unwrap()).name.cxx
765+
);
766+
} else {
767+
write_indirect_return_type_space(out, efn.ret.as_ref().unwrap());
768+
}
758769
write!(out, "*return$");
759770
}
760771
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, ", ");
772+
if !efn.sig.constructor {
773+
write!(out, " ");
774+
write_return_type(out, &efn.ret);
775+
match &efn.receiver {
776+
None => write!(out, "(*{}$)(", efn.name.rust),
777+
Some(receiver) => write!(
778+
out,
779+
"({}::*{}$)(",
780+
out.types.resolve(&receiver.ty).name.to_fully_qualified(),
781+
efn.name.rust,
782+
),
775783
}
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");
784+
for (i, arg) in efn.args.iter().enumerate() {
785+
if i > 0 {
786+
write!(out, ", ");
787+
}
788+
write_type(out, &arg.ty);
782789
}
790+
write!(out, ")");
791+
if let Some(receiver) = &efn.receiver {
792+
if !receiver.mutable {
793+
write!(out, " const");
794+
}
795+
}
796+
write!(out, " = ");
797+
match (&efn.receiver, &efn.self_type) {
798+
(None, None) => write!(out, "{}", efn.name.to_fully_qualified()),
799+
(Some(receiver), None) => write!(
800+
out,
801+
"&{}::{}",
802+
out.types.resolve(&receiver.ty).name.to_fully_qualified(),
803+
efn.name.cxx,
804+
),
805+
(None, Some(self_type)) => write!(
806+
out,
807+
"&{}::{}",
808+
out.types.resolve(self_type).name.to_fully_qualified(),
809+
efn.name.cxx,
810+
),
811+
_ => unreachable!("receiver and self_type are mutually exclusive"),
812+
}
813+
writeln!(out, ";");
783814
}
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, ";");
802815
write!(out, " ");
803816
if efn.throws {
804817
out.builtin.ptr_len = true;
@@ -811,28 +824,38 @@ fn write_cxx_function_shim<'a>(out: &mut OutFile<'a>, efn: &'a ExternFn) {
811824
if indirect_return {
812825
out.include.new = true;
813826
write!(out, "new (return$) ");
814-
write_indirect_return_type(out, efn.ret.as_ref().unwrap());
827+
if efn.sig.constructor {
828+
write!(
829+
out,
830+
"{}",
831+
out.types.resolve(efn.self_type.as_ref().unwrap()).name.cxx
832+
);
833+
} else {
834+
write_indirect_return_type(out, efn.ret.as_ref().unwrap());
835+
}
815836
write!(out, "(");
816837
} else if efn.ret.is_some() {
817838
write!(out, "return ");
818839
}
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(");
840+
if !efn.sig.constructor {
841+
match &efn.ret {
842+
Some(Type::Ref(_)) => write!(out, "&"),
843+
Some(Type::Str(_)) if !indirect_return => {
844+
out.builtin.rust_str_repr = true;
845+
write!(out, "::rust::impl<::rust::Str>::repr(");
846+
}
847+
Some(ty @ Type::SliceRef(_)) if !indirect_return => {
848+
out.builtin.rust_slice_repr = true;
849+
write!(out, "::rust::impl<");
850+
write_type(out, ty);
851+
write!(out, ">::repr(");
852+
}
853+
_ => {}
824854
}
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(");
855+
match &efn.receiver {
856+
None => write!(out, "{}$(", efn.name.rust),
857+
Some(_) => write!(out, "(self.*{}$)(", efn.name.rust),
830858
}
831-
_ => {}
832-
}
833-
match &efn.receiver {
834-
None => write!(out, "{}$(", efn.name.rust),
835-
Some(_) => write!(out, "(self.*{}$)(", efn.name.rust),
836859
}
837860
for (i, arg) in efn.args.iter().enumerate() {
838861
if i > 0 {
@@ -862,7 +885,9 @@ fn write_cxx_function_shim<'a>(out: &mut OutFile<'a>, efn: &'a ExternFn) {
862885
write!(out, "{}", arg.name.cxx);
863886
}
864887
}
865-
write!(out, ")");
888+
if !efn.sig.constructor {
889+
write!(out, ")");
890+
}
866891
match &efn.ret {
867892
Some(Type::RustBox(_)) => write!(out, ".into_raw()"),
868893
Some(Type::UniquePtr(_)) => write!(out, ".release()"),
@@ -892,27 +917,36 @@ fn write_cxx_function_shim<'a>(out: &mut OutFile<'a>, efn: &'a ExternFn) {
892917
fn write_function_pointer_trampoline(out: &mut OutFile, efn: &ExternFn, var: &Pair, f: &Signature) {
893918
let r_trampoline = mangle::r_trampoline(efn, var, out.types);
894919
let indirect_call = true;
895-
write_rust_function_decl_impl(out, &r_trampoline, f, indirect_call);
920+
write_rust_function_decl_impl(out, &r_trampoline, f, &efn.self_type, indirect_call);
896921

897922
out.next_section();
898923
let c_trampoline = mangle::c_trampoline(efn, var, out.types).to_string();
899924
let doc = Doc::new();
900-
write_rust_function_shim_impl(out, &c_trampoline, f, &efn.self_type, &doc, &r_trampoline, indirect_call);
925+
write_rust_function_shim_impl(
926+
out,
927+
&c_trampoline,
928+
f,
929+
&efn.self_type,
930+
&doc,
931+
&r_trampoline,
932+
indirect_call,
933+
);
901934
}
902935

903936
fn write_rust_function_decl<'a>(out: &mut OutFile<'a>, efn: &'a ExternFn) {
904937
out.set_namespace(&efn.name.namespace);
905938
out.begin_block(Block::ExternC);
906939
let link_name = mangle::extern_fn(efn, out.types);
907940
let indirect_call = false;
908-
write_rust_function_decl_impl(out, &link_name, efn, indirect_call);
941+
write_rust_function_decl_impl(out, &link_name, efn, &efn.self_type, indirect_call);
909942
out.end_block(Block::ExternC);
910943
}
911944

912945
fn write_rust_function_decl_impl(
913946
out: &mut OutFile,
914947
link_name: &Symbol,
915948
sig: &Signature,
949+
self_type: &Option<Ident>,
916950
indirect_call: bool,
917951
) {
918952
out.next_section();
@@ -947,15 +981,23 @@ fn write_rust_function_decl_impl(
947981
if needs_comma {
948982
write!(out, ", ");
949983
}
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 ");
984+
if sig.constructor {
985+
write!(
986+
out,
987+
"{} ",
988+
out.types.resolve(self_type.as_ref().unwrap()).name.cxx
989+
);
990+
} else {
991+
match sig.ret.as_ref().unwrap() {
992+
Type::Ref(ret) => {
993+
write_type_space(out, &ret.inner);
994+
if !ret.mutable {
995+
write!(out, "const ");
996+
}
997+
write!(out, "*");
955998
}
956-
write!(out, "*");
999+
ret => write_type_space(out, ret),
9571000
}
958-
ret => write_type_space(out, ret),
9591001
}
9601002
write!(out, "*return$");
9611003
needs_comma = true;
@@ -982,7 +1024,15 @@ fn write_rust_function_shim<'a>(out: &mut OutFile<'a>, efn: &'a ExternFn) {
9821024
let doc = &efn.doc;
9831025
let invoke = mangle::extern_fn(efn, out.types);
9841026
let indirect_call = false;
985-
write_rust_function_shim_impl(out, &local_name, efn, &efn.self_type, doc, &invoke, indirect_call);
1027+
write_rust_function_shim_impl(
1028+
out,
1029+
&local_name,
1030+
efn,
1031+
&efn.self_type,
1032+
doc,
1033+
&invoke,
1034+
indirect_call,
1035+
);
9861036
}
9871037

9881038
fn write_rust_function_shim_decl(
@@ -993,12 +1043,18 @@ fn write_rust_function_shim_decl(
9931043
indirect_call: bool,
9941044
) {
9951045
begin_function_definition(out);
996-
write_return_type(out, &sig.ret);
1046+
if !sig.constructor {
1047+
write_return_type(out, &sig.ret);
1048+
}
9971049
if let Some(self_type) = self_type {
998-
write!(out, "{}::{}(", out.types.resolve(self_type).name.cxx, local_name);
1050+
let cxx_name = &out.types.resolve(self_type).name.cxx;
1051+
if sig.constructor {
1052+
write!(out, "{}::{}(", cxx_name, cxx_name);
1053+
} else {
1054+
write!(out, "{}::{}(", cxx_name, local_name);
1055+
}
9991056
} else {
10001057
write!(out, "{}(", local_name);
1001-
10021058
}
10031059
for (i, arg) in sig.args.iter().enumerate() {
10041060
if i > 0 {
@@ -1059,20 +1115,22 @@ fn write_rust_function_shim_impl(
10591115
write!(out, " ");
10601116
let indirect_return = indirect_return(sig, out.types);
10611117
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 ");
1118+
if !sig.constructor {
1119+
out.builtin.maybe_uninit = true;
1120+
write!(out, "::rust::MaybeUninit<");
1121+
match sig.ret.as_ref().unwrap() {
1122+
Type::Ref(ret) => {
1123+
write_type_space(out, &ret.inner);
1124+
if !ret.mutable {
1125+
write!(out, "const ");
1126+
}
1127+
write!(out, "*");
10691128
}
1070-
write!(out, "*");
1129+
ret => write_type(out, ret),
10711130
}
1072-
ret => write_type(out, ret),
1131+
writeln!(out, "> return$;");
1132+
write!(out, " ");
10731133
}
1074-
writeln!(out, "> return$;");
1075-
write!(out, " ");
10761134
} else if let Some(ret) = &sig.ret {
10771135
write!(out, "return ");
10781136
match ret {
@@ -1128,7 +1186,11 @@ fn write_rust_function_shim_impl(
11281186
if needs_comma {
11291187
write!(out, ", ");
11301188
}
1131-
write!(out, "&return$.value");
1189+
if sig.constructor {
1190+
write!(out, "this");
1191+
} else {
1192+
write!(out, "&return$.value");
1193+
}
11321194
needs_comma = true;
11331195
}
11341196
if indirect_call {
@@ -1152,7 +1214,7 @@ fn write_rust_function_shim_impl(
11521214
writeln!(out, " throw ::rust::impl<::rust::Error>::error(error$);");
11531215
writeln!(out, " }}");
11541216
}
1155-
if indirect_return {
1217+
if indirect_return && !sig.constructor {
11561218
write!(out, " return ");
11571219
match sig.ret.as_ref().unwrap() {
11581220
Type::Ref(_) => write!(out, "*return$.value"),
@@ -1174,9 +1236,11 @@ fn write_return_type(out: &mut OutFile, ty: &Option<Type>) {
11741236
}
11751237

11761238
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))
1239+
sig.constructor
1240+
|| sig
1241+
.ret
1242+
.as_ref()
1243+
.is_some_and(|ret| sig.throws || types.needs_indirect_abi(ret))
11801244
}
11811245

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

0 commit comments

Comments
 (0)