aboutsummaryrefslogtreecommitdiff
path: root/gcc
diff options
context:
space:
mode:
authorbors[bot] <26634292+bors[bot]@users.noreply.github.com>2022-06-17 07:12:29 +0000
committerGitHub <noreply@github.com>2022-06-17 07:12:29 +0000
commit848a1a28b91d105ff4f21cc9993befbcecb3e39d (patch)
tree8acf823dd2b8b35dee20c16b2b36d11f5ffa7e49 /gcc
parentd4a0780073bfaf96d72427d5138b74ef257ed625 (diff)
parent0dbfdb5cfc5cf64de086a85aadc1e58b115fb7f6 (diff)
downloadgcc-848a1a28b91d105ff4f21cc9993befbcecb3e39d.zip
gcc-848a1a28b91d105ff4f21cc9993befbcecb3e39d.tar.gz
gcc-848a1a28b91d105ff4f21cc9993befbcecb3e39d.tar.bz2
Merge #1315
1315: Add base for parsing const generic application r=CohenArthur a=CohenArthur 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. Co-authored-by: Arthur Cohen <arthur.cohen@embecosm.com>
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] };
+}