aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorDavid Tolnay <dtolnay@gmail.com>2020-12-28 21:34:05 -0800
committerGitHub <noreply@github.com>2020-12-28 21:34:05 -0800
commit0c8cb95a3c5aa964a7c33fce07ab7e11882d2160 (patch)
tree2ab2fdcf8c8ca8f19856bb965c030d339460fc5f
parentcb9408df8b6e7fab2e1c38c5237ac477b356592d (diff)
parent446756f4c93cd1e8650161bcfb56a7e2e2bb8c56 (diff)
downloadcxx-0c8cb95a3c5aa964a7c33fce07ab7e11882d2160.tar.gz
Merge pull request #610 from dtolnay/lifetime
Parse lifetimes on foreign module types
-rw-r--r--gen/src/nested.rs1
-rw-r--r--syntax/check.rs8
-rw-r--r--syntax/mod.rs2
-rw-r--r--syntax/parse.rs98
-rw-r--r--tests/ui/extern_type_generic.rs8
-rw-r--r--tests/ui/extern_type_generic.stderr5
-rw-r--r--tests/ui/extern_type_lifetime.rs8
-rw-r--r--tests/ui/extern_type_lifetime.stderr5
-rw-r--r--tests/ui/extern_type_lifetime_bound.rs8
-rw-r--r--tests/ui/extern_type_lifetime_bound.stderr5
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(&param, 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(&param, 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(&param, 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>;
+ | ^^^^^^