diff options
author | Arthur Cohen <arthur.cohen@embecosm.com> | 2023-02-16 13:53:22 +0100 |
---|---|---|
committer | CohenArthur <arthur.cohen@embecosm.com> | 2023-02-20 12:52:12 +0000 |
commit | 57b64a64261ed1d1774af61a1e36eeac604abcde (patch) | |
tree | 86370b4355678e9d50aa4941a5d0d9f443d8f5c5 | |
parent | 773d3c6477d7075ceeb01e4c910be24361ff6dcf (diff) | |
download | gcc-57b64a64261ed1d1774af61a1e36eeac604abcde.zip gcc-57b64a64261ed1d1774af61a1e36eeac604abcde.tar.gz gcc-57b64a64261ed1d1774af61a1e36eeac604abcde.tar.bz2 |
parser: Allow parsing of qualified type path as nested generic argument
Let's take the example of lexing `Option<<T as Iterator>::Item>` and look
at the first few tokens. Originally, `Option<<T` was lexed as 3 tokens:
* IDENTIFIER(Option)
* LEFT_SHIFT
* IDENTIFIER(T)
The parser did not allow a list of generic arguments to start with a left
shift, and rejected the above type. We are now splitting the left shift
into two left angles, as this allows complex generic arguments and overall
makes sense parsing wise. Thus, the above list becomes:
* IDENTIFIER(Option)
* LEFT_ANGLE
* LEFT_ANGLE
* IDENTIFIER(T)
and `<T as Iterator>` is properly parsed as a qualified path.
Fixes #1815
Fixed #1809
Addresses #1524
gcc/rust/ChangeLog:
* parse/rust-parse-impl.h (Parser::parse_path_generic_args): Split leading
`LEFT_SHIFT` token into two `LEFT_ANGLE` tokens when parsing generic arguments.
(Parser::parse_type_path_segment): Allow `LEFT_ANGLE` as starting token for
parsing generic arguments.
gcc/testsuite/ChangeLog:
* rust/compile/parse_associated_type_as_generic_arg.rs: New test.
* rust/compile/parse_associated_type_as_generic_arg2.rs: New test.
* rust/compile/path_as_generic_arg.rs: New test.
* rust/compile/nested_generic.rs: New test.
5 files changed, 68 insertions, 0 deletions
diff --git a/gcc/rust/parse/rust-parse-impl.h b/gcc/rust/parse/rust-parse-impl.h index 4c39284..3bf26bc 100644 --- a/gcc/rust/parse/rust-parse-impl.h +++ b/gcc/rust/parse/rust-parse-impl.h @@ -6383,6 +6383,9 @@ template <typename ManagedTokenSource> AST::GenericArgs Parser<ManagedTokenSource>::parse_path_generic_args () { + if (lexer.peek_token ()->get_id () == LEFT_SHIFT) + lexer.split_current_token (LEFT_ANGLE, LEFT_ANGLE); + if (!skip_token (LEFT_ANGLE)) { // skip after somewhere? @@ -6557,6 +6560,7 @@ Parser<ManagedTokenSource>::parse_type_path_segment () const_TokenPtr t = lexer.peek_token (); switch (t->get_id ()) { + case LEFT_SHIFT: case LEFT_ANGLE: { // parse generic args AST::GenericArgs generic_args = parse_path_generic_args (); diff --git a/gcc/testsuite/rust/compile/nested_generic.rs b/gcc/testsuite/rust/compile/nested_generic.rs new file mode 100644 index 0000000..6c31099 --- /dev/null +++ b/gcc/testsuite/rust/compile/nested_generic.rs @@ -0,0 +1,4 @@ +pub struct A<T>(T); +pub struct B<T>(T); + +pub fn foo(_: A<B<i32>>) {} diff --git a/gcc/testsuite/rust/compile/parse_associated_type_as_generic_arg.rs b/gcc/testsuite/rust/compile/parse_associated_type_as_generic_arg.rs new file mode 100644 index 0000000..dc05c06 --- /dev/null +++ b/gcc/testsuite/rust/compile/parse_associated_type_as_generic_arg.rs @@ -0,0 +1,24 @@ +// { dg-additional-options "-fsyntax-only" } + +trait Foo { + type A; + + fn foo(); +} + +struct S; + +impl Foo for S { + type A = i32; + + fn foo() {} +} + +enum Maybe<T> { + Something(T), + Nothing, +} + +fn foo() -> Maybe<<S as Foo>::A> { + Maybe::Something(15) +} diff --git a/gcc/testsuite/rust/compile/parse_associated_type_as_generic_arg2.rs b/gcc/testsuite/rust/compile/parse_associated_type_as_generic_arg2.rs new file mode 100644 index 0000000..9c518a03 --- /dev/null +++ b/gcc/testsuite/rust/compile/parse_associated_type_as_generic_arg2.rs @@ -0,0 +1,24 @@ +// { dg-additional-options "-fsyntax-only" } + +trait Foo { + type A; + + fn foo(); +} + +struct S; + +impl Foo for S { + type A = (); + + fn foo() {} +} + +enum Maybe<T> { + Something(T), + Nothing, +} + +fn main() { + let a: Maybe<<S as Foo>::A> = Maybe::Something(()); +} diff --git a/gcc/testsuite/rust/compile/path_as_generic_arg.rs b/gcc/testsuite/rust/compile/path_as_generic_arg.rs new file mode 100644 index 0000000..35b3160 --- /dev/null +++ b/gcc/testsuite/rust/compile/path_as_generic_arg.rs @@ -0,0 +1,12 @@ +pub enum Result<T, E> { + Ok(T), + Err(E), +} + +pub mod module { + pub struct E; +} + +pub fn foo() -> Result<(), module::E> { + Result::Err(module::E) +} |