aboutsummaryrefslogtreecommitdiff
path: root/gcc
diff options
context:
space:
mode:
Diffstat (limited to 'gcc')
-rw-r--r--gcc/rust/ast/rust-path.h2
-rw-r--r--gcc/rust/parse/rust-parse-impl.h159
-rw-r--r--gcc/rust/parse/rust-parse.h3
-rw-r--r--gcc/testsuite/rust/compile/const_generics_3.rs26
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] };
+}