Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Recognize C array of relocatable element type in struct as relocatable #1021

Merged
merged 2 commits into from Mar 8, 2022
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Jump to
Jump to file
Failed to load files.
Diff view
Diff view
17 changes: 17 additions & 0 deletions gen/src/builtin.rs
Expand Up @@ -28,6 +28,7 @@ pub struct Builtins<'a> {
pub rust_slice_repr: bool,
pub exception: bool,
pub relocatable: bool,
pub relocatable_or_array: bool,
pub friend_impl: bool,
pub is_complete: bool,
pub destroy: bool,
Expand Down Expand Up @@ -113,6 +114,11 @@ pub(super) fn write(out: &mut OutFile) {
include.sys_types = true;
}

if builtin.relocatable_or_array {
include.cstddef = true;
builtin.relocatable = true;
}

if builtin.relocatable {
include.type_traits = true;
}
Expand Down Expand Up @@ -357,6 +363,17 @@ pub(super) fn write(out: &mut OutFile) {
writeln!(out, "}};");
}

if builtin.relocatable_or_array {
out.next_section();
writeln!(out, "template <typename T>");
writeln!(out, "struct IsRelocatableOrArray : IsRelocatable<T> {{}};");
writeln!(out, "template <typename T, ::std::size_t N>");
writeln!(
out,
"struct IsRelocatableOrArray<T[N]> : IsRelocatableOrArray<T> {{}};",
);
}

out.end_block(Block::AnonymousNamespace);
out.end_block(Block::InlineNamespace("cxxbridge1"));

Expand Down
20 changes: 19 additions & 1 deletion gen/src/write.rs
Expand Up @@ -470,7 +470,25 @@ fn check_trivial_extern_type(out: &mut OutFile, alias: &TypeAlias, reasons: &[Tr
let id = alias.name.to_fully_qualified();
out.builtin.relocatable = true;
writeln!(out, "static_assert(");
writeln!(out, " ::rust::IsRelocatable<{}>::value,", id);
if reasons
.iter()
.all(|r| matches!(r, TrivialReason::StructField(_)))
{
// If the type is only used as a struct field and not as by-value
// function argument or any other use, then C array of trivially
// relocatable type is also permissible.
//
// --- means something sane:
// struct T { char buf[N]; };
//
// --- means something totally different:
// void f(char buf[N]);
//
out.builtin.relocatable_or_array = true;
writeln!(out, " ::rust::IsRelocatableOrArray<{}>::value,", id);
} else {
writeln!(out, " ::rust::IsRelocatable<{}>::value,", id);
}
writeln!(
out,
" \"type {} should be trivially move constructible and trivially destructible in C++ to be used as {} in Rust\");",
Expand Down
16 changes: 15 additions & 1 deletion tests/ffi/lib.rs
Expand Up @@ -15,7 +15,7 @@
pub mod cast;
pub mod module;

use cxx::{CxxString, CxxVector, SharedPtr, UniquePtr};
use cxx::{type_id, CxxString, CxxVector, ExternType, SharedPtr, UniquePtr};
use std::fmt::{self, Display};
use std::mem::MaybeUninit;
use std::os::raw::c_char;
Expand Down Expand Up @@ -80,6 +80,7 @@ pub mod ffi {

pub struct Array {
a: [i32; 4],
b: Buffer,
}

#[derive(Copy, Clone, Debug, Default, Eq, Hash, Ord, PartialEq, PartialOrd)]
Expand Down Expand Up @@ -248,6 +249,10 @@ pub mod ffi {
CVal2,
}

extern "C++" {
type Buffer = crate::Buffer;
}

extern "Rust" {
type R;

Expand Down Expand Up @@ -412,6 +417,15 @@ impl ffi::Array {
}
}

#[derive(Default)]
#[repr(C)]
pub struct Buffer([c_char; 12]);

unsafe impl ExternType for Buffer {
type Id = type_id!("tests::Buffer");
type Kind = cxx::kind::Trivial;
}

#[derive(Debug)]
struct Error;

Expand Down
2 changes: 2 additions & 0 deletions tests/ffi/tests.h
Expand Up @@ -84,6 +84,8 @@ struct Borrow {
const std::string &s;
};

typedef char Buffer[12];

size_t c_return_primitive();
Shared c_return_shared();
::A::AShared c_return_ns_shared();
Expand Down
5 changes: 4 additions & 1 deletion tests/test.rs
Expand Up @@ -261,7 +261,10 @@ fn test_c_method_calls() {
assert_eq!(2023, *ffi::Shared { z: 2023 }.c_method_mut_on_shared());

let val = 42;
let mut array = ffi::Array { a: [0, 0, 0, 0] };
let mut array = ffi::Array {
a: [0, 0, 0, 0],
b: ffi::Buffer::default(),
};
array.c_set_array(val);
assert_eq!(array.a.len() as i32 * val, array.r_get_array_sum());
}
Expand Down