aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorArthur Cohen <arthur.cohen@embecosm.com>2023-02-16 13:53:22 +0100
committerArthur Cohen <arthur.cohen@embecosm.com>2024-01-16 18:13:34 +0100
commit60b6cc1676eb3a4118dc3302f20fbfe573054d51 (patch)
treea71fd0bb5e1e59bbe047ce505ad7b29d0aaf1e90
parenta5258f3a11ab577835ef5e93be5cb65ec9e44132 (diff)
downloadgcc-60b6cc1676eb3a4118dc3302f20fbfe573054d51.zip
gcc-60b6cc1676eb3a4118dc3302f20fbfe573054d51.tar.gz
gcc-60b6cc1676eb3a4118dc3302f20fbfe573054d51.tar.bz2
gccrs: 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.
-rw-r--r--gcc/rust/parse/rust-parse-impl.h4
-rw-r--r--gcc/testsuite/rust/compile/nested_generic.rs4
-rw-r--r--gcc/testsuite/rust/compile/parse_associated_type_as_generic_arg.rs24
-rw-r--r--gcc/testsuite/rust/compile/parse_associated_type_as_generic_arg2.rs24
-rw-r--r--gcc/testsuite/rust/compile/path_as_generic_arg.rs12
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 d1f192e..6dbc2c7 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)
+}