public inbox for gcc-cvs@sourceware.org help / color / mirror / Atom feed
From: Thomas Schwinge <tschwinge@gcc.gnu.org> To: gcc-cvs@gcc.gnu.org Subject: [gcc/devel/rust/master] parser: Add base for parsing const generic application Date: Tue, 21 Jun 2022 10:33:14 +0000 (GMT) [thread overview] Message-ID: <20220621103314.6EC9A3870901@sourceware.org> (raw) https://gcc.gnu.org/g:0dbfdb5cfc5cf64de086a85aadc1e58b115fb7f6 commit 0dbfdb5cfc5cf64de086a85aadc1e58b115fb7f6 Author: Arthur Cohen <arthur.cohen@embecosm.com> Date: Wed Jun 15 12:25:33 2022 +0200 parser: Add base for parsing const generic application 1. Refactor const generic declaration The default value for const generics now benefits from using the same function as parsing a regular const generic expression 2. `Parser::parse_type` should not always add errors In the case that we are parsing a const generic and not a type, we should not emit bogus errors from `parse_type` such as "unexpected token in type: LITERAL". Thus, we add a flag to the function to not always add errors to the error table 3. Figure out how to deal with ambiguities In the following cases, parsing is ambiguous: ```rust let a: Foo<N>; ``` What is N? Is it a type to be used as a generic argument? Is it a const value to be used for a const generic argument? We need to keep both possibilities and differentiate later during typechecking. We need to figure out if it would be better to keep the ambiguity in our future `ConstGenericArg` type (something like Kind::ConstVarOrType) or modify our current `AST::Type` to maybe get differentiated later as a const variable, which seems more annoying. Finally, since the const evaluation is not implemented yet, we are getting some bogus errors in the testcase. This commit simply serves as a necessary base: parsing const generics before we can apply them. Diff: --- gcc/rust/ast/rust-path.h | 2 + gcc/rust/parse/rust-parse-impl.h | 159 +++++++++++++++---------- gcc/rust/parse/rust-parse.h | 3 +- gcc/testsuite/rust/compile/const_generics_3.rs | 26 ++++ 4 files changed, 128 insertions(+), 62 deletions(-) diff --git a/gcc/rust/ast/rust-path.h b/gcc/rust/ast/rust-path.h index 45d08bfbaa9..a1f88d83205 100644 --- a/gcc/rust/ast/rust-path.h +++ b/gcc/rust/ast/rust-path.h @@ -134,6 +134,8 @@ struct GenericArgs std::vector<Lifetime> lifetime_args; std::vector<std::unique_ptr<Type> > type_args; std::vector<GenericArgsBinding> binding_args; + // TODO: Handle const generics here as well. + // We can probably keep a vector of `Expr`s for this. Location locus; public: diff --git a/gcc/rust/parse/rust-parse-impl.h b/gcc/rust/parse/rust-parse-impl.h index ae6ef4a9595..3a76d748d6a 100644 --- a/gcc/rust/parse/rust-parse-impl.h +++ b/gcc/rust/parse/rust-parse-impl.h @@ -2885,37 +2885,14 @@ Parser<ManagedTokenSource>::parse_generic_param (EndTokenPred is_end_token) { lexer.skip_token (); auto tok = lexer.peek_token (); + auto default_expr = parse_const_generic_expression (); - switch (tok->get_id ()) - { - case LEFT_CURLY: { - auto block = parse_block_expr (); - // pass block to `const_generic` - break; - } - case IDENTIFIER: { - auto ident = tok->get_str (); - // pass identifier to `const_generic` - break; - } - case MINUS: - case STRING_LITERAL: - case CHAR_LITERAL: - case INT_LITERAL: - case FLOAT_LITERAL: - case TRUE_LITERAL: - case FALSE_LITERAL: { - auto literal = parse_literal_expr (); - // pass literal to `const_generic` - break; - } - default: - rust_error_at (tok->get_locus (), - "invalid token for start of default value for " - "const generic parameter: expected %<block%>, " - "%<identifier%> or %<literal%>, got %qs", - token_id_to_str (tok->get_id ())); - } + if (!default_expr) + rust_error_at (tok->get_locus (), + "invalid token for start of default value for " + "const generic parameter: expected %<block%>, " + "%<identifier%> or %<literal%>, got %qs", + token_id_to_str (tok->get_id ())); } // param = std::unique_ptr<AST::GenericParam> (const_generic) @@ -6182,6 +6159,39 @@ Parser<ManagedTokenSource>::parse_type_path () has_opening_scope_resolution); } +template <typename ManagedTokenSource> +std::unique_ptr<AST::Expr> +Parser<ManagedTokenSource>::parse_const_generic_expression () +{ + auto tok = lexer.peek_token (); + switch (tok->get_id ()) + { + case LEFT_CURLY: + return parse_block_expr (); + case IDENTIFIER: { + lexer.skip_token (); + + // TODO: This is ambiguous with regular generic types. We probably need + // to differentiate later on during type checking, and thus keep a + // special variant here + + // return this + return std::unique_ptr<AST::IdentifierExpr> ( + new AST::IdentifierExpr (tok->get_str (), {}, tok->get_locus ())); + } + case MINUS: + case STRING_LITERAL: + case CHAR_LITERAL: + case INT_LITERAL: + case FLOAT_LITERAL: + case TRUE_LITERAL: + case FALSE_LITERAL: + return parse_literal_expr (); + default: + return nullptr; + } +} + // Parses the generic arguments in each path segment. template <typename ManagedTokenSource> AST::GenericArgs @@ -6193,6 +6203,9 @@ Parser<ManagedTokenSource>::parse_path_generic_args () return AST::GenericArgs::create_empty (); } + // We need to parse all lifetimes, then parse types and const generics in + // any order. + // try to parse lifetimes first std::vector<AST::Lifetime> lifetime_args; @@ -6222,35 +6235,42 @@ Parser<ManagedTokenSource>::parse_path_generic_args () // try to parse types second std::vector<std::unique_ptr<AST::Type>> type_args; + std::vector<std::unique_ptr<AST::Expr>> const_args; + + // TODO: Keep list of const expressions as well // TODO: think of better control structure t = lexer.peek_token (); while (!is_right_angle_tok (t->get_id ())) { + // FIXME: Is it fine to break if there is one binding? Can't there be + // bindings in between types? + // ensure not binding being parsed as type accidently if (t->get_id () == IDENTIFIER && lexer.peek_token (1)->get_id () == EQUAL) + break; + + auto type = parse_type (false); + if (type) { - break; + type_args.emplace_back (std::move (type)); } - - std::unique_ptr<AST::Type> type = parse_type (); - if (type == nullptr) + else { - // not necessarily an error - break; + auto const_generic_expr = parse_const_generic_expression (); + if (const_generic_expr) + const_args.emplace_back (std::move (const_generic_expr)); + else + break; } - type_args.push_back (std::move (type)); - // if next token isn't comma, then it must be end of list if (lexer.peek_token ()->get_id () != COMMA) - { - break; - } + break; + // skip comma lexer.skip_token (); - t = lexer.peek_token (); } @@ -8982,7 +9002,7 @@ Parser<ManagedTokenSource>::parse_grouped_or_tuple_expr ( // Parses a type (will further disambiguate any type). template <typename ManagedTokenSource> std::unique_ptr<AST::Type> -Parser<ManagedTokenSource>::parse_type () +Parser<ManagedTokenSource>::parse_type (bool save_errors) { /* rules for all types: * NeverType: '!' @@ -9034,9 +9054,12 @@ Parser<ManagedTokenSource>::parse_type () AST::QualifiedPathInType path = parse_qualified_path_in_type (); if (path.is_error ()) { - Error error (t->get_locus (), - "failed to parse qualified path in type"); - add_error (std::move (error)); + if (save_errors) + { + Error error (t->get_locus (), + "failed to parse qualified path in type"); + add_error (std::move (error)); + } return nullptr; } @@ -9085,9 +9108,12 @@ Parser<ManagedTokenSource>::parse_type () AST::TypePath path = parse_type_path (); if (path.is_error ()) { - Error error (t->get_locus (), - "failed to parse path as first component of type"); - add_error (std::move (error)); + if (save_errors) + { + Error error (t->get_locus (), + "failed to parse path as first component of type"); + add_error (std::move (error)); + } return nullptr; } @@ -9103,10 +9129,13 @@ Parser<ManagedTokenSource>::parse_type () AST::SimplePath macro_path = path.as_simple_path (); if (macro_path.is_empty ()) { - Error error (t->get_locus (), - "failed to parse simple path in macro " - "invocation (for type)"); - add_error (std::move (error)); + if (save_errors) + { + Error error (t->get_locus (), + "failed to parse simple path in macro " + "invocation (for type)"); + add_error (std::move (error)); + } return nullptr; } @@ -9190,9 +9219,12 @@ Parser<ManagedTokenSource>::parse_type () std::unique_ptr<AST::TraitBound> initial_bound = parse_trait_bound (); if (initial_bound == nullptr) { - Error error (lexer.peek_token ()->get_locus (), - "failed to parse ImplTraitType initial bound"); - add_error (std::move (error)); + if (save_errors) + { + Error error (lexer.peek_token ()->get_locus (), + "failed to parse ImplTraitType initial bound"); + add_error (std::move (error)); + } return nullptr; } @@ -9265,9 +9297,13 @@ Parser<ManagedTokenSource>::parse_type () = parse_trait_bound (); if (initial_bound == nullptr) { - Error error (lexer.peek_token ()->get_locus (), - "failed to parse TraitObjectType initial bound"); - add_error (std::move (error)); + if (save_errors) + { + Error error ( + lexer.peek_token ()->get_locus (), + "failed to parse TraitObjectType initial bound"); + add_error (std::move (error)); + } return nullptr; } @@ -9313,8 +9349,9 @@ Parser<ManagedTokenSource>::parse_type () } } default: - add_error (Error (t->get_locus (), "unrecognised token %qs in type", - t->get_token_description ())); + if (save_errors) + add_error (Error (t->get_locus (), "unrecognised token %qs in type", + t->get_token_description ())); return nullptr; } diff --git a/gcc/rust/parse/rust-parse.h b/gcc/rust/parse/rust-parse.h index d19bc71d310..f0aedfe6a22 100644 --- a/gcc/rust/parse/rust-parse.h +++ b/gcc/rust/parse/rust-parse.h @@ -138,7 +138,7 @@ public: */ std::unique_ptr<AST::Stmt> parse_stmt (ParseRestrictions restrictions = ParseRestrictions ()); - std::unique_ptr<AST::Type> parse_type (); + std::unique_ptr<AST::Type> parse_type (bool save_errors = true); std::unique_ptr<AST::ExternalItem> parse_external_item (); std::unique_ptr<AST::TraitItem> parse_trait_item (); std::unique_ptr<AST::InherentImplItem> parse_inherent_impl_item (); @@ -177,6 +177,7 @@ private: AST::TypePath parse_type_path (); std::unique_ptr<AST::TypePathSegment> parse_type_path_segment (); AST::PathIdentSegment parse_path_ident_segment (); + std::unique_ptr<AST::Expr> parse_const_generic_expression (); AST::GenericArgs parse_path_generic_args (); AST::GenericArgsBinding parse_generic_args_binding (); AST::TypePathFunction parse_type_path_function (Location locus); diff --git a/gcc/testsuite/rust/compile/const_generics_3.rs b/gcc/testsuite/rust/compile/const_generics_3.rs new file mode 100644 index 00000000000..6a3a0fe27bf --- /dev/null +++ b/gcc/testsuite/rust/compile/const_generics_3.rs @@ -0,0 +1,26 @@ +// { dg-additional-options "-w" } + +const M: usize = 4; + +struct Foo<T, const N: usize = 1> { + // FIXME: This error is bogus. But having it means parsing is valid! + value: [i32; N], // { dg-error "failed to find name: N" } +} + +fn main() { + let foo = Foo::<i32> { value: [15] }; + let foo = Foo::<i32, 2> { value: [15, 13] }; + let foo: Foo<i32, 2> = Foo { value: [15, 13] }; + let foo: Foo<i32, 2> = Foo::<i32, 2> { value: [15, 13] }; + let foo: Foo<i32, { 1 + 1 }> = Foo { value: [15, 13] }; + let foo = Foo::<i32, { 1 + 1 }> { value: [15, 13] }; + let foo: Foo<i32, { 1 + 1 }> = Foo::<i32, { 1 + 1 }> { value: [15, 13] }; + let foo: Foo<i32, M> = Foo::<i32, 4> { + value: [15, 13, 11, 9], + }; + + // FIXME: Add proper const typecheck errors here + let invalid_foo: Foo<i32, { 1 + 1 }> = Foo::<i32, 3> { value: [15, 13] }; + let invalid_foo: Foo<i32, { 1 + 1 }> = Foo::<i32, M> { value: [15, 13] }; + let invalid_foo: Foo<i32> = Foo::<i32, 2> { value: [15, 13] }; +}
reply other threads:[~2022-06-21 10:33 UTC|newest] Thread overview: [no followups] expand[flat|nested] mbox.gz Atom feed
Reply instructions: You may reply publicly to this message via plain-text email using any one of the following methods: * Save the following mbox file, import it into your mail client, and reply-to-all from there: mbox Avoid top-posting and favor interleaved quoting: https://en.wikipedia.org/wiki/Posting_style#Interleaved_style * Reply using the --to, --cc, and --in-reply-to switches of git-send-email(1): git send-email \ --in-reply-to=20220621103314.6EC9A3870901@sourceware.org \ --to=tschwinge@gcc.gnu.org \ --cc=gcc-cvs@gcc.gnu.org \ /path/to/YOUR_REPLY https://kernel.org/pub/software/scm/git/docs/git-send-email.html * If your mail client supports setting the In-Reply-To header via mailto: links, try the mailto: linkBe sure your reply has a Subject: header at the top and a blank line before the message body.
This is a public inbox, see mirroring instructions for how to clone and mirror all data and code used for this inbox; as well as URLs for read-only IMAP folder(s) and NNTP newsgroup(s).