diff --git a/src/librustc_resolve/build_reduced_graph.rs b/src/librustc_resolve/build_reduced_graph.rs index 656d6a3661470..75b99bed43194 100644 --- a/src/librustc_resolve/build_reduced_graph.rs +++ b/src/librustc_resolve/build_reduced_graph.rs @@ -926,6 +926,11 @@ impl<'a, 'b:'a, 'tcx:'b> GraphBuilder<'a, 'b, 'tcx> { is_public, shadowable)); self.unresolved_imports += 1; + + if is_public { + module_.inc_pub_count(); + } + // Bump the reference count on the name. Or, if this is a glob, set // the appropriate flag. @@ -958,7 +963,10 @@ impl<'a, 'b:'a, 'tcx:'b> GraphBuilder<'a, 'b, 'tcx> { // Set the glob flag. This tells us that we don't know the // module's exports ahead of time. - module_.glob_count.set(module_.glob_count.get() + 1); + module_.inc_glob_count(); + if is_public { + module_.inc_pub_glob_count(); + } } } } diff --git a/src/librustc_resolve/lib.rs b/src/librustc_resolve/lib.rs index 8c2bb9a88025f..50a8c58853385 100644 --- a/src/librustc_resolve/lib.rs +++ b/src/librustc_resolve/lib.rs @@ -699,6 +699,12 @@ pub struct Module { // The number of unresolved globs that this module exports. glob_count: Cell, + // The number of unresolved pub imports (both regular and globs) in this module + pub_count: Cell, + + // The number of unresolved pub glob imports in this module + pub_glob_count: Cell, + // The index of the import we're resolving. resolved_import_count: Cell, @@ -726,6 +732,8 @@ impl Module { anonymous_children: RefCell::new(NodeMap()), import_resolutions: RefCell::new(HashMap::new()), glob_count: Cell::new(0), + pub_count: Cell::new(0), + pub_glob_count: Cell::new(0), resolved_import_count: Cell::new(0), populated: Cell::new(!external), } @@ -741,6 +749,30 @@ impl Module { } } +impl Module { + pub fn inc_glob_count(&self) { + self.glob_count.set(self.glob_count.get() + 1); + } + pub fn dec_glob_count(&self) { + assert!(self.glob_count.get() > 0); + self.glob_count.set(self.glob_count.get() - 1); + } + pub fn inc_pub_count(&self) { + self.pub_count.set(self.pub_count.get() + 1); + } + pub fn dec_pub_count(&self) { + assert!(self.pub_count.get() > 0); + self.pub_count.set(self.pub_count.get() - 1); + } + pub fn inc_pub_glob_count(&self) { + self.pub_glob_count.set(self.pub_glob_count.get() + 1); + } + pub fn dec_pub_glob_count(&self) { + assert!(self.pub_glob_count.get() > 0); + self.pub_glob_count.set(self.pub_glob_count.get() - 1); + } +} + impl fmt::Debug for Module { fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { write!(f, "{:?}, kind: {:?}, {}", diff --git a/src/librustc_resolve/resolve_imports.rs b/src/librustc_resolve/resolve_imports.rs index 412643ba94546..5a377d2c5fe12 100644 --- a/src/librustc_resolve/resolve_imports.rs +++ b/src/librustc_resolve/resolve_imports.rs @@ -407,13 +407,18 @@ impl<'a, 'b:'a, 'tcx:'b> ImportResolver<'a, 'b, 'tcx> { if resolution_result.success() { match import_directive.subclass { GlobImport => { - assert!(module_.glob_count.get() >= 1); - module_.glob_count.set(module_.glob_count.get() - 1); + module_.dec_glob_count(); + if import_directive.is_public { + module_.dec_pub_glob_count(); + } } SingleImport(..) => { // Ignore. } } + if import_directive.is_public { + module_.dec_pub_count(); + } } return resolution_result; @@ -503,8 +508,8 @@ impl<'a, 'b:'a, 'tcx:'b> ImportResolver<'a, 'b, 'tcx> { // containing module, bail out. We don't know enough to be // able to resolve this import. - if target_module.glob_count.get() > 0 { - debug!("(resolving single import) unresolved glob; \ + if target_module.pub_glob_count.get() > 0 { + debug!("(resolving single import) unresolved pub glob; \ bailing out"); return ResolveResult::Indeterminate; } @@ -767,16 +772,26 @@ impl<'a, 'b:'a, 'tcx:'b> ImportResolver<'a, 'b, 'tcx> { // We must bail out if the node has unresolved imports of any kind // (including globs). - if !(*target_module).all_imports_resolved() { + if (*target_module).pub_count.get() > 0 { debug!("(resolving glob import) target module has unresolved \ - imports; bailing out"); + pub imports; bailing out"); return ResolveResult::Indeterminate; } - assert_eq!(target_module.glob_count.get(), 0); - // Add all resolved imports from the containing module. let import_resolutions = target_module.import_resolutions.borrow(); + + if module_.import_resolutions.borrow_state() != ::std::cell::BorrowState::Unused { + // In this case, target_module == module_ + // This means we are trying to glob import a module into itself, + // and it is a no-go + debug!("(resolving glob imports) target module is current module; giving up"); + return ResolveResult::Failed(Some(( + import_directive.span, + "Cannot glob-import a module into itself.".into() + ))); + } + for (ident, target_import_resolution) in import_resolutions.iter() { debug!("(resolving glob import) writing module resolution \ {} into `{}`", diff --git a/src/test/compile-fail/issue-25396.rs b/src/test/compile-fail/issue-25396.rs index bf26a591b4b5d..3ada57c999305 100644 --- a/src/test/compile-fail/issue-25396.rs +++ b/src/test/compile-fail/issue-25396.rs @@ -11,14 +11,14 @@ use foo::baz; use bar::baz; //~ ERROR a module named `baz` has already been imported -use bar::Quux; //~ ERROR a trait named `Quux` has already been imported use foo::Quux; +use bar::Quux; //~ ERROR a trait named `Quux` has already been imported -use foo::blah; //~ ERROR a type named `blah` has already been imported -use bar::blah; +use foo::blah; +use bar::blah; //~ ERROR a type named `blah` has already been imported -use foo::WOMP; //~ ERROR a value named `WOMP` has already been imported -use bar::WOMP; +use foo::WOMP; +use bar::WOMP; //~ ERROR a value named `WOMP` has already been imported fn main() {} diff --git a/src/test/compile-fail/issue-8208.rs b/src/test/compile-fail/issue-8208.rs index 7e3f1171e252f..318089b3030f6 100644 --- a/src/test/compile-fail/issue-8208.rs +++ b/src/test/compile-fail/issue-8208.rs @@ -8,7 +8,17 @@ // option. This file may not be copied, modified, or distributed // except according to those terms. -use self::*; //~ ERROR: unresolved import +use self::*; //~ ERROR: unresolved import `self::*`. Cannot glob-import a module into itself. + +mod foo { + use foo::*; //~ ERROR: unresolved import `foo::*`. Cannot glob-import a module into itself. + + mod bar { + use super::bar::*; + //~^ ERROR: unresolved import `super::bar::*`. Cannot glob-import a module into itself. + } + +} fn main() { } diff --git a/src/test/run-pass/issue-4865-2.rs b/src/test/run-pass/issue-4865-2.rs new file mode 100644 index 0000000000000..6de2f437b20b9 --- /dev/null +++ b/src/test/run-pass/issue-4865-2.rs @@ -0,0 +1,33 @@ +// Copyright 2015 The Rust Project Developers. See the COPYRIGHT +// file at the top-level directory of this distribution and at +// http://rust-lang.org/COPYRIGHT. +// +// Licensed under the Apache License, Version 2.0 or the MIT license +// , at your +// option. This file may not be copied, modified, or distributed +// except according to those terms. + +// Previously, this would have failed to resolve due to the circular +// block between `use say` and `pub use hello::*`. +// +// Now, as `use say` is not `pub`, the glob import can resolve +// without any problem and this resolves fine. + +pub use hello::*; + +pub mod say { + pub fn hello() { println!("hello"); } +} + +pub mod hello { + use say; + + pub fn hello() { + say::hello(); + } +} + +fn main() { + hello(); +} diff --git a/src/test/run-pass/issue-4865-3.rs b/src/test/run-pass/issue-4865-3.rs new file mode 100644 index 0000000000000..d800ea6a66580 --- /dev/null +++ b/src/test/run-pass/issue-4865-3.rs @@ -0,0 +1,25 @@ +// Copyright 2015 The Rust Project Developers. See the COPYRIGHT +// file at the top-level directory of this distribution and at +// http://rust-lang.org/COPYRIGHT. +// +// Licensed under the Apache License, Version 2.0 or the MIT license +// , at your +// option. This file may not be copied, modified, or distributed +// except according to those terms. + +// This should resolve fine even with the circular imports as +// they are not `pub`. + +pub mod a { + use b::*; +} + +pub mod b { + use a::*; +} + +use a::*; + +fn main() { +}