mirror of
https://gitee.com/openharmony/third_party_rust_cxx
synced 2025-02-06 06:07:39 +00:00
Pass Str in PtrLen representation
MSVC is hesitant about passing private fields in an extern "C" signature. Repro: struct Str1 { const char *ptr; size_t len; }; struct Str2 { private: const char *ptr; size_t len; }; extern "C" { Str1 str1(); Str2 str2(); } Warning from MSVC v19.27: warning C4190: 'str2' has C-linkage specified, but returns UDT 'Str2' which is incompatible with C
This commit is contained in:
parent
54742b7ced
commit
0356d33acb
@ -324,7 +324,7 @@ fn write_include_cxxbridge(out: &mut OutFile, apis: &[Api]) {
|
||||
|
||||
out.begin_block("namespace");
|
||||
|
||||
if needs_trycatch || needs_rust_error {
|
||||
if needs_trycatch || needs_rust_error || needs_rust_str && !out.header {
|
||||
out.begin_block("namespace repr");
|
||||
writeln!(out, "struct PtrLen final {{");
|
||||
writeln!(out, " const void *ptr;");
|
||||
@ -333,7 +333,28 @@ fn write_include_cxxbridge(out: &mut OutFile, apis: &[Api]) {
|
||||
out.end_block("namespace repr");
|
||||
}
|
||||
|
||||
if needs_rust_str && !out.header {
|
||||
out.next_section();
|
||||
writeln!(out, "template <>");
|
||||
writeln!(out, "class impl<Str> final {{");
|
||||
writeln!(out, "public:");
|
||||
writeln!(
|
||||
out,
|
||||
" static Str new_unchecked(repr::PtrLen repr) noexcept {{",
|
||||
);
|
||||
writeln!(out, " Str str;");
|
||||
writeln!(out, " str.ptr = static_cast<const char *>(repr.ptr);");
|
||||
writeln!(out, " str.len = repr.len;");
|
||||
writeln!(out, " return str;");
|
||||
writeln!(out, " }}");
|
||||
writeln!(out, " static repr::PtrLen repr(Str str) noexcept {{");
|
||||
writeln!(out, " return repr::PtrLen{{str.ptr, str.len}};");
|
||||
writeln!(out, " }}");
|
||||
writeln!(out, "}};");
|
||||
}
|
||||
|
||||
if needs_rust_error {
|
||||
out.next_section();
|
||||
writeln!(out, "template <>");
|
||||
writeln!(out, "class impl<Error> final {{");
|
||||
writeln!(out, "public:");
|
||||
@ -619,6 +640,7 @@ fn write_cxx_function_shim(out: &mut OutFile, efn: &ExternFn, impl_annotations:
|
||||
}
|
||||
match &efn.ret {
|
||||
Some(Type::Ref(_)) => write!(out, "&"),
|
||||
Some(Type::Str(_)) if !indirect_return => write!(out, "::rust::impl<::rust::Str>::repr("),
|
||||
Some(Type::SliceRefU8(_)) if !indirect_return => {
|
||||
write!(out, "::rust::Slice<uint8_t>::Repr(")
|
||||
}
|
||||
@ -638,6 +660,12 @@ fn write_cxx_function_shim(out: &mut OutFile, efn: &ExternFn, impl_annotations:
|
||||
} else if let Type::UniquePtr(_) = &arg.ty {
|
||||
write_type(out, &arg.ty);
|
||||
write!(out, "({})", arg.ident);
|
||||
} else if let Type::Str(_) = arg.ty {
|
||||
write!(
|
||||
out,
|
||||
"::rust::impl<::rust::Str>::new_unchecked({})",
|
||||
arg.ident,
|
||||
);
|
||||
} else if arg.ty == RustString {
|
||||
write!(
|
||||
out,
|
||||
@ -658,7 +686,7 @@ fn write_cxx_function_shim(out: &mut OutFile, efn: &ExternFn, impl_annotations:
|
||||
match &efn.ret {
|
||||
Some(Type::RustBox(_)) => write!(out, ".into_raw()"),
|
||||
Some(Type::UniquePtr(_)) => write!(out, ".release()"),
|
||||
Some(Type::SliceRefU8(_)) if !indirect_return => write!(out, ")"),
|
||||
Some(Type::Str(_)) | Some(Type::SliceRefU8(_)) if !indirect_return => write!(out, ")"),
|
||||
_ => {}
|
||||
}
|
||||
if indirect_return {
|
||||
@ -850,6 +878,7 @@ fn write_rust_function_shim_impl(
|
||||
write!(out, "(");
|
||||
}
|
||||
Type::Ref(_) => write!(out, "*"),
|
||||
Type::Str(_) => write!(out, "::rust::impl<::rust::Str>::new_unchecked("),
|
||||
_ => {}
|
||||
}
|
||||
}
|
||||
@ -865,6 +894,7 @@ fn write_rust_function_shim_impl(
|
||||
write!(out, ", ");
|
||||
}
|
||||
match &arg.ty {
|
||||
Type::Str(_) => write!(out, "::rust::impl<::rust::Str>::repr("),
|
||||
Type::SliceRefU8(_) => write!(out, "::rust::Slice<uint8_t>::Repr("),
|
||||
ty if out.types.needs_indirect_abi(ty) => write!(out, "&"),
|
||||
_ => {}
|
||||
@ -873,7 +903,7 @@ fn write_rust_function_shim_impl(
|
||||
match &arg.ty {
|
||||
Type::RustBox(_) => write!(out, ".into_raw()"),
|
||||
Type::UniquePtr(_) => write!(out, ".release()"),
|
||||
Type::SliceRefU8(_) => write!(out, ")"),
|
||||
Type::Str(_) | Type::SliceRefU8(_) => write!(out, ")"),
|
||||
ty if ty != RustString && out.types.needs_indirect_abi(ty) => write!(out, "$.value"),
|
||||
_ => {}
|
||||
}
|
||||
@ -893,7 +923,7 @@ fn write_rust_function_shim_impl(
|
||||
write!(out, ")");
|
||||
if !indirect_return {
|
||||
if let Some(ret) = &sig.ret {
|
||||
if let Type::RustBox(_) | Type::UniquePtr(_) = ret {
|
||||
if let Type::RustBox(_) | Type::UniquePtr(_) | Type::Str(_) = ret {
|
||||
write!(out, ")");
|
||||
}
|
||||
}
|
||||
@ -964,6 +994,7 @@ fn write_extern_return_type_space(out: &mut OutFile, ty: &Option<Type>) {
|
||||
write_type(out, &ty.inner);
|
||||
write!(out, " *");
|
||||
}
|
||||
Some(Type::Str(_)) => write!(out, "::rust::repr::PtrLen "),
|
||||
Some(Type::SliceRefU8(_)) => write!(out, "::rust::Slice<uint8_t>::Repr "),
|
||||
Some(ty) if out.types.needs_indirect_abi(ty) => write!(out, "void "),
|
||||
_ => write_return_type(out, ty),
|
||||
@ -976,6 +1007,7 @@ fn write_extern_arg(out: &mut OutFile, arg: &Var) {
|
||||
write_type_space(out, &ty.inner);
|
||||
write!(out, "*");
|
||||
}
|
||||
Type::Str(_) => write!(out, "::rust::repr::PtrLen "),
|
||||
Type::SliceRefU8(_) => write!(out, "::rust::Slice<uint8_t>::Repr "),
|
||||
_ => write_type_space(out, &arg.ty),
|
||||
}
|
||||
|
@ -79,6 +79,7 @@ public:
|
||||
~Str() noexcept = default;
|
||||
|
||||
private:
|
||||
friend impl<Str>;
|
||||
// Not necessarily ABI compatible with &str. Codegen will translate to
|
||||
// cxx::rust_str::RustStr which matches this layout.
|
||||
const char *ptr;
|
||||
|
@ -18,7 +18,7 @@ fn test_extern_c_function() {
|
||||
let output = str::from_utf8(&generated.implementation).unwrap();
|
||||
// To avoid continual breakage we won't test every byte.
|
||||
// Let's look for the major features.
|
||||
assert!(output.contains("void cxxbridge05$do_cpp_thing(::rust::Str foo)"));
|
||||
assert!(output.contains("void cxxbridge05$do_cpp_thing(::rust::repr::PtrLen foo)"));
|
||||
}
|
||||
|
||||
#[test]
|
||||
@ -28,5 +28,5 @@ fn test_impl_annotation() {
|
||||
let source = BRIDGE0.parse().unwrap();
|
||||
let generated = generate_header_and_cc(source, &opt).unwrap();
|
||||
let output = str::from_utf8(&generated.implementation).unwrap();
|
||||
assert!(output.contains("ANNOTATION void cxxbridge05$do_cpp_thing(::rust::Str foo)"));
|
||||
assert!(output.contains("ANNOTATION void cxxbridge05$do_cpp_thing(::rust::repr::PtrLen foo)"));
|
||||
}
|
||||
|
Loading…
x
Reference in New Issue
Block a user