From: Pierre-Emmanuel Patry <[email protected]>
We made heavy use of error state within some AST node and it was the
source of multiple errors, and caused confusion with (null) pointers.
This commit removes some error state use within our parser in an attempt
to remove those error states later.
gcc/rust/ChangeLog:
* parse/rust-parse-impl.h (Parser::parse_inner_attributes): Change
return type to avoid empty/error values that may break invariants in
the AST.
(Parser::parse_inner_attribute): Likewise.
(Parser::parse_outer_attribute): Likewise.
(Parser::parse_outer_attributes): Likewise.
(Parser::parse_attribute_body): Likewise.
(Parser::parse_simple_path): Likewise.
(Parser::parse_macro_invocation): Likewise.
(Parser::parse_visibility): Likewise.
(Parser::parse_use_tree): Likewise.
(Parser::parse_delim_token_tree): Likewise.
(Parser::parse_identifier_or_keyword_token): Likewise.
(Parser::parse_token_tree): Likewise.
(Parser::parse_macro_rules_def): Likewise.
(Parser::parse_decl_macro_def): Likewise.
(Parser::parse_macro_invocation): Likewise.
(Parser::parse_macro_rule): Likewise.
(Parser::parse_macro_matcher): Likewise.
(Parser::parse_type_path_segment): Likewise.
(Parser::parse_path_expr_segment): Likewise.
(Parser::parse_type): Likewise.
(Parser::parse_type_no_bounds): Likewise.
(Parser::parse_items): Circumvent GCC 5 to 7 bug.
(is_simple_path_segment): Move to utility file.
(token_id_matches_delims): Likewise.
(is_likely_path_next): Remove unused function.
(Parser::parse_attr_input): Return a structure instead of a tuple.
* expand/rust-macro-builtins-offset-of.cc: Adapt call to expected.
* ast/rust-ast.cc (AttributeParser::parse_path_meta_item): Use empty
vector when an error is encountered.
* expand/rust-macro-builtins-include.cc: Likewise.
* parse/rust-parse.h: Update prototypes.
* parse/rust-parse-impl-proc-macro.cc: Likewise.
* ast/rust-ast.h: Remove error state from Visibility.
* ast/rust-item.h: Use private visibility instead of error.
* ast/rust-macro.h: Likewise.
* expand/rust-macro-expand.cc: Likewise.
* hir/rust-ast-lower.cc: Remove error case.
* rust-session-manager.cc: Use private visibility
* parse/rust-parse-utils.h: New file.
* parse/rust-parse-error.h: New file.
gcc/testsuite/ChangeLog:
* rust/compile/macros/mbe/macro-issue3608.rs: Update error messages.
Signed-off-by: Pierre-Emmanuel Patry <[email protected]>
---
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/40765b86cc37cd0ab4a1b6ca4d6803fc3671d3b0
The commit has been mentioned in the following pull-request(s):
- https://github.com/Rust-GCC/gccrs/pull/4288
gcc/rust/ast/rust-ast.cc | 14 +-
gcc/rust/ast/rust-ast.h | 23 +-
gcc/rust/ast/rust-item.h | 16 +-
gcc/rust/ast/rust-macro.h | 2 +-
.../expand/rust-macro-builtins-include.cc | 3 +-
.../expand/rust-macro-builtins-offset-of.cc | 4 +-
gcc/rust/expand/rust-macro-expand.cc | 8 +-
gcc/rust/hir/rust-ast-lower.cc | 4 +-
gcc/rust/parse/rust-parse-error.h | 326 +++++++++++
gcc/rust/parse/rust-parse-impl-proc-macro.cc | 2 +-
gcc/rust/parse/rust-parse-impl.h | 536 +++++++++---------
gcc/rust/parse/rust-parse-utils.h | 73 +++
gcc/rust/parse/rust-parse.h | 39 +-
gcc/rust/rust-session-manager.cc | 2 +-
.../compile/macros/mbe/macro-issue3608.rs | 2 -
15 files changed, 736 insertions(+), 318 deletions(-)
create mode 100644 gcc/rust/parse/rust-parse-error.h
create mode 100644 gcc/rust/parse/rust-parse-utils.h
diff --git a/gcc/rust/ast/rust-ast.cc b/gcc/rust/ast/rust-ast.cc
index 851f7ea4b..f15cc3d3c 100644
--- a/gcc/rust/ast/rust-ast.cc
+++ b/gcc/rust/ast/rust-ast.cc
@@ -3490,7 +3490,9 @@ Module::load_items ()
// we need to parse any possible inner attributes for this module
inner_attrs = parser.parse_inner_attributes ();
- auto parsed_items = parser.parse_items ();
+ auto parsed_items = parser.parse_items ().value_or (
+ std::vector<std::unique_ptr<AST::Item>>{});
+
for (const auto &error : parser.get_errors ())
error.emit ();
@@ -3705,8 +3707,8 @@ AttributeParser::is_end_meta_item_tok (TokenId id) const
std::unique_ptr<MetaItem>
AttributeParser::parse_path_meta_item ()
{
- SimplePath path = parser->parse_simple_path ();
- if (path.is_empty ())
+ auto path = parser->parse_simple_path ();
+ if (!path)
{
rust_error_at (lexer->peek_token ()->get_locus (),
"failed to parse simple path in attribute");
@@ -3721,7 +3723,7 @@ AttributeParser::parse_path_meta_item ()
= parse_meta_item_seq ();
return std::unique_ptr<MetaItemSeq> (
- new MetaItemSeq (std::move (path), std::move (meta_items)));
+ new MetaItemSeq (std::move (path.value ()), std::move (meta_items)));
}
case EQUAL:
{
@@ -3735,12 +3737,12 @@ AttributeParser::parse_path_meta_item ()
return nullptr;
return std::unique_ptr<MetaItemPathExpr> (
- new MetaItemPathExpr (std::move (path), std::move (expr)));
+ new MetaItemPathExpr (std::move (path.value ()), std::move (expr)));
}
case COMMA:
// just simple path
return std::unique_ptr<MetaItemPath> (
- new MetaItemPath (std::move (path)));
+ new MetaItemPath (std::move (path.value ())));
default:
rust_error_at (lexer->peek_token ()->get_locus (),
"unrecognised token '%s' in meta item",
diff --git a/gcc/rust/ast/rust-ast.h b/gcc/rust/ast/rust-ast.h
index 8610ade83..07ce5bf9f 100644
--- a/gcc/rust/ast/rust-ast.h
+++ b/gcc/rust/ast/rust-ast.h
@@ -477,38 +477,21 @@ private:
SimplePath in_path;
location_t locus;
- // should this store location info?
-
-public:
- // Creates a Visibility - TODO make constructor protected or private?
Visibility (VisType vis_type, SimplePath in_path, location_t locus)
: vis_type (vis_type), in_path (std::move (in_path)), locus (locus)
{}
+public:
VisType get_vis_type () const { return vis_type; }
- // Returns whether visibility is in an error state.
- bool is_error () const
- {
- return vis_type == PUB_IN_PATH && in_path.is_empty ();
- }
-
// Returns whether a visibility has a path
- bool has_path () const { return !is_error () && vis_type >= PUB_CRATE; }
+ bool has_path () const { return vis_type >= PUB_CRATE; }
// Returns whether visibility is public or not.
- bool is_public () const { return vis_type != PRIV && !is_error (); }
+ bool is_public () const { return vis_type != PRIV; }
location_t get_locus () const { return locus; }
- // empty?
- // Creates an error visibility.
- static Visibility create_error ()
- {
- return Visibility (PUB_IN_PATH, SimplePath::create_empty (),
- UNDEF_LOCATION);
- }
-
// Unique pointer custom clone function
/*std::unique_ptr<Visibility> clone_visibility() const {
return std::unique_ptr<Visibility>(clone_visibility_impl());
diff --git a/gcc/rust/ast/rust-item.h b/gcc/rust/ast/rust-item.h
index 3e3735c3e..d04f7fad6 100644
--- a/gcc/rust/ast/rust-item.h
+++ b/gcc/rust/ast/rust-item.h
@@ -814,7 +814,7 @@ public:
// Loaded module constructor, with items
Module (Identifier name, location_t locus,
std::vector<std::unique_ptr<Item>> items,
- Visibility visibility = Visibility::create_error (),
+ Visibility visibility = Visibility::create_private (),
Unsafety safety = Unsafety::Normal,
std::vector<Attribute> inner_attrs = std::vector<Attribute> (),
std::vector<Attribute> outer_attrs = std::vector<Attribute> ())
@@ -1743,7 +1743,7 @@ public:
bool has_outer_attributes () const { return !outer_attrs.empty (); }
// Returns whether struct field has a non-private (non-default) visibility.
- bool has_visibility () const { return !visibility.is_error (); }
+ bool has_visibility () const { return true; }
StructField (Identifier field_name, std::unique_ptr<Type> field_type,
Visibility vis, location_t locus,
@@ -1797,8 +1797,8 @@ public:
// Creates an error state struct field.
static StructField create_error ()
{
- return StructField (std::string (""), nullptr, Visibility::create_error (),
- UNDEF_LOCATION);
+ return StructField (std::string (""), nullptr,
+ Visibility::create_private (), UNDEF_LOCATION);
}
std::string as_string () const;
@@ -1902,7 +1902,7 @@ public:
/* Returns whether tuple field has a non-default visibility (i.e. a public
* one) */
- bool has_visibility () const { return !visibility.is_error (); }
+ bool has_visibility () const { return true; }
// Complete constructor
TupleField (std::unique_ptr<Type> field_type, Visibility vis,
@@ -1952,7 +1952,7 @@ public:
// Creates an error state tuple field.
static TupleField create_error ()
{
- return TupleField (nullptr, Visibility::create_error (), UNDEF_LOCATION);
+ return TupleField (nullptr, Visibility::create_private (), UNDEF_LOCATION);
}
std::string as_string () const;
@@ -3389,7 +3389,7 @@ public:
bool has_outer_attrs () const { return !outer_attrs.empty (); }
// Returns whether item has non-default visibility.
- bool has_visibility () const { return !visibility.is_error (); }
+ bool has_visibility () const { return true; }
location_t get_locus () const { return locus; }
@@ -3481,7 +3481,7 @@ public:
bool has_outer_attrs () const { return !outer_attrs.empty (); }
// Returns whether item has non-default visibility.
- bool has_visibility () const { return !visibility.is_error (); }
+ bool has_visibility () const { return true; }
location_t get_locus () const { return locus; }
diff --git a/gcc/rust/ast/rust-macro.h b/gcc/rust/ast/rust-macro.h
index 71de8f022..e9d2930a7 100644
--- a/gcc/rust/ast/rust-macro.h
+++ b/gcc/rust/ast/rust-macro.h
@@ -529,7 +529,7 @@ public:
return std::make_unique<MacroRulesDefinition> (
MacroRulesDefinition (rule_name, delim_type, rules, outer_attrs, locus,
AST::MacroRulesDefinition::MacroKind::MBE,
- AST::Visibility::create_error ()));
+ AST::Visibility::create_private ()));
}
static std::unique_ptr<MacroRulesDefinition>
diff --git a/gcc/rust/expand/rust-macro-builtins-include.cc
b/gcc/rust/expand/rust-macro-builtins-include.cc
index 2ab2a3a1d..bae5c181f 100644
--- a/gcc/rust/expand/rust-macro-builtins-include.cc
+++ b/gcc/rust/expand/rust-macro-builtins-include.cc
@@ -248,7 +248,8 @@ MacroBuiltin::include_handler (location_t invoc_locus,
std::vector<std::unique_ptr<AST::Item>> parsed_items{};
if (is_semicoloned)
- parsed_items = parser.parse_items ();
+ parsed_items = parser.parse_items ().value_or (
+ std::vector<std::unique_ptr<AST::Item>>{});
else
parsed_expr = parser.parse_expr ();
diff --git a/gcc/rust/expand/rust-macro-builtins-offset-of.cc
b/gcc/rust/expand/rust-macro-builtins-offset-of.cc
index 02c637beb..25bc290ed 100644
--- a/gcc/rust/expand/rust-macro-builtins-offset-of.cc
+++ b/gcc/rust/expand/rust-macro-builtins-offset-of.cc
@@ -56,7 +56,7 @@ MacroBuiltin::offset_of_handler (location_t invoc_locus,
parser.skip_token (COMMA);
auto field_tok = parser.parse_identifier_or_keyword_token ();
- auto invalid_field = !field_tok || !field_tok->should_have_str ();
+ auto invalid_field = !field_tok || !field_tok.value ()->should_have_str ();
if (invalid_field)
rust_error_at (invoc_locus, "could not parse field argument for %qs",
@@ -65,7 +65,7 @@ MacroBuiltin::offset_of_handler (location_t invoc_locus,
if (!type || invalid_field)
return tl::nullopt;
- auto field = Identifier (field_tok->get_str ());
+ auto field = Identifier (field_tok.value ()->get_str ());
// FIXME: Do we need to do anything to handle the optional comma at the end?
parser.maybe_skip_token (COMMA);
diff --git a/gcc/rust/expand/rust-macro-expand.cc
b/gcc/rust/expand/rust-macro-expand.cc
index b47e43afd..450458904 100644
--- a/gcc/rust/expand/rust-macro-expand.cc
+++ b/gcc/rust/expand/rust-macro-expand.cc
@@ -858,7 +858,9 @@ transcribe_many_items (Parser<MacroInvocLexer> &parser,
TokenId &delimiter)
{
return parse_many (parser, delimiter, [&parser] () {
auto item = parser.parse_item (true);
- return AST::SingleASTNode (std::move (item));
+ if (!item)
+ return AST::SingleASTNode (std::unique_ptr<AST::Item> (nullptr));
+ return AST::SingleASTNode (std::move (item.value ()));
});
}
@@ -1191,9 +1193,9 @@ MacroExpander::parse_proc_macro_output
(ProcMacro::TokenStream ts)
while (lex.peek_token ()->get_id () != END_OF_FILE)
{
auto result = parser.parse_item (false);
- if (result == nullptr)
+ if (!result)
break;
- nodes.emplace_back (std::move (result));
+ nodes.emplace_back (std::move (result.value ()));
}
break;
case ContextType::STMT:
diff --git a/gcc/rust/hir/rust-ast-lower.cc b/gcc/rust/hir/rust-ast-lower.cc
index 5b8e7c514..758bc59f5 100644
--- a/gcc/rust/hir/rust-ast-lower.cc
+++ b/gcc/rust/hir/rust-ast-lower.cc
@@ -38,8 +38,6 @@ translate_visibility (const AST::Visibility &vis)
// the AST vis is an error?
// FIXME: We need to add a `create_private()` static function to the
// AST::Visibility class and use it when the vis is empty in the parser...
- if (vis.is_error ())
- return Visibility::create_error ();
switch (vis.get_vis_type ())
{
@@ -57,7 +55,7 @@ translate_visibility (const AST::Visibility &vis)
break;
}
- return Visibility::create_error ();
+ rust_unreachable ();
}
ASTLowering::ASTLowering (AST::Crate &astCrate) : astCrate (astCrate) {}
diff --git a/gcc/rust/parse/rust-parse-error.h
b/gcc/rust/parse/rust-parse-error.h
new file mode 100644
index 000000000..e3eb201f7
--- /dev/null
+++ b/gcc/rust/parse/rust-parse-error.h
@@ -0,0 +1,326 @@
+// Copyright (C) 2025 Free Software Foundation, Inc.
+
+// This file is part of GCC.
+
+// GCC is free software; you can redistribute it and/or modify it under
+// the terms of the GNU General Public License as published by the Free
+// Software Foundation; either version 3, or (at your option) any later
+// version.
+
+// GCC is distributed in the hope that it will be useful, but WITHOUT ANY
+// WARRANTY; without even the implied warranty of MERCHANTABILITY or
+// FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
+// for more details.
+
+// You should have received a copy of the GNU General Public License
+// along with GCC; see the file COPYING3. If not see
+// <http://www.gnu.org/licenses/>.
+
+#ifndef RUST_PARSE_ERROR_H
+#define RUST_PARSE_ERROR_H
+
+#include "expected.h"
+#include "rust-ast.h"
+#include "rust-parse-utils.h"
+
+namespace Rust {
+namespace Parse {
+namespace Error {
+
+struct Attribute
+{
+ static tl::expected<AST::Attribute, Attribute> make_malformed ()
+ {
+ return tl::unexpected<Attribute> (Attribute (Kind::MALFORMED));
+ }
+
+ static tl::expected<AST::Attribute, Attribute> make_malformed_body ()
+ {
+ return tl::unexpected<Attribute> (Attribute (Kind::MALFORMED_BODY));
+ }
+
+ static tl::expected<AST::Attribute, Attribute> make_unexpected_inner ()
+ {
+ return tl::unexpected<Attribute> (Attribute (Kind::UNEXPECTED_INNER));
+ }
+
+ enum class Kind
+ {
+ MALFORMED,
+ MALFORMED_BODY,
+ UNEXPECTED_INNER,
+ } kind;
+
+private:
+ Attribute (Kind kind) : kind (kind) {}
+};
+
+struct SimplePath
+{
+ static tl::expected<AST::SimplePath, SimplePath> make_malformed ()
+ {
+ return tl::unexpected<SimplePath> (SimplePath (Kind::MALFORMED));
+ }
+
+ enum class Kind
+ {
+ MALFORMED,
+ } kind;
+
+private:
+ SimplePath (Kind kind) : kind (kind) {}
+};
+
+struct AttributeBody
+{
+ static tl::expected<Parse::AttributeBody, AttributeBody> make_invalid_path ()
+ {
+ return tl::unexpected<AttributeBody> (AttributeBody (Kind::INVALID_PATH));
+ }
+
+ static tl::expected<Parse::AttributeBody, AttributeBody>
+ make_invalid_attrinput ()
+ {
+ return tl::unexpected<AttributeBody> (
+ AttributeBody (Kind::INVALID_ATTRINPUT));
+ }
+
+ enum class Kind
+ {
+ INVALID_PATH,
+ INVALID_ATTRINPUT,
+ } kind;
+
+private:
+ AttributeBody (Kind kind) : kind (kind) {}
+};
+
+struct SimplePathSegment
+{
+ static tl::expected<AST::SimplePathSegment, SimplePathSegment>
+ make_invalid_token_or_path_end ()
+ {
+ return tl::unexpected<SimplePathSegment> (
+ SimplePathSegment (Kind::INVALID_SIMPLE_PATH_TOKEN));
+ }
+
+ enum class Kind
+ {
+ /* Invalid token found whilst parsing a simple path segment, could be an
+ error or the end of the path */
+ INVALID_SIMPLE_PATH_TOKEN,
+ } kind;
+
+private:
+ SimplePathSegment (Kind kind) : kind (kind) {}
+};
+
+struct PathIdentSegment
+{
+ static tl::expected<AST::PathIdentSegment, PathIdentSegment>
+ make_invalid_token ()
+ {
+ return tl::unexpected<PathIdentSegment> (
+ PathIdentSegment (Kind::INVALID_PATH_IDENT_TOKEN));
+ }
+
+ enum class Kind
+ {
+ INVALID_PATH_IDENT_TOKEN,
+ } kind;
+
+private:
+ PathIdentSegment (Kind kind) : kind (kind) {}
+};
+
+struct AttrInput
+{
+ static tl::expected<std::unique_ptr<AST::AttrInput>, AttrInput>
+ make_malformed ()
+ {
+ return tl::unexpected<AttrInput> (AttrInput (Kind::MALFORMED));
+ }
+
+ static tl::expected<std::unique_ptr<AST::AttrInput>, AttrInput>
+ make_bad_macro_invocation ()
+ {
+ return tl::unexpected<AttrInput> (AttrInput (Kind::BAD_MACRO_INVOCATION));
+ }
+
+ static tl::expected<std::unique_ptr<AST::AttrInput>, AttrInput>
+ make_missing_attrinput ()
+ {
+ return tl::unexpected<AttrInput> (AttrInput (Kind::MISSING));
+ }
+
+ static tl::expected<std::unique_ptr<AST::AttrInput>, AttrInput>
+ make_bad_token_tree ()
+ {
+ return tl::unexpected<AttrInput> (AttrInput (Kind::BAD_TOKEN_TREE));
+ }
+
+ enum class Kind
+ {
+ MALFORMED,
+ BAD_MACRO_INVOCATION,
+ BAD_TOKEN_TREE,
+ // Not an hard error in some context
+ MISSING,
+ } kind;
+
+private:
+ AttrInput (Kind kind) : kind (kind) {}
+};
+
+struct DelimTokenTree
+{
+ static tl::expected<AST::DelimTokenTree, DelimTokenTree>
+ make_expected_delimiter ()
+ {
+ return tl::unexpected<DelimTokenTree> (
+ DelimTokenTree (Kind::EXPECTED_DELIMITER));
+ }
+
+ static tl::expected<AST::DelimTokenTree, DelimTokenTree>
+ make_invalid_token_tree ()
+ {
+ return tl::unexpected<DelimTokenTree> (
+ DelimTokenTree (Kind::INVALID_TOKEN_TREE));
+ }
+
+ static tl::expected<AST::DelimTokenTree, DelimTokenTree>
+ make_mismatched_delimiters ()
+ {
+ return tl::unexpected<DelimTokenTree> (
+ DelimTokenTree (Kind::INVALID_TOKEN_TREE));
+ }
+
+ enum class Kind
+ {
+ EXPECTED_DELIMITER,
+ INVALID_TOKEN_TREE,
+ MISMATCHED_DELIMITERS,
+ } kind;
+
+private:
+ DelimTokenTree (Kind kind) : kind (kind) {}
+};
+
+struct Token
+{
+ static tl::expected<std::unique_ptr<AST::Token>, Token> make_malformed ()
+ {
+ return tl::unexpected<Token> (Token (Kind::MALFORMED));
+ }
+
+ enum class Kind
+ {
+ MALFORMED,
+ } kind;
+
+private:
+ Token (Kind kind) : kind (kind) {}
+};
+
+struct TokenTree
+{
+ static tl::expected<std::unique_ptr<AST::TokenTree>, TokenTree>
+ make_malformed ()
+ {
+ return tl::unexpected<TokenTree> (TokenTree (Kind::MALFORMED));
+ }
+
+ static tl::expected<std::unique_ptr<AST::TokenTree>, TokenTree>
+ make_malformed_delimited_token_tree ()
+ {
+ return tl::unexpected<TokenTree> (
+ TokenTree (Kind::MALFORMED_DELIMITED_TOKEN_TREE));
+ }
+
+ enum class Kind
+ {
+ MALFORMED,
+ MALFORMED_DELIMITED_TOKEN_TREE,
+ } kind;
+
+private:
+ TokenTree (Kind kind) : kind (kind) {}
+};
+
+struct Item
+{
+ static tl::expected<std::unique_ptr<AST::Item>, Item> make_end_of_file ()
+ {
+ return tl::unexpected<Item> (Item (Kind::END_OF_FILE));
+ }
+
+ static tl::expected<std::unique_ptr<AST::Item>, Item> make_malformed ()
+ {
+ return tl::unexpected<Item> (Item (Kind::MALFORMED));
+ }
+
+ enum class Kind
+ {
+ END_OF_FILE,
+ MALFORMED,
+ } kind;
+
+private:
+ Item (Kind kind) : kind (kind) {}
+};
+
+struct Items
+{
+ static tl::expected<std::vector<std::unique_ptr<AST::Item>>, Items>
+ make_malformed (std::vector<std::unique_ptr<AST::Item>> items)
+ {
+ return tl::unexpected<Items> (Items (Kind::MALFORMED, std::move (items)));
+ }
+
+ enum class Kind
+ {
+ MALFORMED,
+ } kind;
+
+ Items (Items const &) = delete;
+ Items &operator= (Items const &) = delete;
+
+ Items (Items &&items) = default;
+ Items &operator= (Items &&) = default;
+
+ // Should we do anything with valid items ?
+ std::vector<std::unique_ptr<AST::Item>> items;
+
+private:
+ Items (Kind kind, std::vector<std::unique_ptr<AST::Item>> items)
+ : kind (kind), items (std::move (items))
+ {}
+};
+
+struct Visibility
+{
+ static tl::expected<AST::Visibility, Visibility> make_malformed ()
+ {
+ return tl::unexpected<Visibility> (Visibility (Kind::MALFORMED));
+ }
+
+ static tl::expected<AST::Visibility, Visibility> make_missing_path ()
+ {
+ return tl::unexpected<Visibility> (Visibility (Kind::MISSING_PATH));
+ }
+
+ enum class Kind
+ {
+ MISSING_PATH,
+ MALFORMED,
+ } kind;
+
+private:
+ Visibility (Kind kind) : kind (kind) {}
+};
+
+} // namespace Error
+} // namespace Parse
+} // namespace Rust
+
+#endif /* !RUST_PARSE_ERROR_H */
diff --git a/gcc/rust/parse/rust-parse-impl-proc-macro.cc
b/gcc/rust/parse/rust-parse-impl-proc-macro.cc
index edc484f75..965c9146d 100644
--- a/gcc/rust/parse/rust-parse-impl-proc-macro.cc
+++ b/gcc/rust/parse/rust-parse-impl-proc-macro.cc
@@ -21,7 +21,7 @@
namespace Rust {
-template std::unique_ptr<AST::Item>
+template tl::expected<std::unique_ptr<AST::Item>, Parse::Error::Item>
Parser<ProcMacroInvocLexer>::parse_item (bool);
template std::unique_ptr<AST::Stmt>
diff --git a/gcc/rust/parse/rust-parse-impl.h b/gcc/rust/parse/rust-parse-impl.h
index 6cb8f0e65..56717709d 100644
--- a/gcc/rust/parse/rust-parse-impl.h
+++ b/gcc/rust/parse/rust-parse-impl.h
@@ -37,6 +37,7 @@
#include "rust-attribute-values.h"
#include "rust-keyword-values.h"
#include "rust-edition.h"
+#include "rust-parse-error.h"
#include "optional.h"
@@ -420,7 +421,7 @@ Parser<ManagedTokenSource>::done_end_of_file ()
// Parses a sequence of items within a module or the implicit top-level module
// in a crate
template <typename ManagedTokenSource>
-std::vector<std::unique_ptr<AST::Item>>
+tl::expected<std::vector<std::unique_ptr<AST::Item>>, Parse::Error::Items>
Parser<ManagedTokenSource>::parse_items ()
{
std::vector<std::unique_ptr<AST::Item>> items;
@@ -428,20 +429,21 @@ Parser<ManagedTokenSource>::parse_items ()
const_TokenPtr t = lexer.peek_token ();
while (t->get_id () != END_OF_FILE)
{
- std::unique_ptr<AST::Item> item = parse_item (false);
- if (item == nullptr)
- {
- // TODO: should all items be cleared?
- items = std::vector<std::unique_ptr<AST::Item>> ();
- break;
- }
+ auto item = parse_item (false);
+ if (!item)
+ return Parse::Error::Items::make_malformed (std::move (items));
- items.push_back (std::move (item));
+ items.push_back (std::move (item.value ()));
t = lexer.peek_token ();
}
+ // GCC 5->7 bug doesn't threat lvalue as an rvalue for the overload
+#if __GNUC__ <= 7
+ return std::move (items);
+#else
return items;
+#endif
}
// Parses a crate (compilation unit) - entry point
@@ -453,7 +455,8 @@ Parser<ManagedTokenSource>::parse_crate ()
AST::AttrVec inner_attrs = parse_inner_attributes ();
// parse items
- std::vector<std::unique_ptr<AST::Item>> items = parse_items ();
+ auto items
+ = parse_items ().value_or (std::vector<std::unique_ptr<AST::Item>>{});
// emit all errors
for (const auto &error : error_table)
@@ -470,18 +473,22 @@ Parser<ManagedTokenSource>::parse_inner_attributes ()
{
AST::AttrVec inner_attributes;
- // only try to parse it if it starts with "#!" not only "#"
- while ((lexer.peek_token ()->get_id () == HASH
- && lexer.peek_token (1)->get_id () == EXCLAM)
- || lexer.peek_token ()->get_id () == INNER_DOC_COMMENT)
+ auto has_valid_inner_attribute_prefix = [&] () {
+ auto id = lexer.peek_token ()->get_id ();
+ /* Outer attribute `#[` is not allowed, only accepts `#!` */
+ return (id == HASH && lexer.peek_token (1)->get_id () == EXCLAM)
+ || id == INNER_DOC_COMMENT;
+ };
+
+ while (has_valid_inner_attribute_prefix ())
{
- AST::Attribute inner_attr = parse_inner_attribute ();
+ auto inner_attr = parse_inner_attribute ();
/* Ensure only valid inner attributes are added to the inner_attributes
* list */
- if (!inner_attr.is_empty ())
+ if (inner_attr)
{
- inner_attributes.push_back (std::move (inner_attr));
+ inner_attributes.push_back (std::move (inner_attr.value ()));
}
else
{
@@ -516,7 +523,7 @@ Parser<ManagedTokenSource>::parse_doc_comment ()
// Parse a single inner attribute.
template <typename ManagedTokenSource>
-AST::Attribute
+tl::expected<AST::Attribute, Parse::Error::Attribute>
Parser<ManagedTokenSource>::parse_inner_attribute ()
{
if (lexer.peek_token ()->get_id () == INNER_DOC_COMMENT)
@@ -528,15 +535,8 @@ Parser<ManagedTokenSource>::parse_inner_attribute ()
return AST::Attribute (std::move (path), std::move (input), loc, true);
}
- if (lexer.peek_token ()->get_id () != HASH)
- {
- Error error (lexer.peek_token ()->get_locus (),
- "BUG: token %<#%> is missing, but %<parse_inner_attribute%> "
- "was invoked");
- add_error (std::move (error));
+ rust_assert (lexer.peek_token ()->get_id () == HASH);
- return AST::Attribute::create_empty ();
- }
lexer.skip_token ();
if (lexer.peek_token ()->get_id () != EXCLAM)
@@ -545,37 +545,38 @@ Parser<ManagedTokenSource>::parse_inner_attribute ()
"expected %<!%> or %<[%> for inner attribute");
add_error (std::move (error));
- return AST::Attribute::create_empty ();
+ return Parse::Error::Attribute::make_malformed ();
}
lexer.skip_token ();
if (!skip_token (LEFT_SQUARE))
- return AST::Attribute::create_empty ();
+ return Parse::Error::Attribute::make_malformed ();
- auto values = parse_attribute_body ();
+ auto body_res = parse_attribute_body ();
+ if (!body_res)
+ return Parse::Error::Attribute::make_malformed ();
+ auto body = std::move (body_res.value ());
- auto path = std::move (std::get<0> (values));
- auto input = std::move (std::get<1> (values));
- auto loc = std::get<2> (values);
auto actual_attribute
- = AST::Attribute (std::move (path), std::move (input), loc, true);
+ = AST::Attribute (std::move (body.path), std::move (body.input),
body.locus,
+ true);
if (!skip_token (RIGHT_SQUARE))
- return AST::Attribute::create_empty ();
+ return Parse::Error::Attribute::make_malformed ();
return actual_attribute;
}
// Parses the body of an attribute (inner or outer).
template <typename ManagedTokenSource>
-std::tuple<AST::SimplePath, std::unique_ptr<AST::AttrInput>, location_t>
+tl::expected<Parse::AttributeBody, Parse::Error::AttributeBody>
Parser<ManagedTokenSource>::parse_attribute_body ()
{
location_t locus = lexer.peek_token ()->get_locus ();
- AST::SimplePath attr_path = parse_simple_path ();
+ auto attr_path = parse_simple_path ();
// ensure path is valid to parse attribute input
- if (attr_path.is_empty ())
+ if (!attr_path)
{
Error error (lexer.peek_token ()->get_locus (),
"empty simple path in attribute");
@@ -583,47 +584,34 @@ Parser<ManagedTokenSource>::parse_attribute_body ()
// Skip past potential further info in attribute (i.e. attr_input)
skip_after_end_attribute ();
- return std::make_tuple (std::move (attr_path), nullptr, UNDEF_LOCATION);
+ return Parse::Error::AttributeBody::make_invalid_path ();
}
- std::unique_ptr<AST::AttrInput> attr_input = parse_attr_input ();
+ auto attr_input = parse_attr_input ();
// AttrInput is allowed to be null, so no checks here
-
- return std::make_tuple (std::move (attr_path), std::move (attr_input),
locus);
-}
-
-/* Determines whether token is a valid simple path segment. This does not
- * include scope resolution operators. */
-inline bool
-is_simple_path_segment (TokenId id)
-{
- switch (id)
- {
- case IDENTIFIER:
- case SUPER:
- case SELF:
- case CRATE:
- return true;
- case DOLLAR_SIGN:
- // assume that dollar sign leads to $crate
- return true;
- default:
- return false;
- }
+ if (attr_input)
+ return Parse::AttributeBody{std::move (attr_path.value ()),
+ std::move (attr_input.value ()), locus};
+ else if (attr_input.error ().kind == Parse::Error::AttrInput::Kind::MISSING)
+ return Parse::AttributeBody{std::move (attr_path.value ()), nullptr,
locus};
+ else
+ return Parse::Error::AttributeBody::make_invalid_attrinput ();
}
// Parses a SimplePath AST node, if it exists. Does nothing otherwise.
template <typename ManagedTokenSource>
-AST::SimplePath
+tl::expected<AST::SimplePath, Parse::Error::SimplePath>
Parser<ManagedTokenSource>::parse_simple_path ()
{
bool has_opening_scope_resolution = false;
location_t locus = UNKNOWN_LOCATION;
+ using Parse::Utils::is_simple_path_segment;
+
// don't parse anything if not a path upfront
if (!is_simple_path_segment (lexer.peek_token ()->get_id ())
&& !is_simple_path_segment (lexer.peek_token (1)->get_id ()))
- return AST::SimplePath::create_empty ();
+ return Parse::Error::SimplePath::make_malformed ();
/* Checks for opening scope resolution (i.e. global scope fully-qualified
* path) */
@@ -637,42 +625,34 @@ Parser<ManagedTokenSource>::parse_simple_path ()
}
// Parse single required simple path segment
- AST::SimplePathSegment segment = parse_simple_path_segment ();
+ auto segment = parse_simple_path_segment ();
+
+ if (!segment)
+ return Parse::Error::SimplePath::make_malformed ();
// get location if not gotten already
if (locus == UNKNOWN_LOCATION)
- locus = segment.get_locus ();
+ locus = segment->get_locus ();
std::vector<AST::SimplePathSegment> segments;
-
- // Return empty vector if first, actually required segment is an error
- if (segment.is_error ())
- return AST::SimplePath::create_empty ();
-
- segments.push_back (std::move (segment));
+ segments.push_back (std::move (segment.value ()));
// Parse all other simple path segments
while (lexer.peek_token ()->get_id () == SCOPE_RESOLUTION)
{
- AST::SimplePathSegment new_segment = parse_simple_path_segment (1);
+ auto new_segment = parse_simple_path_segment (1);
+ using Error = Parse::Error::SimplePathSegment::Kind;
// Return path as currently constructed if segment in error state.
- if (new_segment.is_error ())
- break;
-
- segments.push_back (std::move (new_segment));
- }
-
- // DEBUG: check for any empty segments
- for (const auto &seg : segments)
- {
- if (seg.is_error ())
+ if (!new_segment)
{
- rust_debug (
- "when parsing simple path, somehow empty path segment was "
- "not filtered out. Path begins with '%s'",
- segments.at (0).as_string ().c_str ());
+ if (new_segment.error ().kind == Error::INVALID_SIMPLE_PATH_TOKEN)
+ break; /* Could be end of path */
+ else /* Any other error is an hard error */
+ return Parse::Error::SimplePath::make_malformed ();
}
+
+ segments.push_back (std::move (new_segment.value ()));
}
return AST::SimplePath (std::move (segments), has_opening_scope_resolution,
@@ -685,7 +665,7 @@ Parser<ManagedTokenSource>::parse_simple_path ()
* operators)
* Starts parsing at an offset of base_peek */
template <typename ManagedTokenSource>
-AST::SimplePathSegment
+tl::expected<AST::SimplePathSegment, Parse::Error::SimplePathSegment>
Parser<ManagedTokenSource>::parse_simple_path_segment (int base_peek)
{
using namespace Values;
@@ -721,20 +701,14 @@ Parser<ManagedTokenSource>::parse_simple_path_segment
(int base_peek)
/* could put the rust_error_at thing here but fallthrough (from failing
* $crate condition) isn't completely obvious if it is. */
- // test prevent error
- return AST::SimplePathSegment::create_error ();
+ return Parse::Error::SimplePathSegment::make_invalid_token_or_path_end
();
}
rust_unreachable ();
- /*rust_error_at(
- t->get_locus(), "invalid token '%s' in simple path segment",
- t->get_token_description());*/
- // this is not necessarily an error, e.g. end of path
- // return AST::SimplePathSegment::create_error();
}
// Parses a PathIdentSegment - an identifier segment of a non-SimplePath path.
template <typename ManagedTokenSource>
-AST::PathIdentSegment
+tl::expected<AST::PathIdentSegment, Parse::Error::PathIdentSegment>
Parser<ManagedTokenSource>::parse_path_ident_segment ()
{
const_TokenPtr t = lexer.peek_token ();
@@ -775,15 +749,14 @@ Parser<ManagedTokenSource>::parse_path_ident_segment ()
* condition) isn't completely obvious if it is. */
// test prevent error
- return AST::PathIdentSegment::create_error ();
+ return Parse::Error::PathIdentSegment::make_invalid_token ();
}
rust_unreachable ();
- // not necessarily an error
}
// Parses an AttrInput AST node (polymorphic, as AttrInput is abstract)
template <typename ManagedTokenSource>
-std::unique_ptr<AST::AttrInput>
+tl::expected<std::unique_ptr<AST::AttrInput>, Parse::Error::AttrInput>
Parser<ManagedTokenSource>::parse_attr_input ()
{
const_TokenPtr t = lexer.peek_token ();
@@ -793,13 +766,16 @@ Parser<ManagedTokenSource>::parse_attr_input ()
case LEFT_SQUARE:
case LEFT_CURLY:
{
+ auto dtoken_tree = parse_delim_token_tree ();
+ if (!dtoken_tree)
+ return Parse::Error::AttrInput::make_bad_token_tree ();
+
// must be a delimited token tree, so parse that
std::unique_ptr<AST::AttrInput> input_tree (
- new AST::DelimTokenTree (parse_delim_token_tree ()));
-
- // TODO: potential checks on DelimTokenTree before returning
+ new AST::DelimTokenTree (dtoken_tree.value ()));
- return input_tree;
+ return tl::expected<std::unique_ptr<AST::AttrInput>,
+ Parse::Error::AttrInput>{std::move (input_tree)};
}
case EQUAL:
{
@@ -811,13 +787,13 @@ Parser<ManagedTokenSource>::parse_attr_input ()
// attempt to parse macro
// TODO: macros may/may not be allowed in attributes
// this is needed for "#[doc = include_str!(...)]"
- if (is_simple_path_segment (t->get_id ()))
+ if (Parse::Utils::is_simple_path_segment (t->get_id ()))
{
std::unique_ptr<AST::MacroInvocation> invoke
= parse_macro_invocation ({});
if (!invoke)
- return nullptr;
+ return Parse::Error::AttrInput::make_bad_macro_invocation ();
return std::unique_ptr<AST::AttrInput> (
new AST::AttrInputMacro (std::move (invoke)));
@@ -834,7 +810,7 @@ Parser<ManagedTokenSource>::parse_attr_input ()
add_error (std::move (error));
skip_after_end_attribute ();
- return nullptr;
+ return Parse::Error::AttrInput::make_malformed ();
}
AST::Literal::LitType lit_type = AST::Literal::STRING;
@@ -877,7 +853,9 @@ Parser<ManagedTokenSource>::parse_attr_input ()
// FIXME: shouldn't a skip token be required here?
- return attr_input_lit;
+ return tl::expected<std::unique_ptr<AST::AttrInput>,
+ Parse::Error::AttrInput>{
+ std::move (attr_input_lit)};
}
break;
case RIGHT_PAREN:
@@ -885,7 +863,7 @@ Parser<ManagedTokenSource>::parse_attr_input ()
case RIGHT_CURLY:
case END_OF_FILE:
// means AttrInput is missing, which is allowed
- return nullptr;
+ return Parse::Error::AttrInput::make_missing_attrinput ();
default:
add_error (
Error (t->get_locus (),
@@ -894,46 +872,15 @@ Parser<ManagedTokenSource>::parse_attr_input ()
t->get_token_description ()));
skip_after_end_attribute ();
- return nullptr;
+ return Parse::Error::AttrInput::make_malformed ();
}
rust_unreachable ();
// TODO: find out how to stop gcc error on "no return value"
}
-/* Returns true if the token id matches the delimiter type. Note that this only
- * operates for END delimiter tokens. */
-inline bool
-token_id_matches_delims (TokenId token_id, AST::DelimType delim_type)
-{
- return ((token_id == RIGHT_PAREN && delim_type == AST::PARENS)
- || (token_id == RIGHT_SQUARE && delim_type == AST::SQUARE)
- || (token_id == RIGHT_CURLY && delim_type == AST::CURLY));
-}
-
-/* Returns true if the likely result of parsing the next few tokens is a path.
- * Not guaranteed, though, especially in the case of syntax errors. */
-inline bool
-is_likely_path_next (TokenId next_token_id)
-{
- switch (next_token_id)
- {
- case IDENTIFIER:
- case SUPER:
- case SELF:
- case SELF_ALIAS:
- case CRATE:
- // maybe - maybe do extra check. But then requires another TokenId.
- case DOLLAR_SIGN:
- case SCOPE_RESOLUTION:
- return true;
- default:
- return false;
- }
-}
-
// Parses a delimited token tree
template <typename ManagedTokenSource>
-AST::DelimTokenTree
+tl::expected<AST::DelimTokenTree, Parse::Error::DelimTokenTree>
Parser<ManagedTokenSource>::parse_delim_token_tree ()
{
const_TokenPtr t = lexer.peek_token ();
@@ -961,7 +908,7 @@ Parser<ManagedTokenSource>::parse_delim_token_tree ()
"delimited token tree)",
t->get_token_description ()));
- return AST::DelimTokenTree::create_empty ();
+ return Parse::Error::DelimTokenTree::make_expected_delimiter ();
}
// parse actual token tree vector - 0 or more
@@ -972,15 +919,14 @@ Parser<ManagedTokenSource>::parse_delim_token_tree ()
// repeat loop until finding the matching delimiter
t = lexer.peek_token ();
- while (!token_id_matches_delims (t->get_id (), delim_type)
+ while (!Parse::Utils::token_id_matches_delims (t->get_id (), delim_type)
&& t->get_id () != END_OF_FILE)
{
- std::unique_ptr<AST::TokenTree> tok_tree = parse_token_tree ();
-
- if (tok_tree == nullptr)
- return AST::DelimTokenTree::create_empty ();
+ auto tok_tree = parse_token_tree ();
+ if (!tok_tree)
+ return Parse::Error::DelimTokenTree::make_invalid_token_tree ();
- token_trees_in_tree.push_back (std::move (tok_tree));
+ token_trees_in_tree.push_back (std::move (tok_tree.value ()));
// lexer.skip_token();
t = lexer.peek_token ();
@@ -995,17 +941,10 @@ Parser<ManagedTokenSource>::parse_delim_token_tree ()
// parse end delimiters
t = lexer.peek_token ();
- if (token_id_matches_delims (t->get_id (), delim_type))
+ if (Parse::Utils::token_id_matches_delims (t->get_id (), delim_type))
{
// tokens match opening delimiter, so skip.
lexer.skip_token ();
-
- // DEBUG
- rust_debug ("finished parsing new delim token tree - peeked token is now
"
- "'%s' while t is '%s'",
- lexer.peek_token ()->get_token_description (),
- t->get_token_description ());
-
return token_tree;
}
else
@@ -1020,15 +959,13 @@ Parser<ManagedTokenSource>::parse_delim_token_tree ()
: (delim_type == AST::SQUARE ? "]" : "}")));
add_error (std::move (error));
- /* return empty token tree despite possibly parsing valid token tree -
- * TODO is this a good idea? */
- return AST::DelimTokenTree::create_empty ();
+ return Parse::Error::DelimTokenTree::make_mismatched_delimiters ();
}
}
// Parses an identifier/keyword as a Token
template <typename ManagedTokenSource>
-std::unique_ptr<AST::Token>
+tl::expected<std::unique_ptr<AST::Token>, Parse::Error::Token>
Parser<ManagedTokenSource>::parse_identifier_or_keyword_token ()
{
const_TokenPtr t = lexer.peek_token ();
@@ -1041,14 +978,14 @@
Parser<ManagedTokenSource>::parse_identifier_or_keyword_token ()
else
{
add_error (Error (t->get_locus (), "expected keyword or identifier"));
- return nullptr;
+ return Parse::Error::Token::make_malformed ();
}
}
/* Parses a TokenTree syntactical production. This is either a delimited token
* tree or a non-delimiter token. */
template <typename ManagedTokenSource>
-std::unique_ptr<AST::TokenTree>
+tl::expected<std::unique_ptr<AST::TokenTree>, Parse::Error::TokenTree>
Parser<ManagedTokenSource>::parse_token_tree ()
{
const_TokenPtr t = lexer.peek_token ();
@@ -1058,10 +995,17 @@ Parser<ManagedTokenSource>::parse_token_tree ()
case LEFT_PAREN:
case LEFT_SQUARE:
case LEFT_CURLY:
- // Parse delimited token tree
- // TODO: use move rather than copy constructor
- return std::unique_ptr<AST::DelimTokenTree> (
- new AST::DelimTokenTree (parse_delim_token_tree ()));
+ {
+ // Parse delimited token tree
+ auto delim_token_tree = parse_delim_token_tree ();
+ if (!delim_token_tree)
+ return Parse::Error::TokenTree::
+ make_malformed_delimited_token_tree ();
+
+ // TODO: use move rather than copy constructor
+ return std::unique_ptr<AST::DelimTokenTree> (
+ new AST::DelimTokenTree (delim_token_tree.value ()));
+ }
case RIGHT_PAREN:
case RIGHT_SQUARE:
case RIGHT_CURLY:
@@ -1074,7 +1018,7 @@ Parser<ManagedTokenSource>::parse_token_tree ()
"non-delimiter tokens"));
lexer.skip_token ();
- return nullptr;
+ return Parse::Error::TokenTree::make_malformed ();
default:
// parse token itself as TokenTree
lexer.skip_token ();
@@ -1096,11 +1040,19 @@ Parser<ManagedTokenSource>::is_macro_rules_def
(const_TokenPtr t)
// Parses a single item
template <typename ManagedTokenSource>
-std::unique_ptr<AST::Item>
+tl::expected<std::unique_ptr<AST::Item>, Parse::Error::Item>
Parser<ManagedTokenSource>::parse_item (bool called_from_statement)
{
// has a "called_from_statement" parameter for better error message handling
+ // TODO: GCC 5 does not handle implicit return type correctly so we're forced
+ // to specify it almost every time until the baseline GCC gets bumped.
+ // Since this type is quite long and the code is dense we use an alias.
+ //
+ // When support for GCC 5 stops: remove this alias as well as the explicit
+ // ctor calls.
+ using RType = tl::expected<std::unique_ptr<AST::Item>, Parse::Error::Item>;
+
// parse outer attributes for item
AST::AttrVec outer_attrs = parse_outer_attributes ();
const_TokenPtr t = lexer.peek_token ();
@@ -1117,7 +1069,7 @@ Parser<ManagedTokenSource>::parse_item (bool
called_from_statement)
"expected item after outer attribute or doc comment");
add_error (std::move (error));
}
- return nullptr;
+ return Parse::Error::Item::make_end_of_file ();
case ASYNC:
case PUB:
@@ -1141,22 +1093,34 @@ Parser<ManagedTokenSource>::parse_item (bool
called_from_statement)
case UNSAFE: // maybe - unsafe traits are a thing
// if any of these (should be all possible VisItem prefixes), parse a
// VisItem
- return parse_vis_item (std::move (outer_attrs));
- break;
+ {
+ auto vis_item = parse_vis_item (std::move (outer_attrs));
+ if (!vis_item)
+ return Parse::Error::Item::make_malformed ();
+ return RType{std::move (vis_item)};
+ }
case SUPER:
case SELF:
case CRATE:
case DOLLAR_SIGN:
// almost certainly macro invocation semi
- return parse_macro_invocation_semi (std::move (outer_attrs));
- break;
+ {
+ auto macro_invoc_semi
+ = parse_macro_invocation_semi (std::move (outer_attrs));
+ if (!macro_invoc_semi)
+ return Parse::Error::Item::make_malformed ();
+ return RType{std::move (macro_invoc_semi)};
+ }
// crappy hack to do union "keyword"
case IDENTIFIER:
// TODO: ensure std::string and literal comparison works
if (t->get_str () == Values::WeakKeywords::UNION
&& lexer.peek_token (1)->get_id () == IDENTIFIER)
{
- return parse_vis_item (std::move (outer_attrs));
+ auto vis_item = parse_vis_item (std::move (outer_attrs));
+ if (!vis_item)
+ return Parse::Error::Item::make_malformed ();
+ return RType{std::move (vis_item)};
// or should this go straight to parsing union?
}
else if (t->get_str () == Values::WeakKeywords::DEFAULT
@@ -1165,19 +1129,26 @@ Parser<ManagedTokenSource>::parse_item (bool
called_from_statement)
add_error (Error (t->get_locus (),
"%qs is only allowed on items within %qs blocks",
"default", "impl"));
- return nullptr;
+ return Parse::Error::Item::make_malformed ();
}
else if (is_macro_rules_def (t))
{
// macro_rules! macro item
- return parse_macro_rules_def (std::move (outer_attrs));
+ auto macro_rule_def = parse_macro_rules_def (std::move (outer_attrs));
+ if (!macro_rule_def)
+ return Parse::Error::Item::make_malformed ();
+ return RType{std::move (macro_rule_def)};
}
else if (lexer.peek_token (1)->get_id () == SCOPE_RESOLUTION
|| lexer.peek_token (1)->get_id () == EXCLAM)
{
/* path (probably) or macro invocation, so probably a macro invocation
* semi */
- return parse_macro_invocation_semi (std::move (outer_attrs));
+ auto macro_invocation_semi
+ = parse_macro_invocation_semi (std::move (outer_attrs));
+ if (!macro_invocation_semi)
+ return Parse::Error::Item::make_malformed ();
+ return RType{std::move (macro_invocation_semi)};
}
gcc_fallthrough ();
default:
@@ -1188,7 +1159,7 @@ Parser<ManagedTokenSource>::parse_item (bool
called_from_statement)
called_from_statement ? "statement" : "item"));
// skip somewhere?
- return nullptr;
+ return Parse::Error::Item::make_malformed ();
break;
}
}
@@ -1200,19 +1171,21 @@ Parser<ManagedTokenSource>::parse_outer_attributes ()
{
AST::AttrVec outer_attributes;
- while (lexer.peek_token ()->get_id ()
- == HASH /* Can also be #!, which catches errors. */
- || lexer.peek_token ()->get_id () == OUTER_DOC_COMMENT
- || lexer.peek_token ()->get_id ()
- == INNER_DOC_COMMENT) /* For error handling. */
+ auto has_valid_attribute_prefix = [&] () {
+ auto id = lexer.peek_token ()->get_id ();
+ /* We allow inner attributes `#!` and catch the error later */
+ return id == HASH || id == OUTER_DOC_COMMENT || id == INNER_DOC_COMMENT;
+ };
+
+ while (has_valid_attribute_prefix ()) /* For error handling. */
{
- AST::Attribute outer_attr = parse_outer_attribute ();
+ auto outer_attr = parse_outer_attribute ();
/* Ensure only valid outer attributes are added to the outer_attributes
* list */
- if (!outer_attr.is_empty ())
+ if (outer_attr)
{
- outer_attributes.push_back (std::move (outer_attr));
+ outer_attributes.push_back (std::move (outer_attr.value ()));
}
else
{
@@ -1231,7 +1204,7 @@ Parser<ManagedTokenSource>::parse_outer_attributes ()
// Parse a single outer attribute.
template <typename ManagedTokenSource>
-AST::Attribute
+tl::expected<AST::Attribute, Parse::Error::Attribute>
Parser<ManagedTokenSource>::parse_outer_attribute ()
{
if (lexer.peek_token ()->get_id () == OUTER_DOC_COMMENT)
@@ -1252,13 +1225,13 @@ Parser<ManagedTokenSource>::parse_outer_attribute ()
"and before any outer attribute or doc (%<#[%>, %<///%> or %</**%>)");
add_error (std::move (error));
lexer.skip_token ();
- return AST::Attribute::create_empty ();
+ return Parse::Error::Attribute::make_unexpected_inner ();
}
/* OuterAttribute -> '#' '[' Attr ']' */
if (lexer.peek_token ()->get_id () != HASH)
- return AST::Attribute::create_empty ();
+ return Parse::Error::Attribute::make_malformed ();
lexer.skip_token ();
@@ -1275,20 +1248,22 @@ Parser<ManagedTokenSource>::parse_outer_attribute ()
"attributes are not possible at this location");
add_error (std::move (error));
}
- return AST::Attribute::create_empty ();
+ return Parse::Error::Attribute::make_unexpected_inner ();
}
lexer.skip_token ();
- auto values = parse_attribute_body ();
- auto path = std::move (std::get<0> (values));
- auto input = std::move (std::get<1> (values));
- auto loc = std::get<2> (values);
+ auto body_res = parse_attribute_body ();
+ if (!body_res)
+ return Parse::Error::Attribute::make_malformed_body ();
+ auto body = std::move (body_res.value ());
+
auto actual_attribute
- = AST::Attribute (std::move (path), std::move (input), loc, false);
+ = AST::Attribute (std::move (body.path), std::move (body.input),
body.locus,
+ false);
if (lexer.peek_token ()->get_id () != RIGHT_SQUARE)
- return AST::Attribute::create_empty ();
+ return Parse::Error::Attribute::make_malformed ();
lexer.skip_token ();
@@ -1301,7 +1276,10 @@ std::unique_ptr<AST::VisItem>
Parser<ManagedTokenSource>::parse_vis_item (AST::AttrVec outer_attrs)
{
// parse visibility, which may or may not exist
- AST::Visibility vis = parse_visibility ();
+ auto vis_res = parse_visibility ();
+ if (!vis_res)
+ return nullptr;
+ auto vis = vis_res.value ();
// select VisItem to create depending on keyword
const_TokenPtr t = lexer.peek_token ();
@@ -1570,7 +1548,8 @@ Parser<ManagedTokenSource>::parse_macro_rules_def
(AST::AttrVec outer_attrs)
lexer.skip_token ();
// don't parse if end of macro rules
- if (token_id_matches_delims (lexer.peek_token ()->get_id (), delim_type))
+ if (Parse::Utils::token_id_matches_delims (lexer.peek_token ()->get_id
(),
+ delim_type))
{
// DEBUG
rust_debug (
@@ -1600,7 +1579,7 @@ Parser<ManagedTokenSource>::parse_macro_rules_def
(AST::AttrVec outer_attrs)
// parse end delimiters
t = lexer.peek_token ();
- if (token_id_matches_delims (t->get_id (), delim_type))
+ if (Parse::Utils::token_id_matches_delims (t->get_id (), delim_type))
{
// tokens match opening delimiter, so skip.
lexer.skip_token ();
@@ -1692,8 +1671,12 @@ Parser<ManagedTokenSource>::parse_decl_macro_def
(AST::Visibility vis,
}
location_t transcriber_loc = lexer.peek_token ()->get_locus ();
- AST::DelimTokenTree delim_tok_tree = parse_delim_token_tree ();
- AST::MacroTranscriber transcriber (delim_tok_tree, transcriber_loc);
+ auto delim_tok_tree = parse_delim_token_tree ();
+ if (!delim_tok_tree)
+ return nullptr;
+
+ AST::MacroTranscriber transcriber (delim_tok_tree.value (),
+ transcriber_loc);
if (transcriber.get_token_tree ().get_delim_type ()
!= AST::DelimType::CURLY)
@@ -1753,8 +1736,8 @@ Parser<ManagedTokenSource>::parse_decl_macro_def
(AST::Visibility vis,
lexer.skip_token ();
// don't parse if end of macro rules
- if (token_id_matches_delims (lexer.peek_token ()->get_id (),
- AST::CURLY))
+ if (Parse::Utils::token_id_matches_delims (
+ lexer.peek_token ()->get_id (), AST::CURLY))
{
break;
}
@@ -1806,7 +1789,9 @@ Parser<ManagedTokenSource>::parse_macro_invocation_semi (
AST::AttrVec outer_attrs)
{
location_t macro_locus = lexer.peek_token ()->get_locus ();
- AST::SimplePath path = parse_simple_path ();
+ auto path = parse_simple_path ();
+ if (!path)
+ return nullptr;
if (!skip_token (EXCLAM))
{
@@ -1849,15 +1834,14 @@ Parser<ManagedTokenSource>::parse_macro_invocation_semi
(
t = lexer.peek_token ();
// parse token trees until the initial delimiter token is found again
- while (!token_id_matches_delims (t->get_id (), delim_type)
+ while (!Parse::Utils::token_id_matches_delims (t->get_id (), delim_type)
&& t->get_id () != END_OF_FILE)
{
- std::unique_ptr<AST::TokenTree> tree = parse_token_tree ();
-
- if (tree == nullptr)
+ auto tree = parse_token_tree ();
+ if (!tree)
return nullptr;
- token_trees.push_back (std::move (tree));
+ token_trees.push_back (std::move (tree.value ()));
t = lexer.peek_token ();
}
@@ -1867,11 +1851,12 @@ Parser<ManagedTokenSource>::parse_macro_invocation_semi
(
AST::DelimTokenTree delim_tok_tree (delim_type, std::move (token_trees),
tok_tree_locus);
- AST::MacroInvocData invoc_data (std::move (path), std::move
(delim_tok_tree));
+ AST::MacroInvocData invoc_data (std::move (path.value ()),
+ std::move (delim_tok_tree));
// parse end delimiters
t = lexer.peek_token ();
- if (token_id_matches_delims (t->get_id (), delim_type))
+ if (Parse::Utils::token_id_matches_delims (t->get_id (), delim_type))
{
// tokens match opening delimiter, so skip.
lexer.skip_token ();
@@ -1922,8 +1907,8 @@ std::unique_ptr<AST::MacroInvocation>
Parser<ManagedTokenSource>::parse_macro_invocation (AST::AttrVec outer_attrs)
{
// parse macro path
- AST::SimplePath macro_path = parse_simple_path ();
- if (macro_path.is_empty ())
+ auto macro_path = parse_simple_path ();
+ if (!macro_path)
{
Error error (lexer.peek_token ()->get_locus (),
"failed to parse macro invocation path");
@@ -1940,12 +1925,15 @@ Parser<ManagedTokenSource>::parse_macro_invocation
(AST::AttrVec outer_attrs)
}
// parse internal delim token tree
- AST::DelimTokenTree delim_tok_tree = parse_delim_token_tree ();
+ auto delim_tok_tree = parse_delim_token_tree ();
+ if (!delim_tok_tree)
+ return nullptr;
- location_t macro_locus = macro_path.get_locus ();
+ location_t macro_locus = macro_path->get_locus ();
return AST::MacroInvocation::Regular (
- AST::MacroInvocData (std::move (macro_path), std::move (delim_tok_tree)),
+ AST::MacroInvocData (std::move (macro_path.value ()),
+ std::move (delim_tok_tree.value ())),
std::move (outer_attrs), macro_locus);
}
@@ -1970,7 +1958,11 @@ Parser<ManagedTokenSource>::parse_macro_rule ()
// parse transcriber (this is just a delim token tree)
location_t token_tree_loc = lexer.peek_token ()->get_locus ();
- AST::MacroTranscriber transcriber (parse_delim_token_tree (),
token_tree_loc);
+ auto delim_token_tree = parse_delim_token_tree ();
+ if (!delim_token_tree)
+ return AST::MacroRule::create_error (token_tree_loc);
+
+ AST::MacroTranscriber transcriber (delim_token_tree.value (),
token_tree_loc);
return AST::MacroRule (std::move (matcher), std::move (transcriber), locus);
}
@@ -2019,7 +2011,7 @@ Parser<ManagedTokenSource>::parse_macro_matcher ()
t = lexer.peek_token ();
// parse token trees until the initial delimiter token is found again
- while (!token_id_matches_delims (t->get_id (), delim_type))
+ while (!Parse::Utils::token_id_matches_delims (t->get_id (), delim_type))
{
std::unique_ptr<AST::MacroMatch> match = parse_macro_match ();
@@ -2072,7 +2064,7 @@ Parser<ManagedTokenSource>::parse_macro_matcher ()
// parse end delimiters
t = lexer.peek_token ();
- if (token_id_matches_delims (t->get_id (), delim_type))
+ if (Parse::Utils::token_id_matches_delims (t->get_id (), delim_type))
{
// tokens match opening delimiter, so skip.
lexer.skip_token ();
@@ -2348,7 +2340,7 @@ Parser<ManagedTokenSource>::parse_macro_match_repetition
()
/* Parses a visibility syntactical production (i.e. creating a non-default
* visibility) */
template <typename ManagedTokenSource>
-AST::Visibility
+tl::expected<AST::Visibility, Parse::Error::Visibility>
Parser<ManagedTokenSource>::parse_visibility ()
{
// check for no visibility
@@ -2400,27 +2392,28 @@ Parser<ManagedTokenSource>::parse_visibility ()
lexer.skip_token ();
// parse the "in" path as well
- AST::SimplePath path = parse_simple_path ();
- if (path.is_empty ())
+ auto path = parse_simple_path ();
+ if (!path)
{
Error error (lexer.peek_token ()->get_locus (),
"missing path in pub(in path) visibility");
add_error (std::move (error));
// skip after somewhere?
- return AST::Visibility::create_error ();
+ return Parse::Error::Visibility::make_missing_path ();
}
skip_token (RIGHT_PAREN);
- return AST::Visibility::create_in_path (std::move (path), vis_loc);
+ return AST::Visibility::create_in_path (std::move (path.value ()),
+ vis_loc);
}
default:
add_error (Error (t->get_locus (), "unexpected token %qs in visibility",
t->get_token_description ()));
lexer.skip_token ();
- return AST::Visibility::create_error ();
+ return Parse::Error::Visibility::make_malformed ();
}
}
@@ -2493,8 +2486,8 @@ Parser<ManagedTokenSource>::parse_module (AST::Visibility
vis,
const_TokenPtr tok = lexer.peek_token ();
while (tok->get_id () != RIGHT_CURLY)
{
- std::unique_ptr<AST::Item> item = parse_item (false);
- if (item == nullptr)
+ auto item = parse_item (false);
+ if (!item)
{
Error error (tok->get_locus (),
"failed to parse item in module");
@@ -2503,7 +2496,7 @@ Parser<ManagedTokenSource>::parse_module (AST::Visibility
vis,
return nullptr;
}
- items.push_back (std::move (item));
+ items.push_back (std::move (item.value ()));
tok = lexer.peek_token ();
}
@@ -2695,9 +2688,9 @@ Parser<ManagedTokenSource>::parse_use_tree ()
location_t locus = lexer.peek_token ()->get_locus ();
// bool has_path = false;
- AST::SimplePath path = parse_simple_path ();
+ auto path = parse_simple_path ();
- if (path.is_empty ())
+ if (!path)
{
// has no path, so must be glob or nested tree UseTree type
@@ -2808,14 +2801,14 @@ Parser<ManagedTokenSource>::parse_use_tree ()
return std::unique_ptr<AST::UseTreeRebind> (
new AST::UseTreeRebind (AST::UseTreeRebind::IDENTIFIER,
- std::move (path), locus, t));
+ std::move (path.value ()), locus, t));
case UNDERSCORE:
// skip lexer token
lexer.skip_token ();
return std::unique_ptr<AST::UseTreeRebind> (
new AST::UseTreeRebind (AST::UseTreeRebind::WILDCARD,
- std::move (path), locus,
+ std::move (path.value ()), locus,
{Values::Keywords::UNDERSCORE,
t->get_locus ()}));
default:
@@ -2838,8 +2831,8 @@ Parser<ManagedTokenSource>::parse_use_tree ()
case RIGHT_CURLY:
// this may occur in recursive calls - assume it is ok and ignore it
return std::unique_ptr<AST::UseTreeRebind> (
- new AST::UseTreeRebind (AST::UseTreeRebind::NONE, std::move (path),
- locus));
+ new AST::UseTreeRebind (AST::UseTreeRebind::NONE,
+ std::move (path.value ()), locus));
case SCOPE_RESOLUTION:
// keep going
break;
@@ -2861,7 +2854,7 @@ Parser<ManagedTokenSource>::parse_use_tree ()
return std::unique_ptr<AST::UseTreeGlob> (
new AST::UseTreeGlob (AST::UseTreeGlob::PATH_PREFIXED,
- std::move (path), locus));
+ std::move (path.value ()), locus));
case LEFT_CURLY:
{
// nested tree UseTree type
@@ -2897,8 +2890,8 @@ Parser<ManagedTokenSource>::parse_use_tree ()
return std::unique_ptr<AST::UseTreeList> (
new AST::UseTreeList (AST::UseTreeList::PATH_PREFIXED,
- std::move (path), std::move (use_trees),
- locus));
+ std::move (path.value ()),
+ std::move (use_trees), locus));
}
default:
add_error (Error (t->get_locus (),
@@ -4525,7 +4518,9 @@ Parser<ManagedTokenSource>::parse_struct_field ()
AST::AttrVec outer_attrs = parse_outer_attributes ();
// parse visibility, if it exists
- AST::Visibility vis = parse_visibility ();
+ auto vis = parse_visibility ();
+ if (!vis)
+ return AST::StructField::create_error ();
location_t locus = lexer.peek_token ()->get_locus ();
@@ -4559,7 +4554,8 @@ Parser<ManagedTokenSource>::parse_struct_field ()
}
return AST::StructField (std::move (field_name), std::move (field_type),
- std::move (vis), locus, std::move (outer_attrs));
+ std::move (vis.value ()), locus,
+ std::move (outer_attrs));
}
// Parses tuple fields in tuple/tuple struct declarations.
@@ -4628,7 +4624,9 @@ Parser<ManagedTokenSource>::parse_tuple_field ()
AST::AttrVec outer_attrs = parse_outer_attributes ();
// parse visibility if it exists
- AST::Visibility vis = parse_visibility ();
+ auto visibility = parse_visibility ();
+ if (!visibility)
+ return AST::TupleField::create_error ();
location_t locus = lexer.peek_token ()->get_locus ();
@@ -4645,7 +4643,8 @@ Parser<ManagedTokenSource>::parse_tuple_field ()
return AST::TupleField::create_error ();
}
- return AST::TupleField (std::move (field_type), std::move (vis), locus,
+ return AST::TupleField (std::move (field_type),
+ std::move (visibility.value ()), locus,
std::move (outer_attrs));
}
@@ -4783,7 +4782,10 @@ Parser<ManagedTokenSource>::parse_enum_item ()
AST::AttrVec outer_attrs = parse_outer_attributes ();
// parse visibility, which may or may not exist
- AST::Visibility vis = parse_visibility ();
+ auto vis_res = parse_visibility ();
+ if (!vis_res)
+ return nullptr;
+ auto vis = vis_res.value ();
// parse name for enum item, which is required
const_TokenPtr item_name_tok = lexer.peek_token ();
@@ -5144,7 +5146,11 @@ Parser<ManagedTokenSource>::parse_trait_item ()
// parse outer attributes (if they exist)
AST::AttrVec outer_attrs = parse_outer_attributes ();
- AST::Visibility vis = parse_visibility ();
+ auto vis_res = parse_visibility ();
+ if (!vis_res)
+ return nullptr;
+
+ auto vis = vis_res.value ();
// lookahead to determine what type of trait item to parse
const_TokenPtr tok = lexer.peek_token ();
@@ -5504,7 +5510,10 @@ Parser<ManagedTokenSource>::parse_inherent_impl_item ()
{
// visibility, so not a macro invocation semi - must be constant,
// function, or method
- AST::Visibility vis = parse_visibility ();
+ auto vis_res = parse_visibility ();
+ if (!vis_res)
+ return nullptr;
+ auto vis = vis_res.value ();
// TODO: is a recursive call to parse_inherent_impl_item better?
switch (lexer.peek_token ()->get_id ())
@@ -5708,9 +5717,10 @@ Parser<ManagedTokenSource>::parse_trait_impl_item ()
// parse outer attributes (if they exist)
AST::AttrVec outer_attrs = parse_outer_attributes ();
- auto visibility = AST::Visibility::create_private ();
- if (lexer.peek_token ()->get_id () == PUB)
- visibility = parse_visibility ();
+ auto vis_res = parse_visibility ();
+ if (!vis_res)
+ return nullptr;
+ auto visibility = vis_res.value ();
// branch on next token:
const_TokenPtr t = lexer.peek_token ();
@@ -6010,7 +6020,10 @@ Parser<ManagedTokenSource>::parse_external_item ()
location_t locus = lexer.peek_token ()->get_locus ();
// parse optional visibility
- AST::Visibility vis = parse_visibility ();
+ auto vis_res = parse_visibility ();
+ if (!vis_res)
+ return nullptr;
+ auto vis = vis_res.value ();
const_TokenPtr t = lexer.peek_token ();
switch (t->get_id ())
@@ -6539,12 +6552,13 @@ Parser<ManagedTokenSource>::parse_type_path_segment ()
{
location_t locus = lexer.peek_token ()->get_locus ();
// parse ident segment part
- AST::PathIdentSegment ident_segment = parse_path_ident_segment ();
- if (ident_segment.is_error ())
+ auto ident_segment_res = parse_path_ident_segment ();
+ if (!ident_segment_res)
{
// not necessarily an error
return nullptr;
}
+ auto ident_segment = ident_segment_res.value ();
/* lookahead to determine if variants exist - only consume scope resolution
* then */
@@ -6724,12 +6738,13 @@ Parser<ManagedTokenSource>::parse_path_expr_segment ()
{
location_t locus = lexer.peek_token ()->get_locus ();
// parse ident segment
- AST::PathIdentSegment ident = parse_path_ident_segment ();
- if (ident.is_error ())
+ auto ident_result = parse_path_ident_segment ();
+ if (!ident_result)
{
// not necessarily an error?
return AST::PathExprSegment::create_error ();
}
+ auto ident = ident_result.value ();
// parse generic args (and turbofish), if they exist
/* use lookahead to determine if they actually exist (don't want to
@@ -9148,11 +9163,13 @@ Parser<ManagedTokenSource>::parse_type (bool
save_errors)
lexer.skip_token ();
- AST::DelimTokenTree tok_tree = parse_delim_token_tree ();
+ auto tok_tree = parse_delim_token_tree ();
+ if (!tok_tree)
+ return nullptr;
return AST::MacroInvocation::Regular (
AST::MacroInvocData (std::move (macro_path),
- std::move (tok_tree)),
+ std::move (tok_tree.value ())),
{}, locus);
}
case PLUS:
@@ -10013,11 +10030,13 @@ Parser<ManagedTokenSource>::parse_type_no_bounds ()
lexer.skip_token ();
- AST::DelimTokenTree tok_tree = parse_delim_token_tree ();
+ auto tok_tree = parse_delim_token_tree ();
+ if (!tok_tree)
+ return nullptr;
return AST::MacroInvocation::Regular (
AST::MacroInvocData (std::move (macro_path),
- std::move (tok_tree)),
+ std::move (tok_tree.value ())),
{}, locus);
}
default:
@@ -14233,14 +14252,17 @@
Parser<ManagedTokenSource>::parse_macro_invocation_partial (
return nullptr;
}
- AST::DelimTokenTree tok_tree = parse_delim_token_tree ();
+ auto tok_tree = parse_delim_token_tree ();
+ if (!tok_tree)
+ return nullptr;
rust_debug ("successfully parsed macro invocation (via partial)");
location_t macro_locus = converted_path.get_locus ();
return AST::MacroInvocation::Regular (
- AST::MacroInvocData (std::move (converted_path), std::move (tok_tree)),
+ AST::MacroInvocData (std::move (converted_path),
+ std::move (tok_tree.value ())),
std::move (outer_attrs), macro_locus);
}
diff --git a/gcc/rust/parse/rust-parse-utils.h
b/gcc/rust/parse/rust-parse-utils.h
new file mode 100644
index 000000000..1791f6e83
--- /dev/null
+++ b/gcc/rust/parse/rust-parse-utils.h
@@ -0,0 +1,73 @@
+
+// Copyright (C) 2025 Free Software Foundation, Inc.
+
+// This file is part of GCC.
+
+// GCC is free software; you can redistribute it and/or modify it under
+// the terms of the GNU General Public License as published by the Free
+// Software Foundation; either version 3, or (at your option) any later
+// version.
+
+// GCC is distributed in the hope that it will be useful, but WITHOUT ANY
+// WARRANTY; without even the implied warranty of MERCHANTABILITY or
+// FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
+// for more details.
+
+// You should have received a copy of the GNU General Public License
+// along with GCC; see the file COPYING3. If not see
+// <http://www.gnu.org/licenses/>.
+
+#ifndef RUST_PARSE_UTILS_H
+#define RUST_PARSE_UTILS_H
+
+#include "rust-ast.h"
+
+namespace Rust {
+namespace Parse {
+/* Utility structure to return members of an attribute body, was initially a
+ * tuple but tuples are ugly*/
+struct AttributeBody
+{
+ AST::SimplePath path;
+ std::unique_ptr<AST::AttrInput> input;
+ location_t locus;
+};
+
+namespace Utils {
+
+/* Returns true if the token id matches the delimiter type. Note that this only
+ * operates for END delimiter tokens. */
+inline bool
+token_id_matches_delims (TokenId token_id, AST::DelimType delim_type)
+{
+ return ((token_id == RIGHT_PAREN && delim_type == AST::PARENS)
+ || (token_id == RIGHT_SQUARE && delim_type == AST::SQUARE)
+ || (token_id == RIGHT_CURLY && delim_type == AST::CURLY));
+}
+
+/* Determines whether token is a valid simple path segment. This does not
+ * include scope resolution operators. */
+inline bool
+is_simple_path_segment (TokenId id)
+{
+ switch (id)
+ {
+ case IDENTIFIER:
+ case SUPER:
+ case SELF:
+ case CRATE:
+ return true;
+ case DOLLAR_SIGN:
+ // assume that dollar sign leads to $crate
+ return true;
+ default:
+ return false;
+ }
+}
+
+} // namespace Utils
+
+} // namespace Parse
+} // namespace Rust
+
+#endif /* !RUST_PARSE_UTILS_H */
diff --git a/gcc/rust/parse/rust-parse.h b/gcc/rust/parse/rust-parse.h
index 7b4046365..19b280af9 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-lex.h"
#include "rust-ast-full.h"
#include "rust-diagnostics.h"
+#include "rust-parse-error.h"
+#include "rust-parse-utils.h"
#include "expected.h"
@@ -180,7 +182,8 @@ public:
location_t loc = UNKNOWN_LOCATION);
bool is_macro_rules_def (const_TokenPtr t);
- std::unique_ptr<AST::Item> parse_item (bool called_from_statement);
+ tl::expected<std::unique_ptr<AST::Item>, Parse::Error::Item>
+ parse_item (bool called_from_statement);
std::unique_ptr<AST::Pattern> parse_pattern ();
std::unique_ptr<AST::Pattern> parse_pattern_no_alt ();
@@ -202,11 +205,14 @@ public:
std::unique_ptr<AST::AssociatedItem> parse_trait_impl_item ();
AST::PathInExpression parse_path_in_expression ();
std::vector<std::unique_ptr<AST::LifetimeParam>> parse_lifetime_params ();
- AST::Visibility parse_visibility ();
+ tl::expected<AST::Visibility, Parse::Error::Visibility> parse_visibility ();
std::unique_ptr<AST::IdentifierPattern> parse_identifier_pattern ();
- std::unique_ptr<AST::Token> parse_identifier_or_keyword_token ();
- std::unique_ptr<AST::TokenTree> parse_token_tree ();
- std::tuple<AST::SimplePath, std::unique_ptr<AST::AttrInput>, location_t>
+ tl::expected<std::unique_ptr<AST::Token>, Parse::Error::Token>
+ parse_identifier_or_keyword_token ();
+ tl::expected<std::unique_ptr<AST::TokenTree>, Parse::Error::TokenTree>
+ parse_token_tree ();
+
+ tl::expected<Parse::AttributeBody, Parse::Error::AttributeBody>
parse_attribute_body ();
AST::AttrVec parse_inner_attributes ();
std::unique_ptr<AST::MacroInvocation>
@@ -232,18 +238,23 @@ private:
void parse_statement_seq (bool (Parser::*done) ());
// AST-related stuff - maybe move or something?
- AST::Attribute parse_inner_attribute ();
- AST::Attribute parse_outer_attribute ();
- std::unique_ptr<AST::AttrInput> parse_attr_input ();
+ tl::expected<AST::Attribute, Parse::Error::Attribute>
+ parse_inner_attribute ();
+ tl::expected<AST::Attribute, Parse::Error::Attribute>
+ parse_outer_attribute ();
+ tl::expected<std::unique_ptr<AST::AttrInput>, Parse::Error::AttrInput>
+ parse_attr_input ();
std::tuple<AST::SimplePath, std::unique_ptr<AST::AttrInput>, location_t>
parse_doc_comment ();
// Path-related
- AST::SimplePath parse_simple_path ();
- AST::SimplePathSegment parse_simple_path_segment (int base_peek = 0);
+ tl::expected<AST::SimplePath, Parse::Error::SimplePath> parse_simple_path ();
+ tl::expected<AST::SimplePathSegment, Parse::Error::SimplePathSegment>
+ parse_simple_path_segment (int base_peek = 0);
AST::TypePath parse_type_path ();
std::unique_ptr<AST::TypePathSegment> parse_type_path_segment ();
- AST::PathIdentSegment parse_path_ident_segment ();
+ tl::expected<AST::PathIdentSegment, Parse::Error::PathIdentSegment>
+ parse_path_ident_segment ();
tl::optional<AST::GenericArg> parse_generic_arg ();
AST::GenericArgs parse_path_generic_args ();
AST::GenericArgsBinding parse_generic_args_binding ();
@@ -260,7 +271,8 @@ private:
AST::QualifiedPathInType parse_qualified_path_in_type ();
// Token tree or macro related
- AST::DelimTokenTree parse_delim_token_tree ();
+ tl::expected<AST::DelimTokenTree, Parse::Error::DelimTokenTree>
+ parse_delim_token_tree ();
std::unique_ptr<AST::MacroRulesDefinition>
parse_macro_rules_def (AST::AttrVec outer_attrs);
std::unique_ptr<AST::MacroRulesDefinition>
@@ -742,7 +754,8 @@ public:
// Parse items without parsing an entire crate. This function is the main
// parsing loop of AST::Crate::parse_crate().
- std::vector<std::unique_ptr<AST::Item>> parse_items ();
+ tl::expected<std::vector<std::unique_ptr<AST::Item>>, Parse::Error::Items>
+ parse_items ();
// Main entry point for parser.
std::unique_ptr<AST::Crate> parse_crate ();
diff --git a/gcc/rust/rust-session-manager.cc b/gcc/rust/rust-session-manager.cc
index 641811846..0454c9861 100644
--- a/gcc/rust/rust-session-manager.cc
+++ b/gcc/rust/rust-session-manager.cc
@@ -873,7 +873,7 @@ Session::injection (AST::Crate &crate)
// create "extern crate" item with the name
std::unique_ptr<AST::ExternCrate> extern_crate (
- new AST::ExternCrate (*it, AST::Visibility::create_error (),
+ new AST::ExternCrate (*it, AST::Visibility::create_private (),
{std::move (attr)}, UNKNOWN_LOCATION));
// insert at beginning
diff --git a/gcc/testsuite/rust/compile/macros/mbe/macro-issue3608.rs
b/gcc/testsuite/rust/compile/macros/mbe/macro-issue3608.rs
index b081d456a..c5df85d35 100644
--- a/gcc/testsuite/rust/compile/macros/mbe/macro-issue3608.rs
+++ b/gcc/testsuite/rust/compile/macros/mbe/macro-issue3608.rs
@@ -6,5 +6,3 @@ impl Bar for
fn main() { )// { dg-error "unexpected closing delimiter .\\)." }
- // { dg-error "unexpected token .end of file. - expecting closing
delimiter .\}. .for a delimited token tree." "" { target *-*-* } .+2 }
- // { dg-error "unexpected token .end of file. - expecting closing
delimiter .\\). .for a macro invocation semi." "" { target *-*-* } .+1 }
base-commit: cdf4d7854b4a4f5bb562bda6ebb11b3e6f06e52c
--
2.52.0