diff options
author | bors[bot] <26634292+bors[bot]@users.noreply.github.com> | 2021-11-03 18:00:24 +0000 |
---|---|---|
committer | GitHub <noreply@github.com> | 2021-11-03 18:00:24 +0000 |
commit | 8e992e371bbd896c8b605e1ebade5cad80b1b411 (patch) | |
tree | 329a3e626fb05effe7383efb8df3bdf671f7e35c /gcc | |
parent | 674221a3b27f5455fddc793ec9aaf30a4d858ecb (diff) | |
parent | 1657ee53d578d68c7d807312b1063ffd804d7ef9 (diff) | |
download | gcc-8e992e371bbd896c8b605e1ebade5cad80b1b411.zip gcc-8e992e371bbd896c8b605e1ebade5cad80b1b411.tar.gz gcc-8e992e371bbd896c8b605e1ebade5cad80b1b411.tar.bz2 |
Merge #785
785: rust: track inline module scopes for module file resolution r=CohenArthur a=mathstuf
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>
---
Note that this does not include a test case because I have no idea how to mark up this for all the warnings that come out (#676):
```diff
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 00000000000..f099d61e04a
--- /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 00000000000..d9cdf0a54f1
--- /dev/null
+++ b/gcc/testsuite/rust/compile/mod_missing_middle.rs
`@@` -0,0 +1,11 `@@`
+pub mod missing_middle {
+ pub mod sub;
+}
```
Observed warnings:
```
/home/boeckb/code/depot/group-compilers/gcc/src-gccrs/gcc/testsuite/rust/compile/missing_middle/sub/mod.rs:1:5: warning: unused name 'f'
/home/boeckb/code/depot/group-compilers/gcc/src-gccrs/gcc/testsuite/rust/compile/mod_missing_middle.rs:2:9: warning: unused name 'sub'
/home/boeckb/code/depot/group-compilers/gcc/src-gccrs/gcc/testsuite/rust/compile/missing_middle/sub/mod.rs:1:5: warning: unused name 'sub::f'
/home/boeckb/code/depot/group-compilers/gcc/src-gccrs/gcc/testsuite/rust/compile/mod_missing_middle.rs:2:9: warning: unused name 'missing_middle::sub'
/home/boeckb/code/depot/group-compilers/gcc/src-gccrs/gcc/testsuite/rust/compile/mod_missing_middle.rs:1:5: warning: unused name 'missing_middle'
/home/boeckb/code/depot/group-compilers/gcc/src-gccrs/gcc/testsuite/rust/compile/missing_middle/sub/mod.rs:1:5: warning: unused name 'missing_middle::sub::f'
```
Fixes: #645
Here is a checklist to help you with your PR.
- \[x] GCC development requires copyright assignment or the Developer's Certificate of Origin sign-off, see https://gcc.gnu.org/contribute.html or https://gcc.gnu.org/dco.html
- \[x] Read contributing guidlines
- \[x] `make check-rust` passes locally
- \[x] Run `clang-format` (leaving to CI)
- \[x] Added any relevant test cases to `gcc/testsuite/rust/` (see above)
Co-authored-by: Ben Boeckel <mathstuf@gmail.com>
Diffstat (limited to 'gcc')
-rw-r--r-- | gcc/rust/ast/rust-ast-full-test.cc | 71 | ||||
-rw-r--r-- | gcc/rust/ast/rust-item.h | 11 | ||||
-rw-r--r-- | gcc/rust/parse/rust-parse-impl.h | 8 | ||||
-rw-r--r-- | gcc/rust/parse/rust-parse.cc | 73 | ||||
-rw-r--r-- | gcc/rust/parse/rust-parse.h | 19 | ||||
-rw-r--r-- | gcc/testsuite/rust/compile/missing_middle/both_path.rs | 3 | ||||
-rw-r--r-- | gcc/testsuite/rust/compile/missing_middle/explicit.not.rs | 1 | ||||
-rw-r--r-- | gcc/testsuite/rust/compile/missing_middle/inner_path.rs | 3 | ||||
-rw-r--r-- | gcc/testsuite/rust/compile/missing_middle/other.rs | 3 | ||||
-rw-r--r-- | gcc/testsuite/rust/compile/missing_middle/outer_path.rs | 3 | ||||
-rw-r--r-- | gcc/testsuite/rust/compile/missing_middle/sub/mod.rs | 3 | ||||
-rw-r--r-- | gcc/testsuite/rust/compile/mod_missing_middle.rs | 29 |
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; +} |