From 1657ee53d578d68c7d807312b1063ffd804d7ef9 Mon Sep 17 00:00:00 2001 From: Ben Boeckel Date: Sun, 31 Oct 2021 19:59:37 -0400 Subject: rust: track inline module scopes for module file resolution The set of inline modules is required to find the expected location of a module file. Track this information with an RAII object (`InlineModuleStackScope`) and pass it down to any out-of-line modules so that, when requested, the set of inline modules can be added to the search path. Signed-off-by: Ben Boeckel --- gcc/rust/parse/rust-parse-impl.h | 8 +++-- gcc/rust/parse/rust-parse.cc | 73 ++++++++++++++++++++++++++++++++++++++++ gcc/rust/parse/rust-parse.h | 19 +++++++++++ 3 files changed, 98 insertions(+), 2 deletions(-) (limited to 'gcc/rust/parse') diff --git a/gcc/rust/parse/rust-parse-impl.h b/gcc/rust/parse/rust-parse-impl.h index 52aba4f..7f0db1b 100644 --- a/gcc/rust/parse/rust-parse-impl.h +++ b/gcc/rust/parse/rust-parse-impl.h @@ -2104,14 +2104,18 @@ Parser::parse_module (AST::Visibility vis, // Construct an external module return std::unique_ptr ( new AST::Module (std::move (name), std::move (vis), - std::move (outer_attrs), locus, - lexer.get_filename ())); + std::move (outer_attrs), locus, lexer.get_filename (), + inline_module_stack)); case LEFT_CURLY: { lexer.skip_token (); // parse inner attributes AST::AttrVec inner_attrs = parse_inner_attributes (); + std::string module_path_name + = extract_module_path (inner_attrs, outer_attrs, name); + InlineModuleStackScope scope (*this, std::move (module_path_name)); + // parse items std::vector> items; const_TokenPtr tok = lexer.peek_token (); diff --git a/gcc/rust/parse/rust-parse.cc b/gcc/rust/parse/rust-parse.cc index fdad97c..e78de51 100644 --- a/gcc/rust/parse/rust-parse.cc +++ b/gcc/rust/parse/rust-parse.cc @@ -46,4 +46,77 @@ along with GCC; see the file COPYING3. If not see namespace Rust { +std::string +extract_module_path (const AST::AttrVec &inner_attrs, + const AST::AttrVec &outer_attrs, const std::string &name) +{ + AST::Attribute path_attr = AST::Attribute::create_empty (); + for (const auto &attr : inner_attrs) + { + if (attr.get_path ().as_string () == "path") + { + path_attr = attr; + break; + } + } + + // Here, we found a path attribute, but it has no associated string. This is + // invalid + if (!path_attr.is_empty () && !path_attr.has_attr_input ()) + { + rust_error_at ( + path_attr.get_locus (), + // Split the format string so that -Wformat-diag does not complain... + "path attributes must contain a filename: '%s'", "#![path = \"file\"]"); + return name; + } + + for (const auto &attr : outer_attrs) + { + if (attr.get_path ().as_string () == "path") + { + path_attr = attr; + break; + } + } + + // We didn't find a path attribute. This is not an error, there simply isn't + // one present + if (path_attr.is_empty ()) + return name; + + // Here, we found a path attribute, but it has no associated string. This is + // invalid + if (!path_attr.has_attr_input ()) + { + rust_error_at ( + path_attr.get_locus (), + // Split the format string so that -Wformat-diag does not complain... + "path attributes must contain a filename: '%s'", "#[path = \"file\"]"); + return name; + } + + auto path_value = path_attr.get_attr_input ().as_string (); + + // At this point, the 'path' is of the following format: '= ""' + // We need to remove the equal sign and only keep the actual filename. + // In order to do this, we can simply go through the string until we find + // a character that is not an equal sign or whitespace + auto filename_begin = path_value.find_first_not_of ("=\t "); + + auto path = path_value.substr (filename_begin); + + // On windows, the path might mix '/' and '\' separators. Replace the + // UNIX-like separators by MSDOS separators to make sure the path will resolve + // properly. + // + // Source: rustc compiler + // (https://github.com/rust-lang/rust/blob/9863bf51a52b8e61bcad312f81b5193d53099f9f/compiler/rustc_expand/src/module.rs#L174) +#if defined(HAVE_DOS_BASED_FILE_SYSTEM) + path.replace ('/', '\\'); +#endif /* HAVE_DOS_BASED_FILE_SYSTEM */ + + return path; +} + } // namespace Rust diff --git a/gcc/rust/parse/rust-parse.h b/gcc/rust/parse/rust-parse.h index 45f00f5..acab7ff 100644 --- a/gcc/rust/parse/rust-parse.h +++ b/gcc/rust/parse/rust-parse.h @@ -622,7 +622,26 @@ private: ManagedTokenSource lexer; // The error list. std::vector error_table; + // The names of inline modules while parsing. + std::vector inline_module_stack; + + class InlineModuleStackScope + { + private: + Parser &parser; + + public: + InlineModuleStackScope (Parser &parser, std::string name) : parser (parser) + { + parser.inline_module_stack.emplace_back (std::move (name)); + } + ~InlineModuleStackScope () { parser.inline_module_stack.pop_back (); } + }; }; + +std::string +extract_module_path (const AST::AttrVec &inner_attrs, + const AST::AttrVec &outer_attrs, const std::string &name); } // namespace Rust // as now template, include implementations of all methods -- cgit v1.1