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
This commit is contained in:
Alex Crichton 2014-04-08 14:31:25 -07:00
parent 0bf4e900d4
commit 83d2c0b8a6
8 changed files with 101 additions and 18 deletions

View file

@ -324,7 +324,7 @@ pub fn mkdir(p: &CString, _mode: io::FilePermission) -> IoResult<()> {
}
pub fn readdir(p: &CString) -> IoResult<Vec<Path>> {
use rt::global_heap::malloc_raw;
use std::rt::global_heap::malloc_raw;
fn prune(root: &CString, dirs: Vec<Path>) -> Vec<Path> {
let root = unsafe { CString::new(root.with_ref(|p| p), false) };

View file

@ -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
}
}

View file

@ -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.

View file

@ -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 <LICENSE-APACHE or
// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
// option. This file may not be copied, modified, or distributed
// except according to those terms.
pub mod bar {
pub fn foo() {}
}

View file

@ -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 <LICENSE-APACHE or
// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
// option. This file may not be copied, modified, or distributed
// except according to those terms.
pub fn baz() {}

View file

@ -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 <LICENSE-APACHE or
// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
// <LICENSE-MIT or http://opensource.org/licenses/MIT>, 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() {}

View file

@ -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;

View file

@ -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 <LICENSE-APACHE or
// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
// <LICENSE-MIT or http://opensource.org/licenses/MIT>, 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() {}