From d2f2f68a8d9d3ce71e97fb586318445d7e7cd984 Mon Sep 17 00:00:00 2001 From: Pierre-Emmanuel Patry Date: Wed, 15 Nov 2023 13:02:28 +0100 Subject: [PATCH] Report self parameter parsing error kind Self parameter parsing errors may come from different situations, which should not be handled in the same way. It is now possible to differentiate a missing self parameter from a self pointer or a parsing error. gcc/rust/ChangeLog: * parse/rust-parse-impl.h (Parser::parse_function): Early return on unrecoverable errors. (Parser::parse_trait_item): Likewise. (Parser::parse_self_param): Update return type. * parse/rust-parse.h (enum ParseSelfError): Add enumeration to describe different self parameter parsing errors. Signed-off-by: Pierre-Emmanuel Patry --- gcc/rust/parse/rust-parse-impl.h | 72 ++++++++++++++++++++------------ gcc/rust/parse/rust-parse.h | 12 +++++- 2 files changed, 56 insertions(+), 28 deletions(-) diff --git a/gcc/rust/parse/rust-parse-impl.h b/gcc/rust/parse/rust-parse-impl.h index eb5278232f47..5a276d13c4e9 100644 --- a/gcc/rust/parse/rust-parse-impl.h +++ b/gcc/rust/parse/rust-parse-impl.h @@ -2880,8 +2880,13 @@ Parser::parse_function (AST::Visibility vis, return nullptr; } - std::unique_ptr initial_param = parse_self_param (); - if (initial_param != nullptr) + auto initial_param = parse_self_param (); + + if (!initial_param.has_value () + && initial_param.error () != ParseSelfError::NOT_SELF) + return nullptr; + + if (initial_param.has_value ()) skip_token (COMMA); // parse function parameters (only if next token isn't right paren) @@ -2891,9 +2896,9 @@ Parser::parse_function (AST::Visibility vis, function_params = parse_function_params ([] (TokenId id) { return id == RIGHT_PAREN; }); - if (initial_param != nullptr) + if (initial_param.has_value ()) function_params.insert (function_params.begin (), - std::move (initial_param)); + std::move (*initial_param)); if (!skip_token (RIGHT_PAREN)) { @@ -5063,13 +5068,15 @@ Parser::parse_trait_item () /* now for function vs method disambiguation - method has opening * "self" param */ - std::unique_ptr initial_param = parse_self_param (); + auto initial_param = parse_self_param (); + if (!initial_param.has_value () && initial_param.error () != NOT_SELF) + return nullptr; /* FIXME: ensure that self param doesn't accidently consume tokens for * a function */ bool is_method = false; - if (initial_param != nullptr) + if (initial_param.has_value ()) { - if (initial_param->is_self ()) + if ((*initial_param)->is_self ()) is_method = true; /* skip comma so function and method regular params can be parsed @@ -5089,9 +5096,9 @@ Parser::parse_trait_item () return nullptr; } - if (initial_param != nullptr) + if (initial_param.has_value ()) function_params.insert (function_params.begin (), - std::move (initial_param)); + std::move (*initial_param)); // parse return type (optional) std::unique_ptr return_type = parse_function_return_type (); @@ -5609,14 +5616,18 @@ Parser::parse_inherent_impl_function_or_method ( // now for function vs method disambiguation - method has opening "self" // param - std::unique_ptr initial_param = parse_self_param (); + auto initial_param = parse_self_param (); + + if (!initial_param.has_value () && initial_param.error () != NOT_SELF) + return nullptr; + /* FIXME: ensure that self param doesn't accidently consume tokens for a * function one idea is to lookahead up to 4 tokens to see whether self is * one of them */ bool is_method = false; - if (initial_param != nullptr) + if (initial_param.has_value ()) { - if (initial_param->is_self ()) + if ((*initial_param)->is_self ()) is_method = true; /* skip comma so function and method regular params can be parsed in @@ -5629,9 +5640,9 @@ Parser::parse_inherent_impl_function_or_method ( std::vector> function_params = parse_function_params ([] (TokenId id) { return id == RIGHT_PAREN; }); - if (initial_param != nullptr) + if (initial_param.has_value ()) function_params.insert (function_params.begin (), - std::move (initial_param)); + std::move (*initial_param)); if (!skip_token (RIGHT_PAREN)) { @@ -5817,13 +5828,17 @@ Parser::parse_trait_impl_function_or_method ( // now for function vs method disambiguation - method has opening "self" // param - std::unique_ptr initial_param = parse_self_param (); + auto initial_param = parse_self_param (); + + if (!initial_param.has_value () && initial_param.error () != NOT_SELF) + return nullptr; + // FIXME: ensure that self param doesn't accidently consume tokens for a // function bool is_method = false; - if (initial_param != nullptr) + if (initial_param.has_value ()) { - if (initial_param->is_self ()) + if ((*initial_param)->is_self ()) is_method = true; // skip comma so function and method regular params can be parsed in @@ -5861,9 +5876,9 @@ Parser::parse_trait_impl_function_or_method ( } } - if (initial_param != nullptr) + if (initial_param.has_value ()) function_params.insert (function_params.begin (), - std::move (initial_param)); + std::move (*initial_param)); // DEBUG rust_debug ("successfully parsed function params in function or method " @@ -7112,7 +7127,7 @@ Parser::parse_qualified_path_in_type () // Parses a self param. Also handles self param not existing. template -std::unique_ptr +tl::expected, ParseSelfError> Parser::parse_self_param () { bool has_reference = false; @@ -7133,8 +7148,11 @@ Parser::parse_self_param () if (lexer.peek_token (i)->get_id () != s[i]) break; if (i == s.size ()) - rust_error_at (lexer.peek_token ()->get_locus (), - "cannot pass % by raw pointer"); + { + rust_error_at (lexer.peek_token ()->get_locus (), + "cannot pass % by raw pointer"); + return tl::make_unexpected (ParseSelfError::SELF_PTR); + } } // Trying to find those patterns: @@ -7154,7 +7172,7 @@ Parser::parse_self_param () is_self = true; if (!is_self) - return nullptr; + return tl::make_unexpected (ParseSelfError::NOT_SELF); // test if self is a reference parameter if (lexer.peek_token ()->get_id () == AMP) @@ -7175,7 +7193,7 @@ Parser::parse_self_param () add_error (std::move (error)); // skip after somewhere? - return nullptr; + return tl::make_unexpected (ParseSelfError::PARSING); } } } @@ -7193,7 +7211,7 @@ Parser::parse_self_param () if (self_tok->get_id () != SELF) { // skip after somewhere? - return nullptr; + return tl::make_unexpected (ParseSelfError::NOT_SELF); } lexer.skip_token (); @@ -7212,7 +7230,7 @@ Parser::parse_self_param () add_error (std::move (error)); // skip after somewhere? - return nullptr; + return tl::make_unexpected (ParseSelfError::PARSING); } } @@ -7225,7 +7243,7 @@ Parser::parse_self_param () add_error (std::move (error)); // skip after somewhere? - return nullptr; + return tl::make_unexpected (ParseSelfError::PARSING); } if (has_reference) diff --git a/gcc/rust/parse/rust-parse.h b/gcc/rust/parse/rust-parse.h index 08e6ce000f4d..e873d5292cde 100644 --- a/gcc/rust/parse/rust-parse.h +++ b/gcc/rust/parse/rust-parse.h @@ -22,6 +22,8 @@ along with GCC; see the file COPYING3. If not see #include "rust-ast-full.h" #include "rust-diagnostics.h" +#include "expected.h" + namespace Rust { /* HACK: used to resolve the expression-or-statement problem at the end of a * block by allowing either to be returned (technically). Tagged union would @@ -93,6 +95,12 @@ struct ParseRestrictions bool allow_close_after_expr_stmt = false; }; +enum ParseSelfError +{ + SELF_PTR, + PARSING, + NOT_SELF, +}; // Parser implementation for gccrs. // TODO: if updated to C++20, ManagedTokenSource would be useful as a concept template class Parser @@ -335,7 +343,9 @@ template class Parser parse_trait_type (AST::AttrVec outer_attrs, AST::Visibility); std::unique_ptr parse_trait_const (AST::AttrVec outer_attrs); - std::unique_ptr parse_self_param (); + + tl::expected, ParseSelfError> parse_self_param (); + std::unique_ptr parse_impl (AST::Visibility vis, AST::AttrVec outer_attrs); std::unique_ptr