diff --git a/src/librustc_resolve/resolve_imports.rs b/src/librustc_resolve/resolve_imports.rs index f0e834d4303..ff684d37653 100644 --- a/src/librustc_resolve/resolve_imports.rs +++ b/src/librustc_resolve/resolve_imports.rs @@ -275,7 +275,6 @@ impl<'a> ::ModuleS<'a> { // Define the name or return the existing binding if there is a collision. pub fn try_define_child(&self, name: Name, ns: Namespace, binding: NameBinding<'a>) -> Result<(), &'a NameBinding<'a>> { - if self.resolutions.borrow_state() != ::std::cell::BorrowState::Unused { return Ok(()); } self.update_resolution(name, ns, |resolution| { resolution.try_define(self.arenas.alloc_name_binding(binding)) }) @@ -318,15 +317,22 @@ impl<'a> ::ModuleS<'a> { fn update_resolution(&self, name: Name, ns: Namespace, update: F) -> T where F: FnOnce(&mut NameResolution<'a>) -> T { - let mut resolution = &mut *self.resolution(name, ns).borrow_mut(); - let was_known = resolution.binding().is_some(); + // Ensure that `resolution` isn't borrowed during `define_in_glob_importers`, + // where it might end up getting re-defined via a glob cycle. + let (new_binding, t) = { + let mut resolution = &mut *self.resolution(name, ns).borrow_mut(); + let was_known = resolution.binding().is_some(); - let t = update(resolution); - if !was_known { - if let Some(binding) = resolution.binding() { - self.define_in_glob_importers(name, ns, binding); + let t = update(resolution); + + if was_known { return t; } + match resolution.binding() { + Some(binding) => (binding, t), + None => return t, } - } + }; + + self.define_in_glob_importers(name, ns, new_binding); t } @@ -650,11 +656,14 @@ impl<'a, 'b:'a, 'tcx:'b> ImportResolver<'a, 'b, 'tcx> { // Add to target_module's glob_importers target_module.glob_importers.borrow_mut().push((module_, directive)); - for (&(name, ns), resolution) in target_module.resolutions.borrow().iter() { - if let Some(binding) = resolution.borrow().binding() { - if binding.defined_with(DefModifiers::IMPORTABLE | DefModifiers::PUBLIC) { - let _ = module_.try_define_child(name, ns, directive.import(binding, None)); - } + // Ensure that `resolutions` isn't borrowed during `try_define_child`, + // since it might get updated via a glob cycle. + let bindings = target_module.resolutions.borrow().iter().filter_map(|(name, resolution)| { + resolution.borrow().binding().map(|binding| (*name, binding)) + }).collect::>(); + for ((name, ns), binding) in bindings { + if binding.defined_with(DefModifiers::IMPORTABLE | DefModifiers::PUBLIC) { + let _ = module_.try_define_child(name, ns, directive.import(binding, None)); } } diff --git a/src/test/compile-fail/glob-cycles.rs b/src/test/compile-fail/glob-cycles.rs new file mode 100644 index 00000000000..077ae19b4cb --- /dev/null +++ b/src/test/compile-fail/glob-cycles.rs @@ -0,0 +1,26 @@ +// Copyright 2016 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. + +mod foo { + pub use bar::*; + pub use main as f; //~ ERROR has already been imported +} + +mod bar { + pub use foo::*; +} + +pub use foo::*; +pub use baz::*; //~ ERROR has already been imported +mod baz { + pub use super::*; +} + +pub fn main() {} diff --git a/src/test/compile-fail/issue-32797.rs b/src/test/compile-fail/issue-32797.rs new file mode 100644 index 00000000000..af75783a710 --- /dev/null +++ b/src/test/compile-fail/issue-32797.rs @@ -0,0 +1,21 @@ +// Copyright 2016 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. + +pub use bar::*; +mod bar { + pub use super::*; +} + +pub use baz::*; //~ ERROR already been imported +mod baz { + pub use main as f; +} + +pub fn main() {}