[gccrs COMMIT 5/5] gccrs: refactor function qualifier parsing
gerris.rs@gmail.com
gerris.rs@gmail.com
Tue Mar 31 10:47:30 GMT 2026
From: Philipp Gesang <phg@phi-gamma.net>
gcc/rust/ChangeLog
* parse/rust-parse-impl.hxx: Refactor qualifier parsing
* parse/rust-parse.h: (parse_function_qualifiers) Likewise
Signed-off-by: Philipp Gesang <phg@phi-gamma.net>
---
This change was merged into the gccrs repository and is posted here for
upstream visibility and potential drive-by review, as requested by GCC
release managers.
Each commit email contains a link to its details on github from where you can
find the Pull-Request and associated discussions.
Commit on github: https://github.com/Rust-GCC/gccrs/commit/732732618557f25d87885d816d75f456fe3b03a3
The commit has been mentioned in the following pull-request(s):
- https://github.com/Rust-GCC/gccrs/pull/4463
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 fc9f45a8e..97bd5b15e 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 8df990476..dac39da36 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.53.0
More information about the Gcc-rust
mailing list