diff options
author | David Tolnay <dtolnay@gmail.com> | 2020-12-28 21:34:05 -0800 |
---|---|---|
committer | GitHub <noreply@github.com> | 2020-12-28 21:34:05 -0800 |
commit | 0c8cb95a3c5aa964a7c33fce07ab7e11882d2160 (patch) | |
tree | 2ab2fdcf8c8ca8f19856bb965c030d339460fc5f | |
parent | cb9408df8b6e7fab2e1c38c5237ac477b356592d (diff) | |
parent | 446756f4c93cd1e8650161bcfb56a7e2e2bb8c56 (diff) | |
download | cxx-0c8cb95a3c5aa964a7c33fce07ab7e11882d2160.tar.gz |
Merge pull request #610 from dtolnay/lifetime
Parse lifetimes on foreign module types
-rw-r--r-- | gen/src/nested.rs | 1 | ||||
-rw-r--r-- | syntax/check.rs | 8 | ||||
-rw-r--r-- | syntax/mod.rs | 2 | ||||
-rw-r--r-- | syntax/parse.rs | 98 | ||||
-rw-r--r-- | tests/ui/extern_type_generic.rs | 8 | ||||
-rw-r--r-- | tests/ui/extern_type_generic.stderr | 5 | ||||
-rw-r--r-- | tests/ui/extern_type_lifetime.rs | 8 | ||||
-rw-r--r-- | tests/ui/extern_type_lifetime.stderr | 5 | ||||
-rw-r--r-- | tests/ui/extern_type_lifetime_bound.rs | 8 | ||||
-rw-r--r-- | tests/ui/extern_type_lifetime_bound.stderr | 5 |
10 files changed, 118 insertions, 30 deletions
diff --git a/gen/src/nested.rs b/gen/src/nested.rs index abc96701..99cfdf8f 100644 --- a/gen/src/nested.rs +++ b/gen/src/nested.rs @@ -136,6 +136,7 @@ mod tests { cxx: ident.clone(), rust: ident, }, + lifetimes: Vec::new(), colon_token: None, bounds: Vec::new(), semi_token: Token![;](Span::call_site()), diff --git a/syntax/check.rs b/syntax/check.rs index 39ea04ec..29013cb2 100644 --- a/syntax/check.rs +++ b/syntax/check.rs @@ -337,6 +337,10 @@ fn check_api_type(cx: &mut Check, ety: &ExternType) { cx.error(derive, msg); } + if let Some(lifetime) = ety.lifetimes.first() { + cx.error(lifetime, "extern type with lifetimes is not supported yet"); + } + if !ety.bounds.is_empty() { let bounds = &ety.bounds; let span = quote!(#(#bounds)*); @@ -440,6 +444,10 @@ fn check_api_type_alias(cx: &mut Check, alias: &TypeAlias) { let msg = format!("derive({}) on extern type alias is not supported", derive); cx.error(derive, msg); } + + if let Some(lifetime) = alias.lifetimes.first() { + cx.error(lifetime, "extern type with lifetimes is not supported yet"); + } } fn check_api_impl(cx: &mut Check, imp: &Impl) { diff --git a/syntax/mod.rs b/syntax/mod.rs index 111cec34..c878ae28 100644 --- a/syntax/mod.rs +++ b/syntax/mod.rs @@ -74,6 +74,7 @@ pub struct ExternType { pub derives: Vec<Derive>, pub type_token: Token![type], pub name: Pair, + pub lifetimes: Vec<Lifetime>, pub colon_token: Option<Token![:]>, pub bounds: Vec<Derive>, pub semi_token: Token![;], @@ -115,6 +116,7 @@ pub struct TypeAlias { pub derives: Vec<Derive>, pub type_token: Token![type], pub name: Pair, + pub lifetimes: Vec<Lifetime>, pub eq_token: Token![=], pub ty: RustType, pub semi_token: Token![;], diff --git a/syntax/parse.rs b/syntax/parse.rs index 1ae4c2df..65e07aaa 100644 --- a/syntax/parse.rs +++ b/syntax/parse.rs @@ -13,8 +13,8 @@ use syn::parse::{ParseStream, Parser}; use syn::punctuated::Punctuated; use syn::{ Abi, Attribute, Error, Expr, Fields, FnArg, ForeignItem, ForeignItemFn, ForeignItemType, - GenericArgument, GenericParam, Generics, Ident, ItemEnum, ItemImpl, ItemStruct, Lit, LitStr, - Pat, PathArguments, Result, ReturnType, Token, TraitBound, TraitBoundModifier, + GenericArgument, GenericParam, Generics, Ident, ItemEnum, ItemImpl, ItemStruct, Lifetime, Lit, + LitStr, Pat, PathArguments, Result, ReturnType, Token, TraitBound, TraitBoundModifier, Type as RustType, TypeArray, TypeBareFn, TypeParamBound, TypePath, TypeReference, Variant as RustVariant, }; @@ -385,6 +385,7 @@ fn parse_extern_type( let type_token = foreign_type.type_token; let name = pair(namespace, &foreign_type.ident, cxx_name, rust_name); + let lifetimes = Vec::new(); let colon_token = None; let bounds = Vec::new(); let semi_token = foreign_type.semi_token; @@ -398,6 +399,7 @@ fn parse_extern_type( derives, type_token, name, + lifetimes, colon_token, bounds, semi_token, @@ -578,14 +580,45 @@ fn parse_extern_verbatim( } }; let ident: Ident = input.parse()?; + let generics: Generics = input.parse()?; + let mut lifetimes = Vec::new(); + let mut has_unsupported_generic_param = false; + for param in generics.params { + match param { + GenericParam::Lifetime(param) => { + if !param.bounds.is_empty() && !has_unsupported_generic_param { + let msg = "lifetime parameter with bounds is not supported yet"; + cx.error(¶m, msg); + has_unsupported_generic_param = true; + } + lifetimes.push(param.lifetime); + } + GenericParam::Type(param) => { + if !has_unsupported_generic_param { + let msg = "extern type with generic type parameter is not supported yet"; + cx.error(¶m, msg); + has_unsupported_generic_param = true; + } + } + GenericParam::Const(param) => { + if !has_unsupported_generic_param { + let msg = "extern type with const generic parameter is not supported yet"; + cx.error(¶m, msg); + has_unsupported_generic_param = true; + } + } + } + } let lookahead = input.lookahead1(); if lookahead.peek(Token![=]) { // type Alias = crate::path::to::Type; - parse_type_alias(cx, attrs, type_token, ident, input, lang, namespace) - } else if lookahead.peek(Token![:]) { + parse_type_alias( + cx, attrs, type_token, ident, lifetimes, input, lang, namespace, + ) + } else if lookahead.peek(Token![:]) || lookahead.peek(Token![;]) { // type Opaque: Bound2 + Bound2; parse_extern_type_bounded( - cx, attrs, type_token, ident, input, lang, trusted, namespace, + cx, attrs, type_token, ident, lifetimes, input, lang, trusted, namespace, ) } else { Err(lookahead.error()) @@ -599,6 +632,7 @@ fn parse_type_alias( attrs: Vec<Attribute>, type_token: Token![type], ident: Ident, + lifetimes: Vec<Lifetime>, input: ParseStream, lang: Lang, namespace: &Namespace, @@ -638,6 +672,7 @@ fn parse_type_alias( derives, type_token, name, + lifetimes, eq_token, ty, semi_token, @@ -649,38 +684,41 @@ fn parse_extern_type_bounded( attrs: Vec<Attribute>, type_token: Token![type], ident: Ident, + lifetimes: Vec<Lifetime>, input: ParseStream, lang: Lang, trusted: bool, namespace: &Namespace, ) -> Result<Api> { - let colon_token: Token![:] = input.parse()?; let mut bounds = Vec::new(); - loop { - match input.parse()? { - TypeParamBound::Trait(TraitBound { - paren_token: None, - modifier: TraitBoundModifier::None, - lifetimes: None, - path, - }) if if let Some(derive) = path.get_ident().and_then(Derive::from) { - bounds.push(derive); - true - } else { - false - } => {} - bound @ TypeParamBound::Trait(_) | bound @ TypeParamBound::Lifetime(_) => { - cx.error(bound, "unsupported trait"); + let colon_token: Option<Token![:]> = input.parse()?; + if colon_token.is_some() { + loop { + match input.parse()? { + TypeParamBound::Trait(TraitBound { + paren_token: None, + modifier: TraitBoundModifier::None, + lifetimes: None, + path, + }) if if let Some(derive) = path.get_ident().and_then(Derive::from) { + bounds.push(derive); + true + } else { + false + } => {} + bound @ TypeParamBound::Trait(_) | bound @ TypeParamBound::Lifetime(_) => { + cx.error(bound, "unsupported trait"); + } } - } - let lookahead = input.lookahead1(); - if lookahead.peek(Token![+]) { - input.parse::<Token![+]>()?; - } else if lookahead.peek(Token![;]) { - break; - } else { - return Err(lookahead.error()); + let lookahead = input.lookahead1(); + if lookahead.peek(Token![+]) { + input.parse::<Token![+]>()?; + } else if lookahead.peek(Token![;]) { + break; + } else { + return Err(lookahead.error()); + } } } let semi_token: Token![;] = input.parse()?; @@ -704,7 +742,6 @@ fn parse_extern_type_bounded( ); let name = pair(namespace, &ident, cxx_name, rust_name); - let colon_token = Some(colon_token); Ok(match lang { Lang::Cxx => Api::CxxType, @@ -715,6 +752,7 @@ fn parse_extern_type_bounded( derives, type_token, name, + lifetimes, colon_token, bounds, semi_token, diff --git a/tests/ui/extern_type_generic.rs b/tests/ui/extern_type_generic.rs new file mode 100644 index 00000000..4de2c981 --- /dev/null +++ b/tests/ui/extern_type_generic.rs @@ -0,0 +1,8 @@ +#[cxx::bridge] +mod ffi { + extern "C++" { + type Generic<T>; + } +} + +fn main() {} diff --git a/tests/ui/extern_type_generic.stderr b/tests/ui/extern_type_generic.stderr new file mode 100644 index 00000000..95faec6c --- /dev/null +++ b/tests/ui/extern_type_generic.stderr @@ -0,0 +1,5 @@ +error: extern type with generic type parameter is not supported yet + --> $DIR/extern_type_generic.rs:4:22 + | +4 | type Generic<T>; + | ^ diff --git a/tests/ui/extern_type_lifetime.rs b/tests/ui/extern_type_lifetime.rs new file mode 100644 index 00000000..4e0e2f7f --- /dev/null +++ b/tests/ui/extern_type_lifetime.rs @@ -0,0 +1,8 @@ +#[cxx::bridge] +mod ffi { + extern "C++" { + type Complex<'a, 'b>; + } +} + +fn main() {} diff --git a/tests/ui/extern_type_lifetime.stderr b/tests/ui/extern_type_lifetime.stderr new file mode 100644 index 00000000..85a5d396 --- /dev/null +++ b/tests/ui/extern_type_lifetime.stderr @@ -0,0 +1,5 @@ +error: extern type with lifetimes is not supported yet + --> $DIR/extern_type_lifetime.rs:4:22 + | +4 | type Complex<'a, 'b>; + | ^^ diff --git a/tests/ui/extern_type_lifetime_bound.rs b/tests/ui/extern_type_lifetime_bound.rs new file mode 100644 index 00000000..ad581818 --- /dev/null +++ b/tests/ui/extern_type_lifetime_bound.rs @@ -0,0 +1,8 @@ +#[cxx::bridge] +mod ffi { + extern "C++" { + type Complex<'a, 'b: 'a>; + } +} + +fn main() {} diff --git a/tests/ui/extern_type_lifetime_bound.stderr b/tests/ui/extern_type_lifetime_bound.stderr new file mode 100644 index 00000000..8c58050a --- /dev/null +++ b/tests/ui/extern_type_lifetime_bound.stderr @@ -0,0 +1,5 @@ +error: lifetime parameter with bounds is not supported yet + --> $DIR/extern_type_lifetime_bound.rs:4:26 + | +4 | type Complex<'a, 'b: 'a>; + | ^^^^^^ |