aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorBen Boeckel <mathstuf@gmail.com>2021-10-31 19:59:37 -0400
committerBen Boeckel <mathstuf@gmail.com>2021-11-03 07:09:01 -0400
commit1657ee53d578d68c7d807312b1063ffd804d7ef9 (patch)
tree502c1c87dc290c7301907a46791c4b2996697cbb
parent09af9b16b436606fa8ced0aa6cc111555bdc3da7 (diff)
downloadgcc-1657ee53d578d68c7d807312b1063ffd804d7ef9.zip
gcc-1657ee53d578d68c7d807312b1063ffd804d7ef9.tar.gz
gcc-1657ee53d578d68c7d807312b1063ffd804d7ef9.tar.bz2
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 <mathstuf@gmail.com>
-rw-r--r--gcc/rust/ast/rust-ast-full-test.cc71
-rw-r--r--gcc/rust/ast/rust-item.h11
-rw-r--r--gcc/rust/parse/rust-parse-impl.h8
-rw-r--r--gcc/rust/parse/rust-parse.cc73
-rw-r--r--gcc/rust/parse/rust-parse.h19
-rw-r--r--gcc/testsuite/rust/compile/missing_middle/both_path.rs3
-rw-r--r--gcc/testsuite/rust/compile/missing_middle/explicit.not.rs1
-rw-r--r--gcc/testsuite/rust/compile/missing_middle/inner_path.rs3
-rw-r--r--gcc/testsuite/rust/compile/missing_middle/other.rs3
-rw-r--r--gcc/testsuite/rust/compile/missing_middle/outer_path.rs3
-rw-r--r--gcc/testsuite/rust/compile/missing_middle/sub/mod.rs3
-rw-r--r--gcc/testsuite/rust/compile/mod_missing_middle.rs29
12 files changed, 169 insertions, 58 deletions
diff --git a/gcc/rust/ast/rust-ast-full-test.cc b/gcc/rust/ast/rust-ast-full-test.cc
index a189d8c..8780853 100644
--- a/gcc/rust/ast/rust-ast-full-test.cc
+++ b/gcc/rust/ast/rust-ast-full-test.cc
@@ -3984,53 +3984,11 @@ file_exists (const std::string path)
static std::string
filename_from_path_attribute (std::vector<Attribute> &outer_attrs)
{
- Attribute path_attr = Attribute::create_empty ();
- for (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 "";
-
- // 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 "";
- }
-
- auto path_value = path_attr.get_attr_input ().as_string ();
-
- // At this point, the 'path' is of the following format: '= "<file.rs>"'
- // 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;
+ // An out-of-line module cannot have inner attributes. Additionally, the
+ // default name is specified as `""` so that the caller can detect the case
+ // of "no path given" and use the default path logic (`name.rs` or
+ // `name/mod.rs`).
+ return extract_module_path ({}, outer_attrs, "");
}
void
@@ -4057,6 +4015,13 @@ Module::process_file_path ()
current_directory_name
= including_fname.substr (0, dir_slash_pos) + file_separator;
+ // Handle inline module declarations adding path components.
+ for (auto const &name : module_scope)
+ {
+ current_directory_name.append (name);
+ current_directory_name.append (file_separator);
+ }
+
auto path_string = filename_from_path_attribute (get_outer_attrs ());
if (!path_string.empty ())
{
@@ -4070,12 +4035,13 @@ Module::process_file_path ()
// current file is titled `mod.rs`.
// First, we search for <directory>/<module_name>.rs
- bool file_mod_found
- = file_exists (current_directory_name + expected_file_path);
+ std::string file_mod_path = current_directory_name + expected_file_path;
+ bool file_mod_found = file_exists (file_mod_path);
// Then, search for <directory>/<module_name>/mod.rs
- current_directory_name += module_name + file_separator;
- bool dir_mod_found = file_exists (current_directory_name + expected_dir_path);
+ std::string dir_mod_path
+ = current_directory_name + module_name + file_separator + expected_dir_path;
+ bool dir_mod_found = file_exists (dir_mod_path);
bool multiple_candidates_found = file_mod_found && dir_mod_found;
bool no_candidates_found = !file_mod_found && !dir_mod_found;
@@ -4093,8 +4059,7 @@ Module::process_file_path ()
if (no_candidates_found || multiple_candidates_found)
return;
- module_file = file_mod_found ? expected_file_path
- : current_directory_name + expected_dir_path;
+ module_file = std::move (file_mod_found ? file_mod_path : dir_mod_path);
}
void
diff --git a/gcc/rust/ast/rust-item.h b/gcc/rust/ast/rust-item.h
index 39411f8..f952dcc 100644
--- a/gcc/rust/ast/rust-item.h
+++ b/gcc/rust/ast/rust-item.h
@@ -991,6 +991,8 @@ private:
std::vector<Attribute> inner_attrs;
// bool has_items;
std::vector<std::unique_ptr<Item>> items;
+ // Names of including inline modules (immediate parent is last in the list)
+ std::vector<std::string> module_scope;
// Filename the module refers to. Empty string on LOADED modules or if an
// error occured when dealing with UNLOADED modules
@@ -1013,11 +1015,12 @@ public:
// Unloaded module constructor
Module (Identifier module_name, Visibility visibility,
std::vector<Attribute> outer_attrs, Location locus,
- std::string outer_filename)
+ std::string outer_filename, std::vector<std::string> module_scope)
: VisItem (std::move (visibility), std::move (outer_attrs)),
module_name (module_name), locus (locus), kind (ModuleKind::UNLOADED),
outer_filename (outer_filename), inner_attrs (std::vector<Attribute> ()),
- items (std::vector<std::unique_ptr<Item>> ())
+ items (std::vector<std::unique_ptr<Item>> ()),
+ module_scope (std::move (module_scope))
{}
// Loaded module constructor, with items
@@ -1035,7 +1038,8 @@ public:
// Copy constructor with vector clone
Module (Module const &other)
: VisItem (other), module_name (other.module_name), locus (other.locus),
- kind (other.kind), inner_attrs (other.inner_attrs)
+ kind (other.kind), inner_attrs (other.inner_attrs),
+ module_scope (other.module_scope)
{
// We need to check whether we are copying a loaded module or an unloaded
// one. In the second case, clear the `items` vector.
@@ -1054,6 +1058,7 @@ public:
locus = other.locus;
kind = other.kind;
inner_attrs = other.inner_attrs;
+ module_scope = other.module_scope;
// Likewise, we need to clear the `items` vector in case the other module is
// unloaded
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<ManagedTokenSource>::parse_module (AST::Visibility vis,
// Construct an external module
return std::unique_ptr<AST::Module> (
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<std::unique_ptr<AST::Item>> 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: '= "<file.rs>"'
+ // 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> error_table;
+ // The names of inline modules while parsing.
+ std::vector<std::string> 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
diff --git a/gcc/testsuite/rust/compile/missing_middle/both_path.rs b/gcc/testsuite/rust/compile/missing_middle/both_path.rs
new file mode 100644
index 0000000..5e5ad15
--- /dev/null
+++ b/gcc/testsuite/rust/compile/missing_middle/both_path.rs
@@ -0,0 +1,3 @@
+pub fn f() -> u32 {
+ 5
+}
diff --git a/gcc/testsuite/rust/compile/missing_middle/explicit.not.rs b/gcc/testsuite/rust/compile/missing_middle/explicit.not.rs
new file mode 100644
index 0000000..e28288b
--- /dev/null
+++ b/gcc/testsuite/rust/compile/missing_middle/explicit.not.rs
@@ -0,0 +1 @@
+mod other;
diff --git a/gcc/testsuite/rust/compile/missing_middle/inner_path.rs b/gcc/testsuite/rust/compile/missing_middle/inner_path.rs
new file mode 100644
index 0000000..daf4e3c
--- /dev/null
+++ b/gcc/testsuite/rust/compile/missing_middle/inner_path.rs
@@ -0,0 +1,3 @@
+pub fn f() -> u32 {
+ 4
+}
diff --git a/gcc/testsuite/rust/compile/missing_middle/other.rs b/gcc/testsuite/rust/compile/missing_middle/other.rs
new file mode 100644
index 0000000..0c0884e
--- /dev/null
+++ b/gcc/testsuite/rust/compile/missing_middle/other.rs
@@ -0,0 +1,3 @@
+pub fn f() -> u32 {
+ 2
+}
diff --git a/gcc/testsuite/rust/compile/missing_middle/outer_path.rs b/gcc/testsuite/rust/compile/missing_middle/outer_path.rs
new file mode 100644
index 0000000..fbe5074
--- /dev/null
+++ b/gcc/testsuite/rust/compile/missing_middle/outer_path.rs
@@ -0,0 +1,3 @@
+pub fn f() -> u32 {
+ 3
+}
diff --git a/gcc/testsuite/rust/compile/missing_middle/sub/mod.rs b/gcc/testsuite/rust/compile/missing_middle/sub/mod.rs
new file mode 100644
index 0000000..f099d61
--- /dev/null
+++ b/gcc/testsuite/rust/compile/missing_middle/sub/mod.rs
@@ -0,0 +1,3 @@
+pub fn f() -> u32 {
+ 1
+}
diff --git a/gcc/testsuite/rust/compile/mod_missing_middle.rs b/gcc/testsuite/rust/compile/mod_missing_middle.rs
new file mode 100644
index 0000000..7963340
--- /dev/null
+++ b/gcc/testsuite/rust/compile/mod_missing_middle.rs
@@ -0,0 +1,29 @@
+// { dg-additional-options "-w" }
+
+mod missing_middle {
+ mod sub;
+
+ #[path = "explicit.not.rs"]
+ mod explicit;
+}
+
+#[path = "missing_middle"]
+mod with_outer_path_attr {
+ #[path = "outer_path.rs"]
+ mod inner;
+}
+
+mod with_inner_path_attr {
+ #![path = "missing_middle"]
+
+ #[path = "inner_path.rs"]
+ mod inner;
+}
+
+#[path = "missing_middle"]
+mod with_both_path_attr {
+ #![path = "this_is_ignored"]
+
+ #[path = "both_path.rs"]
+ mod inner;
+}