From 83d2c0b8a6f6c2ce25fe48b541f176ea88be8d99 Mon Sep 17 00:00:00 2001 From: Alex Crichton Date: Tue, 8 Apr 2014 14:31:25 -0700 Subject: [PATCH] rustc: Disallow importing through use statements Resolve is currently erroneously allowing imports through private `use` statements in some circumstances, even across module boundaries. For example, this code compiles successfully today: use std::c_str; mod test { use c_str::CString; } This should not be allowed because it was explicitly decided that private `use` statements are purely bringing local names into scope, they are not participating further in name resolution. As a consequence of this patch, this code, while valid today, is now invalid: mod test { use std::c_str; unsafe fn foo() { ::test::c_str::CString::new(0 as *u8, false); } } While plausibly acceptable, I found it to be more consistent if private imports were only considered candidates to resolve the first component in a path, and no others. Closes #12612 --- src/libnative/io/file_win32.rs | 2 +- src/librustc/front/test.rs | 14 ++++++++------ src/librustc/middle/resolve.rs | 22 +++++++++++++++++----- src/test/auxiliary/issue-12612-1.rs | 13 +++++++++++++ src/test/auxiliary/issue-12612-2.rs | 11 +++++++++++ src/test/compile-fail/issue-12612.rs | 24 ++++++++++++++++++++++++ src/test/run-pass/issue-11881.rs | 10 ++++------ src/test/run-pass/issue-12612.rs | 23 +++++++++++++++++++++++ 8 files changed, 101 insertions(+), 18 deletions(-) create mode 100644 src/test/auxiliary/issue-12612-1.rs create mode 100644 src/test/auxiliary/issue-12612-2.rs create mode 100644 src/test/compile-fail/issue-12612.rs create mode 100644 src/test/run-pass/issue-12612.rs diff --git a/src/libnative/io/file_win32.rs b/src/libnative/io/file_win32.rs index 8090042f090..de515659bf7 100644 --- a/src/libnative/io/file_win32.rs +++ b/src/libnative/io/file_win32.rs @@ -324,7 +324,7 @@ pub fn mkdir(p: &CString, _mode: io::FilePermission) -> IoResult<()> { } pub fn readdir(p: &CString) -> IoResult> { - use rt::global_heap::malloc_raw; + use std::rt::global_heap::malloc_raw; fn prune(root: &CString, dirs: Vec) -> Vec { let root = unsafe { CString::new(root.with_ref(|p| p), false) }; diff --git a/src/librustc/front/test.rs b/src/librustc/front/test.rs index 86d2e039505..dff3d8b03bc 100644 --- a/src/librustc/front/test.rs +++ b/src/librustc/front/test.rs @@ -297,20 +297,22 @@ mod __test { fn mk_std(cx: &TestCtxt) -> ast::ViewItem { let id_test = token::str_to_ident("test"); - let vi = if cx.is_test_crate { - ast::ViewItemUse( + let (vi, vis) = if cx.is_test_crate { + (ast::ViewItemUse( vec!(@nospan(ast::ViewPathSimple(id_test, path_node(vec!(id_test)), - ast::DUMMY_NODE_ID)))) + ast::DUMMY_NODE_ID)))), + ast::Public) } else { - ast::ViewItemExternCrate(id_test, + (ast::ViewItemExternCrate(id_test, with_version("test"), - ast::DUMMY_NODE_ID) + ast::DUMMY_NODE_ID), + ast::Inherited) }; ast::ViewItem { node: vi, attrs: Vec::new(), - vis: ast::Inherited, + vis: vis, span: DUMMY_SP } } diff --git a/src/librustc/middle/resolve.rs b/src/librustc/middle/resolve.rs index 95101dc6337..cfacf0ee3df 100644 --- a/src/librustc/middle/resolve.rs +++ b/src/librustc/middle/resolve.rs @@ -2286,10 +2286,12 @@ impl<'a> Resolver<'a> { } Some(child_name_bindings) => { if child_name_bindings.defined_in_namespace(ValueNS) { + debug!("(resolving single import) found value binding"); value_result = BoundResult(containing_module, *child_name_bindings); } if child_name_bindings.defined_in_namespace(TypeNS) { + debug!("(resolving single import) found type binding"); type_result = BoundResult(containing_module, *child_name_bindings); } @@ -2320,6 +2322,7 @@ impl<'a> Resolver<'a> { .borrow(); match import_resolutions.find(&source.name) { None => { + debug!("(resolving single import) no import"); // The containing module definitely doesn't have an // exported import with the name in question. We can // therefore accurately report that the names are @@ -2353,6 +2356,8 @@ impl<'a> Resolver<'a> { return UnboundResult; } Some(target) => { + debug!("(resolving single import) found \ + import in ns {:?}", namespace); let id = import_resolution.id(namespace); this.used_imports.insert((id, namespace)); return BoundResult(target.target_module, @@ -2396,6 +2401,8 @@ impl<'a> Resolver<'a> { .find_copy(&source.name) { None => {} // Continue. Some(module) => { + debug!("(resolving single import) found external \ + module"); let name_bindings = @Resolver::create_name_bindings_from_module( module); @@ -2669,7 +2676,8 @@ impl<'a> Resolver<'a> { match self.resolve_name_in_module(search_module, name, TypeNS, - name_search_type) { + name_search_type, + false) { Failed => { let segment_name = token::get_ident(name); let module_name = self.module_to_str(search_module); @@ -2977,7 +2985,8 @@ impl<'a> Resolver<'a> { match self.resolve_name_in_module(search_module, name, namespace, - PathSearch) { + PathSearch, + true) { Failed => { // Continue up the search chain. } @@ -3141,7 +3150,8 @@ impl<'a> Resolver<'a> { module_: @Module, name: Ident, namespace: Namespace, - name_search_type: NameSearchType) + name_search_type: NameSearchType, + allow_private_imports: bool) -> ResolveResult<(Target, bool)> { debug!("(resolving name in module) resolving `{}` in `{}`", token::get_ident(name), @@ -3172,7 +3182,9 @@ impl<'a> Resolver<'a> { // Check the list of resolved imports. match module_.import_resolutions.borrow().find(&name.name) { - Some(import_resolution) => { + Some(import_resolution) if allow_private_imports || + import_resolution.is_public.get() => { + if import_resolution.is_public.get() && import_resolution.outstanding_references.get() != 0 { debug!("(resolving name in module) import \ @@ -3193,7 +3205,7 @@ impl<'a> Resolver<'a> { } } } - None => {} // Continue. + Some(..) | None => {} // Continue. } // Finally, search through external children. diff --git a/src/test/auxiliary/issue-12612-1.rs b/src/test/auxiliary/issue-12612-1.rs new file mode 100644 index 00000000000..a0234c1185a --- /dev/null +++ b/src/test/auxiliary/issue-12612-1.rs @@ -0,0 +1,13 @@ +// Copyright 2014 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 mod bar { + pub fn foo() {} +} diff --git a/src/test/auxiliary/issue-12612-2.rs b/src/test/auxiliary/issue-12612-2.rs new file mode 100644 index 00000000000..b4ae4374b2e --- /dev/null +++ b/src/test/auxiliary/issue-12612-2.rs @@ -0,0 +1,11 @@ +// Copyright 2014 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 fn baz() {} diff --git a/src/test/compile-fail/issue-12612.rs b/src/test/compile-fail/issue-12612.rs new file mode 100644 index 00000000000..9d6eb425678 --- /dev/null +++ b/src/test/compile-fail/issue-12612.rs @@ -0,0 +1,24 @@ +// Copyright 2014 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. + +// aux-build:issue-12612-1.rs + +extern crate foo = "issue-12612-1"; + +use foo::bar; + +mod test { + use bar::foo; + //~^ ERROR: unresolved import + //~^^ ERROR: failed to resolve import +} + +fn main() {} + diff --git a/src/test/run-pass/issue-11881.rs b/src/test/run-pass/issue-11881.rs index 2bf846fe341..7e51c6ad2ae 100644 --- a/src/test/run-pass/issue-11881.rs +++ b/src/test/run-pass/issue-11881.rs @@ -8,13 +8,11 @@ // option. This file may not be copied, modified, or distributed // except according to those terms. -extern crate ser = "serialize"; +extern crate serialize; -use serialize = self::ser; - //necessary for deriving(Encodable) -use ser::{Encodable, Encoder}; -use ser::json; -use ser::ebml::writer; +use serialize::{Encodable, Encoder}; +use serialize::json; +use serialize::ebml::writer; use std::io::MemWriter; use std::str::from_utf8_owned; diff --git a/src/test/run-pass/issue-12612.rs b/src/test/run-pass/issue-12612.rs new file mode 100644 index 00000000000..fcb658036b6 --- /dev/null +++ b/src/test/run-pass/issue-12612.rs @@ -0,0 +1,23 @@ +// Copyright 2014 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. + +// aux-build:issue-12612-1.rs +// aux-build:issue-12612-2.rs + +extern crate foo = "issue-12612-1"; +extern crate bar = "issue-12612-2"; + +use foo::bar; + +mod test { + use bar::baz; +} + +fn main() {}