Skip to content

Commit 1cbd1b2

Browse files
authored
Merge pull request #336 from dtolnay/impl
Explicitly requesting an instantiation
2 parents c86633d + 64cab48 commit 1cbd1b2

17 files changed

+176
-17
lines changed

gen/src/write.rs

Lines changed: 6 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1056,14 +1056,18 @@ fn write_generic_instantiations(out: &mut OutFile, types: &Types) {
10561056
}
10571057
} else if let Type::UniquePtr(ptr) = ty {
10581058
if let Type::Ident(inner) = &ptr.inner {
1059-
if Atom::from(inner).is_none() && !types.aliases.contains_key(inner) {
1059+
if Atom::from(inner).is_none()
1060+
&& (!types.aliases.contains_key(inner) || types.explicit_impls.contains(ty))
1061+
{
10601062
out.next_section();
10611063
write_unique_ptr(out, inner, types);
10621064
}
10631065
}
10641066
} else if let Type::CxxVector(ptr) = ty {
10651067
if let Type::Ident(inner) = &ptr.inner {
1066-
if Atom::from(inner).is_none() && !types.aliases.contains_key(inner) {
1068+
if Atom::from(inner).is_none()
1069+
&& (!types.aliases.contains_key(inner) || types.explicit_impls.contains(ty))
1070+
{
10671071
out.next_section();
10681072
write_cxx_vector(out, ty, inner, types);
10691073
}

macro/src/expand.rs

Lines changed: 7 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -39,7 +39,7 @@ fn expand(ffi: Module, apis: &[Api], types: &Types) -> TokenStream {
3939

4040
for api in apis {
4141
match api {
42-
Api::Include(_) | Api::RustType(_) => {}
42+
Api::Include(_) | Api::RustType(_) | Api::Impl(_) => {}
4343
Api::Struct(strct) => expanded.extend(expand_struct(strct)),
4444
Api::Enum(enm) => expanded.extend(expand_enum(enm)),
4545
Api::CxxType(ety) => {
@@ -76,13 +76,17 @@ fn expand(ffi: Module, apis: &[Api], types: &Types) -> TokenStream {
7676
}
7777
} else if let Type::UniquePtr(ptr) = ty {
7878
if let Type::Ident(ident) = &ptr.inner {
79-
if Atom::from(ident).is_none() && !types.aliases.contains_key(ident) {
79+
if Atom::from(ident).is_none()
80+
&& (!types.aliases.contains_key(ident) || types.explicit_impls.contains(ty))
81+
{
8082
expanded.extend(expand_unique_ptr(namespace, ident, types));
8183
}
8284
}
8385
} else if let Type::CxxVector(ptr) = ty {
8486
if let Type::Ident(ident) = &ptr.inner {
85-
if Atom::from(ident).is_none() && !types.aliases.contains_key(ident) {
87+
if Atom::from(ident).is_none()
88+
&& (!types.aliases.contains_key(ident) || types.explicit_impls.contains(ty))
89+
{
8690
// Generate impl for CxxVector<T> if T is a struct or opaque
8791
// C++ type. Impl for primitives is already provided by cxx
8892
// crate.

syntax/check.rs

Lines changed: 15 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -3,8 +3,8 @@ use crate::syntax::namespace::Namespace;
33
use crate::syntax::report::Errors;
44
use crate::syntax::types::TrivialReason;
55
use crate::syntax::{
6-
error, ident, Api, Enum, ExternFn, ExternType, Lang, Receiver, Ref, Slice, Struct, Ty1, Type,
7-
Types,
6+
error, ident, Api, Enum, ExternFn, ExternType, Impl, Lang, Receiver, Ref, Slice, Struct, Ty1,
7+
Type, Types,
88
};
99
use proc_macro2::{Delimiter, Group, Ident, TokenStream};
1010
use quote::{quote, ToTokens};
@@ -48,6 +48,7 @@ fn do_typecheck(cx: &mut Check) {
4848
Api::Enum(enm) => check_api_enum(cx, enm),
4949
Api::CxxType(ety) | Api::RustType(ety) => check_api_type(cx, ety),
5050
Api::CxxFunction(efn) | Api::RustFunction(efn) => check_api_fn(cx, efn),
51+
Api::Impl(imp) => check_api_impl(cx, imp),
5152
_ => {}
5253
}
5354
}
@@ -286,6 +287,18 @@ fn check_api_fn(cx: &mut Check, efn: &ExternFn) {
286287
check_multiple_arg_lifetimes(cx, efn);
287288
}
288289

290+
fn check_api_impl(cx: &mut Check, imp: &Impl) {
291+
if let Type::UniquePtr(ty) | Type::CxxVector(ty) = &imp.ty {
292+
if let Type::Ident(inner) = &ty.inner {
293+
if Atom::from(inner).is_none() {
294+
return;
295+
}
296+
}
297+
}
298+
299+
cx.error(imp, "unsupported Self type of explicit impl");
300+
}
301+
289302
fn check_mut_return_restriction(cx: &mut Check, efn: &ExternFn) {
290303
match &efn.ret {
291304
Some(Type::Ref(ty)) if ty.mutability.is_some() => {}

syntax/file.rs

Lines changed: 4 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -2,8 +2,8 @@ use crate::syntax::namespace::Namespace;
22
use quote::quote;
33
use syn::parse::{Error, Parse, ParseStream, Result};
44
use syn::{
5-
braced, token, Abi, Attribute, ForeignItem, Ident, Item as RustItem, ItemEnum, ItemStruct,
6-
ItemUse, LitStr, Token, Visibility,
5+
braced, token, Abi, Attribute, ForeignItem, Ident, Item as RustItem, ItemEnum, ItemImpl,
6+
ItemStruct, ItemUse, LitStr, Token, Visibility,
77
};
88

99
pub struct Module {
@@ -22,6 +22,7 @@ pub enum Item {
2222
Enum(ItemEnum),
2323
ForeignMod(ItemForeignMod),
2424
Use(ItemUse),
25+
Impl(ItemImpl),
2526
Other(RustItem),
2627
}
2728

@@ -99,6 +100,7 @@ impl Parse for Item {
99100
brace_token: item.brace_token,
100101
items: item.items,
101102
})),
103+
RustItem::Impl(item) => Ok(Item::Impl(ItemImpl { attrs, ..item })),
102104
RustItem::Use(item) => Ok(Item::Use(ItemUse { attrs, ..item })),
103105
other => Ok(Item::Other(other)),
104106
}

syntax/ident.rs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -20,7 +20,7 @@ pub(crate) fn check_all(cx: &mut Check, namespace: &Namespace, apis: &[Api]) {
2020

2121
for api in apis {
2222
match api {
23-
Api::Include(_) => {}
23+
Api::Include(_) | Api::Impl(_) => {}
2424
Api::Struct(strct) => {
2525
check(cx, &strct.ident);
2626
for field in &strct.fields {

syntax/mod.rs

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -42,6 +42,7 @@ pub enum Api {
4242
RustType(ExternType),
4343
RustFunction(ExternFn),
4444
TypeAlias(TypeAlias),
45+
Impl(Impl),
4546
}
4647

4748
pub struct ExternType {
@@ -87,6 +88,12 @@ pub struct TypeAlias {
8788
pub semi_token: Token![;],
8889
}
8990

91+
pub struct Impl {
92+
pub impl_token: Token![impl],
93+
pub ty: Type,
94+
pub brace_token: Brace,
95+
}
96+
9097
pub struct Signature {
9198
pub unsafety: Option<Token![unsafe]>,
9299
pub fn_token: Token![fn],

syntax/parse.rs

Lines changed: 40 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -3,17 +3,17 @@ use crate::syntax::file::{Item, ItemForeignMod};
33
use crate::syntax::report::Errors;
44
use crate::syntax::Atom::*;
55
use crate::syntax::{
6-
attrs, error, Api, Doc, Enum, ExternFn, ExternType, Lang, Receiver, Ref, Signature, Slice,
7-
Struct, Ty1, Type, TypeAlias, Var, Variant,
6+
attrs, error, Api, Doc, Enum, ExternFn, ExternType, Impl, Lang, Receiver, Ref, Signature,
7+
Slice, Struct, Ty1, Type, TypeAlias, Var, Variant,
88
};
9-
use proc_macro2::{TokenStream, TokenTree};
9+
use proc_macro2::{Delimiter, Group, TokenStream, TokenTree};
1010
use quote::{format_ident, quote, quote_spanned};
1111
use syn::parse::{ParseStream, Parser};
1212
use syn::punctuated::Punctuated;
1313
use syn::{
1414
Abi, Attribute, Error, Fields, FnArg, ForeignItem, ForeignItemFn, ForeignItemType,
15-
GenericArgument, Ident, ItemEnum, ItemStruct, LitStr, Pat, PathArguments, Result, ReturnType,
16-
Token, Type as RustType, TypeBareFn, TypePath, TypeReference, TypeSlice,
15+
GenericArgument, Ident, ItemEnum, ItemImpl, ItemStruct, LitStr, Pat, PathArguments, Result,
16+
ReturnType, Token, Type as RustType, TypeBareFn, TypePath, TypeReference, TypeSlice,
1717
};
1818

1919
pub mod kw {
@@ -33,6 +33,10 @@ pub fn parse_items(cx: &mut Errors, items: Vec<Item>, trusted: bool) -> Vec<Api>
3333
Err(err) => cx.push(err),
3434
},
3535
Item::ForeignMod(foreign_mod) => parse_foreign_mod(cx, foreign_mod, &mut apis, trusted),
36+
Item::Impl(item) => match parse_impl(item) {
37+
Ok(imp) => apis.push(imp),
38+
Err(err) => cx.push(err),
39+
},
3640
Item::Use(item) => cx.error(item, error::USE_NOT_ALLOWED),
3741
Item::Other(item) => cx.error(item, "unsupported item"),
3842
}
@@ -420,6 +424,37 @@ fn parse_extern_verbatim(cx: &mut Errors, tokens: &TokenStream, lang: Lang) -> R
420424
}
421425
}
422426

427+
fn parse_impl(imp: ItemImpl) -> Result<Api> {
428+
if !imp.items.is_empty() {
429+
let mut span = Group::new(Delimiter::Brace, TokenStream::new());
430+
span.set_span(imp.brace_token.span);
431+
return Err(Error::new_spanned(span, "expected an empty impl block"));
432+
}
433+
434+
let self_ty = &imp.self_ty;
435+
if let Some((bang, path, for_token)) = &imp.trait_ {
436+
let span = quote!(#bang #path #for_token #self_ty);
437+
return Err(Error::new_spanned(
438+
span,
439+
"unexpected impl, expected something like `impl UniquePtr<T> {}`",
440+
));
441+
}
442+
443+
let generics = &imp.generics;
444+
if !generics.params.is_empty() || generics.where_clause.is_some() {
445+
return Err(Error::new_spanned(
446+
imp,
447+
"generic parameters on an impl is not supported",
448+
));
449+
}
450+
451+
Ok(Api::Impl(Impl {
452+
impl_token: imp.impl_token,
453+
ty: parse_type(&self_ty)?,
454+
brace_token: imp.brace_token,
455+
}))
456+
}
457+
423458
fn parse_include(input: ParseStream) -> Result<String> {
424459
if input.peek(LitStr) {
425460
return Ok(input.parse::<LitStr>()?.value());

syntax/tokens.rs

Lines changed: 10 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,7 @@
11
use crate::syntax::atom::Atom::*;
22
use crate::syntax::{
3-
Atom, Derive, Enum, ExternFn, ExternType, Receiver, Ref, Signature, Slice, Struct, Ty1, Type,
4-
TypeAlias, Var,
3+
Atom, Derive, Enum, ExternFn, ExternType, Impl, Receiver, Ref, Signature, Slice, Struct, Ty1,
4+
Type, TypeAlias, Var,
55
};
66
use proc_macro2::{Ident, Span, TokenStream};
77
use quote::{quote_spanned, ToTokens};
@@ -121,6 +121,14 @@ impl ToTokens for ExternFn {
121121
}
122122
}
123123

124+
impl ToTokens for Impl {
125+
fn to_tokens(&self, tokens: &mut TokenStream) {
126+
self.impl_token.to_tokens(tokens);
127+
self.ty.to_tokens(tokens);
128+
self.brace_token.surround(tokens, |_tokens| {});
129+
}
130+
}
131+
124132
impl ToTokens for Signature {
125133
fn to_tokens(&self, tokens: &mut TokenStream) {
126134
self.fn_token.to_tokens(tokens);

syntax/types.rs

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -15,6 +15,7 @@ pub struct Types<'a> {
1515
pub aliases: Map<&'a Ident, &'a TypeAlias>,
1616
pub untrusted: Map<&'a Ident, &'a ExternType>,
1717
pub required_trivial: Map<&'a Ident, TrivialReason<'a>>,
18+
pub explicit_impls: Set<&'a Type>,
1819
}
1920

2021
impl<'a> Types<'a> {
@@ -26,6 +27,7 @@ impl<'a> Types<'a> {
2627
let mut rust = Set::new();
2728
let mut aliases = Map::new();
2829
let mut untrusted = Map::new();
30+
let mut explicit_impls = Set::new();
2931

3032
fn visit<'a>(all: &mut Set<&'a Type>, ty: &'a Type) {
3133
all.insert(ty);
@@ -133,6 +135,10 @@ impl<'a> Types<'a> {
133135
cxx.insert(ident);
134136
aliases.insert(ident, alias);
135137
}
138+
Api::Impl(imp) => {
139+
visit(&mut all, &imp.ty);
140+
explicit_impls.insert(&imp.ty);
141+
}
136142
}
137143
}
138144

@@ -179,6 +185,7 @@ impl<'a> Types<'a> {
179185
aliases,
180186
untrusted,
181187
required_trivial,
188+
explicit_impls,
182189
}
183190
}
184191

tests/ui/bad_explicit_impl.rs

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,10 @@
1+
#[cxx::bridge]
2+
mod ffi {
3+
struct S {
4+
x: u8,
5+
}
6+
7+
impl fn() -> &S {}
8+
}
9+
10+
fn main() {}

0 commit comments

Comments
 (0)