Skip to content

Commit 44198dd

Browse files
authored
Merge pull request #335 from dtolnay/kind
Add dedicated error message referring to cxx::ExternType when opaque type is used by value
2 parents 373d704 + 3208fd7 commit 44198dd

File tree

5 files changed

+53
-22
lines changed

5 files changed

+53
-22
lines changed

gen/src/write.rs

Lines changed: 4 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -81,7 +81,7 @@ pub(super) fn gen(
8181
}
8282
}
8383
Api::TypeAlias(ety) => {
84-
if types.required_trivial_aliases.contains(&ety.ident) {
84+
if types.required_trivial.contains_key(&ety.ident) {
8585
check_trivial_extern_type(out, &ety.ident)
8686
}
8787
}
@@ -136,7 +136,9 @@ fn write_includes(out: &mut OutFile, types: &Types) {
136136
Some(CxxString) => out.include.string = true,
137137
Some(Bool) | Some(Isize) | Some(F32) | Some(F64) | Some(RustString) => {}
138138
None => {
139-
if types.required_trivial_aliases.contains(&ident) {
139+
if types.aliases.contains_key(ident)
140+
&& types.required_trivial.contains_key(ident)
141+
{
140142
out.include.type_traits = true;
141143
}
142144
}

macro/src/expand.rs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -683,7 +683,7 @@ fn expand_type_alias_verify(
683683
const _: fn() = #begin #ident, #type_id #end;
684684
};
685685

686-
if types.required_trivial_aliases.contains(&alias.ident) {
686+
if types.required_trivial.contains_key(&alias.ident) {
687687
let begin = quote_spanned!(begin_span=> ::cxx::private::verify_extern_kind::<);
688688
verify.extend(quote! {
689689
const _: fn() = #begin #ident, ::cxx::kind::Trivial #end;

syntax/check.rs

Lines changed: 19 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,7 @@
11
use crate::syntax::atom::Atom::{self, *};
22
use crate::syntax::namespace::Namespace;
33
use crate::syntax::report::Errors;
4+
use crate::syntax::types::TrivialReason;
45
use crate::syntax::{
56
error, ident, Api, Enum, ExternFn, ExternType, Lang, Receiver, Ref, Slice, Struct, Ty1, Type,
67
Types,
@@ -208,6 +209,19 @@ fn check_api_enum(cx: &mut Check, enm: &Enum) {
208209

209210
fn check_api_type(cx: &mut Check, ty: &ExternType) {
210211
check_reserved_name(cx, &ty.ident);
212+
213+
if let Some(reason) = cx.types.required_trivial.get(&ty.ident) {
214+
let what = match reason {
215+
TrivialReason::StructField(strct) => format!("a field of `{}`", strct.ident),
216+
TrivialReason::FunctionArgument(efn) => format!("an argument of `{}`", efn.ident),
217+
TrivialReason::FunctionReturn(efn) => format!("a return value of `{}`", efn.ident),
218+
};
219+
let msg = format!(
220+
"needs a cxx::ExternType impl in order to be used as {}",
221+
what,
222+
);
223+
cx.error(ty, msg);
224+
}
211225
}
212226

213227
fn check_api_fn(cx: &mut Check, efn: &ExternFn) {
@@ -338,7 +352,8 @@ fn is_unsized(cx: &mut Check, ty: &Type) -> bool {
338352
|| cx.types.cxx.contains(ident)
339353
&& !cx.types.structs.contains_key(ident)
340354
&& !cx.types.enums.contains_key(ident)
341-
&& !cx.types.required_trivial_aliases.contains(ident)
355+
&& !(cx.types.aliases.contains_key(ident)
356+
&& cx.types.required_trivial.contains_key(ident))
342357
|| cx.types.rust.contains(ident)
343358
}
344359

@@ -376,12 +391,10 @@ fn describe(cx: &mut Check, ty: &Type) -> String {
376391
"struct".to_owned()
377392
} else if cx.types.enums.contains_key(ident) {
378393
"enum".to_owned()
394+
} else if cx.types.aliases.contains_key(ident) {
395+
"C++ type".to_owned()
379396
} else if cx.types.cxx.contains(ident) {
380-
if cx.types.required_trivial_aliases.contains(ident) {
381-
"trivial C++ type".to_owned()
382-
} else {
383-
"non-trivial C++ type".to_owned()
384-
}
397+
"opaque C++ type".to_owned()
385398
} else if cx.types.rust.contains(ident) {
386399
"opaque Rust type".to_owned()
387400
} else if Atom::from(ident) == Some(CxxString) {

syntax/types.rs

Lines changed: 20 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,7 @@
11
use crate::syntax::atom::Atom::{self, *};
22
use crate::syntax::report::Errors;
33
use crate::syntax::set::OrderedSet as Set;
4-
use crate::syntax::{Api, Derive, Enum, ExternType, Struct, Type, TypeAlias};
4+
use crate::syntax::{Api, Derive, Enum, ExternFn, ExternType, Struct, Type, TypeAlias};
55
use proc_macro2::Ident;
66
use quote::ToTokens;
77
use std::collections::{BTreeMap as Map, HashSet as UnorderedSet};
@@ -14,7 +14,7 @@ pub struct Types<'a> {
1414
pub rust: Set<&'a Ident>,
1515
pub aliases: Map<&'a Ident, &'a TypeAlias>,
1616
pub untrusted: Map<&'a Ident, &'a ExternType>,
17-
pub required_trivial_aliases: Set<&'a Ident>,
17+
pub required_trivial: Map<&'a Ident, TrivialReason<'a>>,
1818
}
1919

2020
impl<'a> Types<'a> {
@@ -140,27 +140,30 @@ impl<'a> Types<'a> {
140140
// we check that this is permissible. We do this _after_ scanning all
141141
// the APIs above, in case some function or struct references a type
142142
// which is declared subsequently.
143-
let mut required_trivial_aliases = Set::new();
144-
let mut insist_alias_types_are_trivial = |ty: &'a Type| {
143+
let mut required_trivial = Map::new();
144+
let mut insist_alias_types_are_trivial = |ty: &'a Type, reason| {
145145
if let Type::Ident(ident) = ty {
146-
if aliases.contains_key(ident) {
147-
required_trivial_aliases.insert(ident);
146+
if cxx.contains(ident) {
147+
required_trivial.entry(ident).or_insert(reason);
148148
}
149149
}
150150
};
151151
for api in apis {
152152
match api {
153153
Api::Struct(strct) => {
154+
let reason = TrivialReason::StructField(strct);
154155
for field in &strct.fields {
155-
insist_alias_types_are_trivial(&field.ty);
156+
insist_alias_types_are_trivial(&field.ty, reason);
156157
}
157158
}
158159
Api::CxxFunction(efn) | Api::RustFunction(efn) => {
160+
let reason = TrivialReason::FunctionArgument(efn);
159161
for arg in &efn.args {
160-
insist_alias_types_are_trivial(&arg.ty);
162+
insist_alias_types_are_trivial(&arg.ty, reason);
161163
}
162164
if let Some(ret) = &efn.ret {
163-
insist_alias_types_are_trivial(&ret);
165+
let reason = TrivialReason::FunctionReturn(efn);
166+
insist_alias_types_are_trivial(&ret, reason);
164167
}
165168
}
166169
_ => {}
@@ -175,7 +178,7 @@ impl<'a> Types<'a> {
175178
rust,
176179
aliases,
177180
untrusted,
178-
required_trivial_aliases,
181+
required_trivial,
179182
}
180183
}
181184

@@ -211,6 +214,13 @@ impl<'t, 'a> IntoIterator for &'t Types<'a> {
211214
}
212215
}
213216

217+
#[derive(Copy, Clone)]
218+
pub enum TrivialReason<'a> {
219+
StructField(&'a Struct),
220+
FunctionArgument(&'a ExternFn),
221+
FunctionReturn(&'a ExternFn),
222+
}
223+
214224
fn duplicate_name(cx: &mut Errors, sp: impl ToTokens, ident: &Ident) {
215225
let msg = format!("the name `{}` is defined multiple times", ident);
216226
cx.error(sp, msg);

tests/ui/by_value_not_supported.stderr

Lines changed: 9 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
error: using non-trivial C++ type by value is not supported
1+
error: using opaque C++ type by value is not supported
22
--> $DIR/by_value_not_supported.rs:4:9
33
|
44
4 | c: C,
@@ -16,13 +16,19 @@ error: using C++ string by value is not supported
1616
6 | s: CxxString,
1717
| ^^^^^^^^^^^^
1818

19-
error: passing non-trivial C++ type by value is not supported
19+
error: needs a cxx::ExternType impl in order to be used as a field of `S`
20+
--> $DIR/by_value_not_supported.rs:10:9
21+
|
22+
10 | type C;
23+
| ^^^^^^
24+
25+
error: passing opaque C++ type by value is not supported
2026
--> $DIR/by_value_not_supported.rs:16:14
2127
|
2228
16 | fn f(c: C) -> C;
2329
| ^^^^
2430

25-
error: returning non-trivial C++ type by value is not supported
31+
error: returning opaque C++ type by value is not supported
2632
--> $DIR/by_value_not_supported.rs:16:23
2733
|
2834
16 | fn f(c: C) -> C;

0 commit comments

Comments
 (0)