diff options
Diffstat (limited to 'gcc')
-rw-r--r-- | gcc/rust/ast/rust-path.h | 2 | ||||
-rw-r--r-- | gcc/rust/parse/rust-parse-impl.h | 159 | ||||
-rw-r--r-- | gcc/rust/parse/rust-parse.h | 3 | ||||
-rw-r--r-- | 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 45d08bf..a1f88d8 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 ae6ef4a..3a76d74 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 d19bc71..f0aedfe 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 0000000..6a3a0fe --- /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] }; +} |