From 20cb73ae6fbcaba7620eced7350539f2e70c2e29 Mon Sep 17 00:00:00 2001 From: David Tolnay Date: Fri, 23 Jul 2021 14:09:33 -0700 Subject: [PATCH] Support slice of trivial extern type alias --- syntax/check.rs | 4 +- syntax/trivial.rs | 57 ++++++++++++++++++++++++++++- tests/ui/slice_of_type_alias.rs | 30 +++++++++++++++ tests/ui/slice_of_type_alias.stderr | 10 +++++ tests/ui/slice_unsupported.stderr | 6 +++ 5 files changed, 105 insertions(+), 2 deletions(-) create mode 100644 tests/ui/slice_of_type_alias.rs create mode 100644 tests/ui/slice_of_type_alias.stderr diff --git a/syntax/check.rs b/syntax/check.rs index 38be4b64..698782f9 100644 --- a/syntax/check.rs +++ b/syntax/check.rs @@ -266,7 +266,9 @@ fn check_type_ptr(cx: &mut Check, ty: &Ptr) { fn check_type_slice_ref(cx: &mut Check, ty: &SliceRef) { let supported = !is_unsized(cx, &ty.inner) || match &ty.inner { - Type::Ident(ident) => cx.types.rust.contains(&ident.rust), + Type::Ident(ident) => { + cx.types.rust.contains(&ident.rust) || cx.types.aliases.contains_key(&ident.rust) + } _ => false, }; diff --git a/syntax/trivial.rs b/syntax/trivial.rs index fe95e2b7..067e2d75 100644 --- a/syntax/trivial.rs +++ b/syntax/trivial.rs @@ -11,6 +11,7 @@ pub enum TrivialReason<'a> { FunctionReturn(&'a ExternFn), BoxTarget, VecElement, + SliceElement { mutable: bool }, UnpinnedMut(&'a ExternFn), } @@ -105,6 +106,14 @@ pub fn required_trivial_reasons<'a>( insist_extern_types_are_trivial(ident, reason); } } + Type::SliceRef(ty) => { + if let Type::Ident(ident) = &ty.inner { + let reason = TrivialReason::SliceElement { + mutable: ty.mutable, + }; + insist_extern_types_are_trivial(ident, reason); + } + } _ => {} } } @@ -128,6 +137,8 @@ pub fn as_what<'a>(name: &'a Pair, reasons: &'a [TrivialReason]) -> impl Display let mut return_of = Set::new(); let mut box_target = false; let mut vec_element = false; + let mut slice_shared_element = false; + let mut slice_mut_element = false; let mut unpinned_mut = Set::new(); for reason in self.reasons { @@ -143,6 +154,13 @@ pub fn as_what<'a>(name: &'a Pair, reasons: &'a [TrivialReason]) -> impl Display } TrivialReason::BoxTarget => box_target = true, TrivialReason::VecElement => vec_element = true, + TrivialReason::SliceElement { mutable } => { + if *mutable { + slice_mut_element = true; + } else { + slice_shared_element = true; + } + } TrivialReason::UnpinnedMut(efn) => { unpinned_mut.insert(&efn.name.rust); } @@ -185,6 +203,15 @@ pub fn as_what<'a>(name: &'a Pair, reasons: &'a [TrivialReason]) -> impl Display param: self.name, }); } + if slice_shared_element || slice_mut_element { + clauses.push(Clause::Slice { + article: "a", + desc: "slice element in", + shared: slice_shared_element, + mutable: slice_mut_element, + param: self.name, + }); + } if !unpinned_mut.is_empty() { clauses.push(Clause::Set { article: "a", @@ -219,12 +246,21 @@ pub fn as_what<'a>(name: &'a Pair, reasons: &'a [TrivialReason]) -> impl Display desc: &'a str, param: &'a Pair, }, + Slice { + article: &'a str, + desc: &'a str, + shared: bool, + mutable: bool, + param: &'a Pair, + }, } impl<'a> Clause<'a> { fn article(&self) -> &'a str { match self { - Clause::Set { article, .. } | Clause::Ty1 { article, .. } => article, + Clause::Set { article, .. } + | Clause::Ty1 { article, .. } + | Clause::Slice { article, .. } => article, } } @@ -249,6 +285,25 @@ pub fn as_what<'a>(name: &'a Pair, reasons: &'a [TrivialReason]) -> impl Display desc, param, } => write!(f, "{}<{}>", desc, param.rust), + Clause::Slice { + article: _, + desc, + shared, + mutable, + param, + } => { + write!(f, "{} ", desc)?; + if *shared { + write!(f, "&[{}]", param.rust)?; + } + if *shared && *mutable { + write!(f, " and ")?; + } + if *mutable { + write!(f, "&mut [{}]", param.rust)?; + } + Ok(()) + } } } } diff --git a/tests/ui/slice_of_type_alias.rs b/tests/ui/slice_of_type_alias.rs new file mode 100644 index 00000000..a7bbc114 --- /dev/null +++ b/tests/ui/slice_of_type_alias.rs @@ -0,0 +1,30 @@ +use cxx::{type_id, ExternType}; + +#[repr(C)] +struct ElementTrivial(usize); + +#[repr(C)] +struct ElementOpaque(usize); + +#[cxx::bridge] +mod ffi { + unsafe extern "C++" { + type ElementTrivial = crate::ElementTrivial; + type ElementOpaque = crate::ElementOpaque; + + fn f(slice: &mut [ElementTrivial]); + fn g(slice: &[ElementOpaque]); + } +} + +unsafe impl ExternType for ElementTrivial { + type Id = type_id!("ElementTrivial"); + type Kind = cxx::kind::Trivial; +} + +unsafe impl ExternType for ElementOpaque { + type Id = type_id!("ElementOpaque"); + type Kind = cxx::kind::Opaque; +} + +fn main() {} diff --git a/tests/ui/slice_of_type_alias.stderr b/tests/ui/slice_of_type_alias.stderr new file mode 100644 index 00000000..f5fb04b0 --- /dev/null +++ b/tests/ui/slice_of_type_alias.stderr @@ -0,0 +1,10 @@ +error[E0271]: type mismatch resolving `::Kind == Trivial` + --> $DIR/slice_of_type_alias.rs:13:9 + | +13 | type ElementOpaque = crate::ElementOpaque; + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ expected enum `Trivial`, found enum `cxx::kind::Opaque` + | + ::: $WORKSPACE/src/extern_type.rs + | + | pub fn verify_extern_kind, Kind: self::Kind>() {} + | ----------- required by this bound in `verify_extern_kind` diff --git a/tests/ui/slice_unsupported.stderr b/tests/ui/slice_unsupported.stderr index 787076fb..2cbd26da 100644 --- a/tests/ui/slice_unsupported.stderr +++ b/tests/ui/slice_unsupported.stderr @@ -3,3 +3,9 @@ error: unsupported &mut [T] element type: opaque C++ type is not supported yet | 6 | fn f(_: &mut [Opaque]); | ^^^^^^^^^^^^^ + +error: needs a cxx::ExternType impl in order to be used as a slice element in &mut [Opaque] + --> $DIR/slice_unsupported.rs:4:9 + | +4 | type Opaque; + | ^^^^^^^^^^^