Display all known reasons why type must be Trivial.

This generates multiple Rust-side and C++-side error messages
when a given opaque C++ type is being used in contexts which
allow only a Trivial type. Previously, we showed just the first
message and discarded all others.
This commit is contained in:
Adrian Taylor 2020-12-07 16:49:19 -08:00
parent 7b443f71b0
commit f831a5abcf
5 changed files with 57 additions and 26 deletions

View File

@ -117,8 +117,8 @@ fn write_data_structures<'a>(out: &mut OutFile<'a>, apis: &'a [Api]) {
out.next_section();
for api in apis {
if let Api::TypeAlias(ety) = api {
if let Some(reason) = out.types.required_trivial.get(&ety.name.rust) {
check_trivial_extern_type(out, &ety.name, reason)
if let Some(reasons) = out.types.required_trivial.get(&ety.name.rust) {
check_trivial_extern_type(out, &ety.name, reasons)
}
}
}
@ -366,7 +366,7 @@ fn check_enum<'a>(out: &mut OutFile<'a>, enm: &'a Enum) {
}
}
fn check_trivial_extern_type(out: &mut OutFile, id: &Pair, reason: &TrivialReason) {
fn check_trivial_extern_type(out: &mut OutFile, id: &Pair, reasons: &[TrivialReason]) {
// NOTE: The following static assertion is just nice-to-have and not
// necessary for soundness. That's because triviality is always declared by
// the user in the form of an unsafe impl of cxx::ExternType:
@ -402,14 +402,16 @@ fn check_trivial_extern_type(out: &mut OutFile, id: &Pair, reason: &TrivialReaso
let id = id.to_fully_qualified();
out.builtin.relocatable = true;
writeln!(out, "static_assert(");
writeln!(out, " ::rust::IsRelocatable<{}>::value,", id);
writeln!(
out,
" \"type {} is not move constructible and trivially destructible in C++ yet is used as a trivial type in Rust ({})\");",
id,
reason
);
for reason in reasons {
writeln!(out, "static_assert(");
writeln!(out, " ::rust::IsRelocatable<{}>::value,", id);
writeln!(
out,
" \"type {} is not move constructible and trivially destructible in C++ yet is used as a trivial type in Rust ({})\");",
id,
reason
);
}
}
fn write_struct_operator_decls<'a>(out: &mut OutFile<'a>, strct: &'a Struct) {

View File

@ -324,13 +324,15 @@ fn check_api_type(cx: &mut Check, ety: &ExternType) {
cx.error(span, "extern type bounds are not implemented yet");
}
if let Some(reason) = cx.types.required_trivial.get(&ety.name.rust) {
let what = reason.describe_in_context(&ety);
let msg = format!(
"needs a cxx::ExternType impl in order to be used as {}",
what,
);
cx.error(ety, msg);
if let Some(reasons) = cx.types.required_trivial.get(&ety.name.rust) {
for reason in reasons {
let what = reason.describe_in_context(&ety);
let msg = format!(
"needs a cxx::ExternType impl in order to be used as {}",
what,
);
cx.error(ety, msg);
}
}
}

View File

@ -18,7 +18,7 @@ pub struct Types<'a> {
pub rust: Set<&'a Ident>,
pub aliases: Map<&'a Ident, &'a TypeAlias>,
pub untrusted: Map<&'a Ident, &'a ExternType>,
pub required_trivial: Map<&'a Ident, TrivialReason<'a>>,
pub required_trivial: Map<&'a Ident, Vec<TrivialReason<'a>>>,
pub explicit_impls: Set<&'a Impl>,
pub resolutions: Map<&'a RustName, &'a Pair>,
pub struct_improper_ctypes: UnorderedSet<&'a Ident>,
@ -169,14 +169,17 @@ impl<'a> Types<'a> {
// we check that this is permissible. We do this _after_ scanning all
// the APIs above, in case some function or struct references a type
// which is declared subsequently.
let mut required_trivial = Map::new();
let mut required_trivial: Map<_, Vec<_>> = Map::new();
let mut insist_extern_types_are_trivial = |ident: &'a RustName, reason| {
if cxx.contains(&ident.rust)
&& !structs.contains_key(&ident.rust)
&& !enums.contains_key(&ident.rust)
{
required_trivial.entry(&ident.rust).or_insert(reason);
required_trivial
.entry(&ident.rust)
.or_default()
.push(reason);
}
};
for api in apis {

View File

@ -22,6 +22,18 @@ error: needs a cxx::ExternType impl in order to be used as a field of `S`
10 | type C;
| ^^^^^^
error: needs a cxx::ExternType impl in order to be used as an argument of `f`
--> $DIR/by_value_not_supported.rs:10:9
|
10 | type C;
| ^^^^^^
error: needs a cxx::ExternType impl in order to be used as a return value of `f`
--> $DIR/by_value_not_supported.rs:10:9
|
10 | type C;
| ^^^^^^
error: passing opaque C++ type by value is not supported
--> $DIR/by_value_not_supported.rs:16:14
|

View File

@ -1,16 +1,16 @@
error: mutable reference to C++ type requires a pin -- use Pin<&mut Opaque>
error: mutable reference to C++ type requires a pin -- use Pin<&mut Opaque> or declare the type Trivial in a cxx::ExternType impl
--> $DIR/pin_mut_opaque.rs:5:19
|
5 | fn f(arg: &mut Opaque);
| ^^^^^^^^^^^
error: mutable reference to C++ type requires a pin -- use Pin<&mut CxxString>
error: mutable reference to C++ type requires a pin -- use Pin<&mut CxxString> or declare the type Trivial in a cxx::ExternType impl
--> $DIR/pin_mut_opaque.rs:8:17
|
8 | fn s(s: &mut CxxString);
| ^^^^^^^^^^^^^^
error: mutable reference to C++ type requires a pin -- use Pin<&mut CxxVector<...>>
error: mutable reference to C++ type requires a pin -- use Pin<&mut CxxVector<...>> or declare the type Trivial in a cxx::ExternType impl
--> $DIR/pin_mut_opaque.rs:9:17
|
9 | fn v(v: &mut CxxVector<u8>);
@ -22,13 +22,25 @@ error: needs a cxx::ExternType impl in order to be used as a non-pinned mutable
4 | type Opaque;
| ^^^^^^^^^^^
error: mutable reference to C++ type requires a pin -- use `self: Pin<&mut Opaque>`
error: needs a cxx::ExternType impl in order to be used as a non-pinned mutable reference argument of g
--> $DIR/pin_mut_opaque.rs:4:9
|
4 | type Opaque;
| ^^^^^^^^^^^
error: needs a cxx::ExternType impl in order to be used as a non-pinned mutable reference argument of h
--> $DIR/pin_mut_opaque.rs:4:9
|
4 | type Opaque;
| ^^^^^^^^^^^
error: mutable reference to opaque C++ type requires a pin -- use `self: Pin<&mut Opaque>` or declare the type Trivial in a cxx::ExternType impl
--> $DIR/pin_mut_opaque.rs:6:14
|
6 | fn g(&mut self);
| ^^^^^^^^^
error: mutable reference to C++ type requires a pin -- use `self: Pin<&mut Opaque>`
error: mutable reference to opaque C++ type requires a pin -- use `self: Pin<&mut Opaque>` or declare the type Trivial in a cxx::ExternType impl
--> $DIR/pin_mut_opaque.rs:7:20
|
7 | fn h(self: &mut Opaque);