From: Philipp Gesang <[email protected]> gcc/rust/ChangeLog * parse/rust-parse-impl.hxx: Refactor qualifier parsing * parse/rust-parse.h: (parse_function_qualifiers) Likewise
Signed-off-by: Philipp Gesang <[email protected]> --- gcc/rust/parse/rust-parse-impl.hxx | 236 ++++++++++++++++++----------- gcc/rust/parse/rust-parse.h | 16 +- 2 files changed, 159 insertions(+), 93 deletions(-) diff --git a/gcc/rust/parse/rust-parse-impl.hxx b/gcc/rust/parse/rust-parse-impl.hxx index fc9f45a8e5c..97bd5b15e1f 100644 --- a/gcc/rust/parse/rust-parse-impl.hxx +++ b/gcc/rust/parse/rust-parse-impl.hxx @@ -1638,7 +1638,7 @@ Parser<ManagedTokenSource>::parse_function (AST::Visibility vis, } return std::unique_ptr<AST::Function> (new AST::Function ( - std::move (function_name), std::move (*qualifiers.value ()), + std::move (function_name), std::move (qualifiers.value ()), std::move (generic_params), std::move (function_params), std::move (return_type), std::move (where_clause), std::move (body), std::move (vis), std::move (outer_attrs), locus, is_external)); @@ -1646,93 +1646,146 @@ Parser<ManagedTokenSource>::parse_function (AST::Visibility vis, // Parses function or method qualifiers (i.e. const, unsafe, and extern). template <typename ManagedTokenSource> -tl::expected<std::unique_ptr<AST::FunctionQualifiers>, Parse::Error::Node> +tl::expected<AST::FunctionQualifiers, Parse::Error::Node> Parser<ManagedTokenSource>::parse_function_qualifiers () +{ + location_t locus = lexer.peek_token ()->get_locus (); + + auto parsed = parse_function_qualifiers_raw (locus); + if (!parsed) + return tl::unexpected<Parse::Error::Node> (parsed.error ()); + + return function_qualifiers_from_keywords (locus, std::move (parsed->first), + std::move (parsed->second)); +} + +// Take the list of parsed function qualifiers and convert it to +// the corrresponding flags to pass to the AST item constructor. +// +// This assumes ``keywords`` contains only those tokens that +// map to qualifiers. +template <typename ManagedTokenSource> +tl::expected<AST::FunctionQualifiers, Parse::Error::Node> +Parser<ManagedTokenSource>::function_qualifiers_from_keywords ( + location_t locus, const std::vector<TokenId> keywords, std::string abi) { Default default_status = Default::No; Async async_status = Async::No; Const const_status = Const::No; Unsafety unsafe_status = Unsafety::Normal; bool has_extern = false; - std::string abi; - // collect all qualifiers before checking the order to allow for a better - // error message - std::vector<TokenId> found_order; + for (auto qualifier : keywords) + { + switch (qualifier) + { + case IDENTIFIER: + // only "default" is valid in this context + default_status = Default::Yes; + continue; + case CONST: + const_status = Const::Yes; + continue; + case ASYNC: + async_status = Async::Yes; + continue; + case UNSAFE: + unsafe_status = Unsafety::Unsafe; + continue; + case EXTERN_KW: + has_extern = true; + continue; + default: + // non-qualifier token in input + rust_unreachable (); + } + } - const_TokenPtr t; - location_t locus = lexer.peek_token ()->get_locus (); + return AST::FunctionQualifiers (locus, default_status, async_status, + const_status, unsafe_status, has_extern, + std::move (abi)); +} + +// this consumes as many function qualifier tokens while ensuring +// uniqueness. +template <typename ManagedTokenSource> +tl::expected<std::pair<std::vector<TokenId>, std::string>, Parse::Error::Node> +Parser<ManagedTokenSource>::parse_function_qualifiers_raw (location_t locus) +{ + std::vector<TokenId> found_order; + std::string abi; // this will terminate on duplicates or the first non-qualifier token while (true) { - const TokenId token_id = lexer.peek_token ()->get_id (); - - if (std::find (found_order.cbegin (), found_order.cend (), token_id) - != found_order.cend ()) - { - // qualifiers mustn't appear twice - Error error (lexer.peek_token ()->get_locus (), - "encountered duplicate function qualifier %qs", - lexer.peek_token ()->get_token_description ()); - add_error (std::move (error)); - - return tl::unexpected<Parse::Error::Node> ( - Parse::Error::Node::MALFORMED); - } + auto token = lexer.peek_token (); + const TokenId token_id = token->get_id (); + location_t locus = lexer.peek_token ()->get_locus (); switch (token_id) { case IDENTIFIER: - if (lexer.peek_token ()->get_str () != Values::WeakKeywords::DEFAULT) + if (token->get_str () != Values::WeakKeywords::DEFAULT) { - // only "default" is valid in this context + // only "default" is valid in this context, so this must + // be a non-qualifier keyword goto done; } - default_status = Default::Yes; - break; + // fallthrough case CONST: - const_status = Const::Yes; - break; case ASYNC: - async_status = Async::Yes; - break; case UNSAFE: - unsafe_status = Unsafety::Unsafe; + found_order.push_back (token_id); + lexer.skip_token (); break; case EXTERN_KW: { - has_extern = true; - // detect optional abi name + found_order.push_back (token_id); lexer.skip_token (); + + // detect optional abi name const_TokenPtr next_tok = lexer.peek_token (); if (next_tok->get_id () == STRING_LITERAL) { abi = next_tok->get_str (); + lexer.skip_token (); } } break; default: + // non-qualifier keyword goto done; } - found_order.push_back (token_id); - lexer.skip_token (); + + if (std::count (found_order.cbegin (), found_order.cend (), token_id) > 1) + { + // qualifiers mustn't appear twice + Error error (locus, "encountered duplicate function qualifier %qs", + token->get_token_description ()); + add_error (std::move (error)); + + return tl::unexpected<Parse::Error::Node> ( + Parse::Error::Node::MALFORMED); + } } done: - if (!ensure_function_qualifier_order (locus, std::move (found_order))) + if (!ensure_function_qualifier_order (locus, found_order)) return tl::unexpected<Parse::Error::Node> (Parse::Error::Node::MALFORMED); - return std::unique_ptr<AST::FunctionQualifiers> ( - new AST::FunctionQualifiers (locus, default_status, async_status, - const_status, unsafe_status, has_extern, - std::move (abi))); + return make_pair (found_order, abi); } +// Validate the order of the list of function qualifiers; this assumes that +// ``found_order`` consists only of function qualifier tokens. +// +// If the order is illegal, the generated error message gives both the wrong +// order as found in the source and the correct order according to Rust syntax +// rules. template <typename ManagedTokenSource> bool Parser<ManagedTokenSource>::ensure_function_qualifier_order ( - location_t locus, std::vector<TokenId> found_order) + location_t locus, const std::vector<TokenId> &found_order) { // Check in order of default, const, async, unsafe, extern auto token_priority = [] (const TokenId id) { @@ -1759,62 +1812,65 @@ Parser<ManagedTokenSource>::ensure_function_qualifier_order ( const size_t priority = token_priority (token_id); if (priority <= last_priority) { - auto qualifiers_to_str = [] (const std::vector<TokenId> &token_ids) { - std::ostringstream ss; + emit_function_qualifier_order_error_msg (locus, found_order); + return false; + } - for (auto id : token_ids) - { - if (ss.tellp () != 0) - ss << ' '; + last_priority = priority; + } - if (id == IDENTIFIER) - ss << Values::WeakKeywords::DEFAULT; - else - ss << token_id_keyword_string (id); - } + return true; +} - return ss.str (); - }; +template <typename ManagedTokenSource> +void +Parser<ManagedTokenSource>::emit_function_qualifier_order_error_msg ( + location_t locus, const std::vector<TokenId> &found_order) +{ + std::vector<TokenId> expected_order + = {IDENTIFIER, CONST, ASYNC, UNSAFE, EXTERN_KW}; - std::vector<TokenId> expected_order - = {IDENTIFIER, CONST, ASYNC, UNSAFE, EXTERN_KW}; + // we only keep the qualifiers actually used in the offending code + std::vector<TokenId>::iterator token_id = expected_order.begin (); + while (token_id != expected_order.end ()) + { + if (std::find (found_order.cbegin (), found_order.cend (), *token_id) + == found_order.cend ()) + { + token_id = expected_order.erase (token_id); + } + else + { + ++token_id; + } + } - // we only keep the qualifiers actually used in the offending code - std::vector<TokenId>::const_iterator token_id - = expected_order.cbegin (); - while (token_id != expected_order.cend ()) - { - if (std::find (found_order.cbegin (), found_order.cend (), - *token_id) - == found_order.cend ()) - { - token_id = expected_order.erase (token_id); - } - else - { - ++token_id; - } - } + auto qualifiers_to_str = [] (const std::vector<TokenId> &token_ids) { + std::ostringstream ss; - const std::string found_qualifiers = qualifiers_to_str (found_order); - const std::string expected_qualifiers - = qualifiers_to_str (expected_order); + for (auto id : token_ids) + { + if (ss.tellp () != 0) + ss << ' '; - location_t error_locus - = make_location (locus, locus, lexer.peek_token ()->get_locus ()); - Error error ( - error_locus, - "invalid order of function qualifiers; found %qs, expected %qs", - found_qualifiers.c_str (), expected_qualifiers.c_str ()); - add_error (std::move (error)); + if (id == IDENTIFIER) + ss << Values::WeakKeywords::DEFAULT; + else + ss << token_id_keyword_string (id); + } - return false; - } + return ss.str (); + }; - last_priority = priority; - } + const std::string found_qualifiers = qualifiers_to_str (found_order); + const std::string expected_qualifiers = qualifiers_to_str (expected_order); - return true; + location_t error_locus + = make_location (locus, locus, lexer.peek_token ()->get_locus ()); + Error error (error_locus, + "invalid order of function qualifiers; found %qs, expected %qs", + found_qualifiers.c_str (), expected_qualifiers.c_str ()); + add_error (std::move (error)); } // Parses generic (lifetime or type) params inside angle brackets (optional). @@ -4479,7 +4535,7 @@ Parser<ManagedTokenSource>::parse_inherent_impl_function_or_method ( } return std::unique_ptr<AST::Function> ( - new AST::Function (std::move (ident), std::move (*qualifiers.value ()), + new AST::Function (std::move (ident), std::move (qualifiers.value ()), std::move (generic_params), std::move (function_params), std::move (return_type), std::move (where_clause), std::move (body), std::move (vis), @@ -4709,7 +4765,7 @@ Parser<ManagedTokenSource>::parse_trait_impl_function_or_method ( } return std::unique_ptr<AST::Function> ( - new AST::Function (std::move (ident), std::move (*qualifiers.value ()), + new AST::Function (std::move (ident), std::move (qualifiers.value ()), std::move (generic_params), std::move (function_params), std::move (return_type), std::move (where_clause), std::move (body), std::move (vis), @@ -6407,7 +6463,7 @@ Parser<ManagedTokenSource>::parse_bare_function_type ( } return std::unique_ptr<AST::BareFunctionType> (new AST::BareFunctionType ( - std::move (for_lifetimes), std::move (*qualifiers.value ()), + std::move (for_lifetimes), std::move (qualifiers.value ()), std::move (params), is_variadic, std::move (variadic_attrs), std::move (return_type), best_try_locus)); } diff --git a/gcc/rust/parse/rust-parse.h b/gcc/rust/parse/rust-parse.h index 8df9904766a..dac39da3660 100644 --- a/gcc/rust/parse/rust-parse.h +++ b/gcc/rust/parse/rust-parse.h @@ -364,10 +364,20 @@ private: std::unique_ptr<AST::Function> parse_function (AST::Visibility vis, AST::AttrVec outer_attrs, bool is_external = false); - tl::expected<std::unique_ptr<AST::FunctionQualifiers>, Parse::Error::Node> + tl::expected<AST::FunctionQualifiers, Parse::Error::Node> parse_function_qualifiers (); - bool ensure_function_qualifier_order (location_t locus, - std::vector<TokenId> found_order); + tl::expected<std::pair<std::vector<TokenId>, std::string>, Parse::Error::Node> + parse_function_qualifiers_raw (location_t locus); + bool + ensure_function_qualifier_order (location_t locus, + const std::vector<TokenId> &found_order); + tl::expected<AST::FunctionQualifiers, Parse::Error::Node> + function_qualifiers_from_keywords (location_t locus, + std::vector<TokenId> keywords, + std::string abi); + void emit_function_qualifier_order_error_msg ( + location_t locus, const std::vector<TokenId> &found_order); + std::vector<std::unique_ptr<AST::GenericParam>> parse_generic_params_in_angles (); template <typename EndTokenPred> -- 2.50.1
