Skip to content

Commit

Permalink
Report self parameter parsing error kind
Browse files Browse the repository at this point in the history
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 <pierre-emmanuel.patry@embecosm.com>
  • Loading branch information
P-E-P committed Nov 15, 2023
1 parent 122ffbe commit 5cbc768
Show file tree
Hide file tree
Showing 2 changed files with 56 additions and 28 deletions.
72 changes: 45 additions & 27 deletions gcc/rust/parse/rust-parse-impl.h
Original file line number Diff line number Diff line change
Expand Up @@ -2879,8 +2879,13 @@ Parser<ManagedTokenSource>::parse_function (AST::Visibility vis,
return nullptr;
}

std::unique_ptr<AST::Param> 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)
Expand All @@ -2890,9 +2895,9 @@ Parser<ManagedTokenSource>::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.value ()));

if (!skip_token (RIGHT_PAREN))
{
Expand Down Expand Up @@ -5060,13 +5065,15 @@ Parser<ManagedTokenSource>::parse_trait_item ()

/* now for function vs method disambiguation - method has opening
* "self" param */
std::unique_ptr<AST::Param> 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.value ()->is_self ())
is_method = true;

/* skip comma so function and method regular params can be parsed
Expand All @@ -5086,9 +5093,9 @@ Parser<ManagedTokenSource>::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.value ()));

// parse return type (optional)
std::unique_ptr<AST::Type> return_type = parse_function_return_type ();
Expand Down Expand Up @@ -5605,14 +5612,18 @@ Parser<ManagedTokenSource>::parse_inherent_impl_function_or_method (

// now for function vs method disambiguation - method has opening "self"
// param
std::unique_ptr<AST::Param> 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.value ()->is_self ())
is_method = true;

/* skip comma so function and method regular params can be parsed in
Expand All @@ -5625,9 +5636,9 @@ Parser<ManagedTokenSource>::parse_inherent_impl_function_or_method (
std::vector<std::unique_ptr<AST::Param>> 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.value ()));

if (!skip_token (RIGHT_PAREN))
{
Expand Down Expand Up @@ -5813,13 +5824,17 @@ Parser<ManagedTokenSource>::parse_trait_impl_function_or_method (

// now for function vs method disambiguation - method has opening "self"
// param
std::unique_ptr<AST::Param> 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.value ()->is_self ())
is_method = true;

// skip comma so function and method regular params can be parsed in
Expand Down Expand Up @@ -5857,9 +5872,9 @@ Parser<ManagedTokenSource>::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.value ()));

// DEBUG
rust_debug ("successfully parsed function params in function or method "
Expand Down Expand Up @@ -7108,7 +7123,7 @@ Parser<ManagedTokenSource>::parse_qualified_path_in_type ()

// Parses a self param. Also handles self param not existing.
template <typename ManagedTokenSource>
std::unique_ptr<AST::Param>
tl::expected<std::unique_ptr<AST::Param>, ParseSelfError>
Parser<ManagedTokenSource>::parse_self_param ()
{
bool has_reference = false;
Expand All @@ -7129,8 +7144,11 @@ Parser<ManagedTokenSource>::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 %<self%> by raw pointer");
{
rust_error_at (lexer.peek_token ()->get_locus (),
"cannot pass %<self%> by raw pointer");
return tl::make_unexpected (ParseSelfError::SELF_PTR);
}
}

// Trying to find those patterns:
Expand All @@ -7150,7 +7168,7 @@ Parser<ManagedTokenSource>::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)
Expand All @@ -7171,7 +7189,7 @@ Parser<ManagedTokenSource>::parse_self_param ()
add_error (std::move (error));

// skip after somewhere?
return nullptr;
return tl::make_unexpected (ParseSelfError::PARSING);
}
}
}
Expand All @@ -7189,7 +7207,7 @@ Parser<ManagedTokenSource>::parse_self_param ()
if (self_tok->get_id () != SELF)
{
// skip after somewhere?
return nullptr;
return tl::make_unexpected (ParseSelfError::NOT_SELF);
}
lexer.skip_token ();

Expand All @@ -7208,7 +7226,7 @@ Parser<ManagedTokenSource>::parse_self_param ()
add_error (std::move (error));

// skip after somewhere?
return nullptr;
return tl::make_unexpected (ParseSelfError::PARSING);
}
}

Expand All @@ -7221,7 +7239,7 @@ Parser<ManagedTokenSource>::parse_self_param ()
add_error (std::move (error));

// skip after somewhere?
return nullptr;
return tl::make_unexpected (ParseSelfError::PARSING);
}

if (has_reference)
Expand Down
12 changes: 11 additions & 1 deletion gcc/rust/parse/rust-parse.h
Original file line number Diff line number Diff line change
Expand Up @@ -21,6 +21,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
Expand Down Expand Up @@ -92,6 +94,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 <typename ManagedTokenSource> class Parser
Expand Down Expand Up @@ -334,7 +342,9 @@ template <typename ManagedTokenSource> class Parser
parse_trait_type (AST::AttrVec outer_attrs);
std::unique_ptr<AST::TraitItemConst>
parse_trait_const (AST::AttrVec outer_attrs);
std::unique_ptr<AST::Param> parse_self_param ();

tl::expected<std::unique_ptr<AST::Param>, ParseSelfError> parse_self_param ();

std::unique_ptr<AST::Impl> parse_impl (AST::Visibility vis,
AST::AttrVec outer_attrs);
std::unique_ptr<AST::InherentImplItem>
Expand Down

0 comments on commit 5cbc768

Please sign in to comment.