auto merge of #12245 : nick29581/rust/priv2, r=alexcrichton

closes #4110
This commit is contained in:
bors 2014-02-18 18:11:48 -08:00
commit a25f447835
5 changed files with 552 additions and 111 deletions

View File

@ -41,6 +41,11 @@ pub type ExportedItems = HashSet<ast::NodeId>;
/// reexporting a public struct doesn't inline the doc).
pub type PublicItems = HashSet<ast::NodeId>;
/// Result of a checking operation - None => no errors were found. Some => an
/// error and contains the span and message for reporting that error and
/// optionally the same for a note about the error.
type CheckResult = Option<(Span, ~str, Option<(Span, ~str)>)>;
////////////////////////////////////////////////////////////////////////////////
/// The parent visitor, used to determine what's the parent of what (node-wise)
////////////////////////////////////////////////////////////////////////////////
@ -510,40 +515,50 @@ impl<'a> PrivacyVisitor<'a> {
}
}
/// Guarantee that a particular definition is public, possibly emitting an
/// error message if it's not.
fn ensure_public(&self, span: Span, to_check: ast::DefId,
source_did: Option<ast::DefId>, msg: &str) -> bool {
match self.def_privacy(to_check) {
ExternallyDenied => {
self.tcx.sess.span_err(span, format!("{} is private", msg))
}
DisallowedBy(id) => {
if id == source_did.unwrap_or(to_check).node {
self.tcx.sess.span_err(span, format!("{} is private", msg));
return false;
} else {
self.tcx.sess.span_err(span, format!("{} is inaccessible",
msg));
fn report_error(&self, result: CheckResult) -> bool {
match result {
None => true,
Some((span, msg, note)) => {
self.tcx.sess.span_err(span, msg);
match note {
Some((span, msg)) => self.tcx.sess.span_note(span, msg),
None => {},
}
false
},
}
}
/// Guarantee that a particular definition is public. Returns a CheckResult
/// which contains any errors found. These can be reported using `report_error`.
/// If the result is `None`, no errors were found.
fn ensure_public(&self, span: Span, to_check: ast::DefId,
source_did: Option<ast::DefId>, msg: &str) -> CheckResult {
match self.def_privacy(to_check) {
ExternallyDenied => Some((span, format!("{} is private", msg), None)),
DisallowedBy(id) => {
let (err_span, err_msg) = if id == source_did.unwrap_or(to_check).node {
return Some((span, format!("{} is private", msg), None));
} else {
(span, format!("{} is inaccessible", msg))
};
match self.tcx.map.find(id) {
Some(ast_map::NodeItem(item)) => {
let desc = match item.node {
ast::ItemMod(..) => "module",
ast::ItemTrait(..) => "trait",
_ => return false,
_ => return Some((err_span, err_msg, None)),
};
let msg = format!("{} `{}` is private",
desc,
token::get_ident(item.ident));
self.tcx.sess.span_note(span, msg);
}
Some(..) | None => {}
Some((err_span, err_msg, Some((span, msg))))
},
_ => Some((err_span, err_msg, None)),
}
}
Allowable => return true
},
Allowable => None,
}
return false;
}
// Checks that a field is in scope.
@ -613,34 +628,99 @@ impl<'a> PrivacyVisitor<'a> {
let method_id = ty::method(self.tcx, method_id).provided_source
.unwrap_or(method_id);
self.ensure_public(span,
method_id,
None,
format!("method `{}`", token::get_ident(name)));
let string = token::get_ident(name);
self.report_error(self.ensure_public(span,
method_id,
None,
format!("method `{}`", string)));
}
// Checks that a path is in scope.
fn check_path(&mut self, span: Span, path_id: ast::NodeId, path: &ast::Path) {
debug!("privacy - path {}", self.nodestr(path_id));
let def_map = self.tcx.def_map.borrow();
let def = def_map.get().get_copy(&path_id);
let orig_def = def_map.get().get_copy(&path_id);
let ck = |tyname: &str| {
let origdid = def_id_of_def(def);
let ck_public = |def: ast::DefId| {
let name = token::get_ident(path.segments
.last()
.unwrap()
.identifier);
let origdid = def_id_of_def(orig_def);
self.ensure_public(span,
def,
Some(origdid),
format!("{} `{}`",
tyname,
name))
};
match *self.last_private_map.get(&path_id) {
resolve::AllPublic => {},
resolve::DependsOn(def) => {
let name = token::get_ident(path.segments
.last()
.unwrap()
.identifier);
self.ensure_public(span,
def,
Some(origdid),
format!("{} `{}`",
tyname, name));
}
resolve::LastMod(resolve::AllPublic) => {},
resolve::LastMod(resolve::DependsOn(def)) => {
self.report_error(ck_public(def));
},
resolve::LastImport{value_priv: value_priv,
value_used: check_value,
type_priv: type_priv,
type_used: check_type} => {
// This dance with found_error is because we don't want to report
// a privacy error twice for the same directive.
let found_error = match (type_priv, check_type) {
(Some(resolve::DependsOn(def)), resolve::Used) => {
!self.report_error(ck_public(def))
},
_ => false,
};
if !found_error {
match (value_priv, check_value) {
(Some(resolve::DependsOn(def)), resolve::Used) => {
self.report_error(ck_public(def));
},
_ => {},
}
}
// If an import is not used in either namespace, we still want to check
// that it could be legal. Therefore we check in both namespaces and only
// report an error if both would be illegal. We only report one error,
// even if it is illegal to import from both namespaces.
match (value_priv, check_value, type_priv, check_type) {
(Some(p), resolve::Unused, None, _) |
(None, _, Some(p), resolve::Unused) => {
let p = match p {
resolve::AllPublic => None,
resolve::DependsOn(def) => ck_public(def),
};
if p.is_some() {
self.report_error(p);
}
},
(Some(v), resolve::Unused, Some(t), resolve::Unused) => {
let v = match v {
resolve::AllPublic => None,
resolve::DependsOn(def) => ck_public(def),
};
let t = match t {
resolve::AllPublic => None,
resolve::DependsOn(def) => ck_public(def),
};
match (v, t) {
(Some(_), Some(t)) => {
self.report_error(Some(t));
},
_ => {},
}
},
_ => {},
}
},
}
};
// FIXME(#12334) Imports can refer to definitions in both the type and
// value namespaces. The privacy information is aware of this, but the
// def map is not. Therefore the names we work out below will not always
// be accurate and we can get slightly wonky error messages (but type
// checking is always correct).
let def_map = self.tcx.def_map.borrow();
match def_map.get().get_copy(&path_id) {
ast::DefStaticMethod(..) => ck("static method"),
@ -668,7 +748,7 @@ impl<'a> PrivacyVisitor<'a> {
// is whether the trait itself is accessible or not.
method_param(method_param { trait_id: trait_id, .. }) |
method_object(method_object { trait_id: trait_id, .. }) => {
self.ensure_public(span, trait_id, None, "source trait");
self.report_error(self.ensure_public(span, trait_id, None, "source trait"));
}
}
}

View File

@ -8,7 +8,6 @@
// option. This file may not be copied, modified, or distributed
// except according to those terms.
use driver::session::Session;
use metadata::csearch;
use metadata::decoder::{DefLike, DlDef, DlField, DlImpl};
@ -64,14 +63,34 @@ pub type ExternalExports = HashSet<DefId>;
pub type LastPrivateMap = HashMap<NodeId, LastPrivate>;
pub enum LastPrivate {
LastMod(PrivateDep),
// `use` directives (imports) can refer to two separate definitions in the
// type and value namespaces. We record here the last private node for each
// and whether the import is in fact used for each.
// If the Option<PrivateDep> fields are None, it means there is no defintion
// in that namespace.
LastImport{value_priv: Option<PrivateDep>,
value_used: ImportUse,
type_priv: Option<PrivateDep>,
type_used: ImportUse},
}
pub enum PrivateDep {
AllPublic,
DependsOn(DefId),
}
// How an import is used.
#[deriving(Eq)]
pub enum ImportUse {
Unused, // The import is not used.
Used, // The import is used.
}
impl LastPrivate {
fn or(self, other: LastPrivate) -> LastPrivate {
match (self, other) {
(me, AllPublic) => me,
(me, LastMod(AllPublic)) => me,
(_, other) => other,
}
}
@ -84,7 +103,7 @@ enum PatternBindingMode {
ArgumentIrrefutableMode,
}
#[deriving(Eq)]
#[deriving(Eq, IterBytes)]
enum Namespace {
TypeNS,
ValueNS
@ -869,7 +888,7 @@ struct Resolver {
// so as to avoid printing duplicate errors
emit_errors: bool,
used_imports: HashSet<NodeId>,
used_imports: HashSet<(NodeId, Namespace)>,
}
struct BuildReducedGraphVisitor<'a> {
@ -904,7 +923,7 @@ impl<'a> Visitor<ReducedGraphParent> for BuildReducedGraphVisitor<'a> {
}
struct UnusedImportCheckVisitor<'a> { resolver: &'a Resolver }
struct UnusedImportCheckVisitor<'a> { resolver: &'a mut Resolver }
impl<'a> Visitor<()> for UnusedImportCheckVisitor<'a> {
fn visit_view_item(&mut self, vi: &ViewItem, _: ()) {
@ -2152,7 +2171,7 @@ impl Resolver {
// First, resolve the module path for the directive, if necessary.
let container = if module_path.len() == 0 {
// Use the crate root.
Some((self.graph_root.get_module(), AllPublic))
Some((self.graph_root.get_module(), LastMod(AllPublic)))
} else {
match self.resolve_module_path(module_,
*module_path,
@ -2257,6 +2276,12 @@ impl Resolver {
directive.id,
lp);
let lp = match lp {
LastMod(lp) => lp,
LastImport{..} => self.session.span_bug(directive.span,
"Not expecting Import here, must be LastMod"),
};
// We need to resolve both namespaces for this to succeed.
//
@ -2287,7 +2312,8 @@ impl Resolver {
// Unless we managed to find a result in both namespaces (unlikely),
// search imports as well.
let mut used_reexport = false;
let mut value_used_reexport = false;
let mut type_used_reexport = false;
match (value_result, type_result) {
(BoundResult(..), BoundResult(..)) => {} // Continue.
_ => {
@ -2342,7 +2368,7 @@ impl Resolver {
}
Some(target) => {
let id = import_resolution.id(namespace);
this.used_imports.insert(id);
this.used_imports.insert((id, namespace));
return BoundResult(target.target_module,
target.bindings);
}
@ -2354,12 +2380,12 @@ impl Resolver {
if value_result.is_unknown() {
value_result = get_binding(self, *import_resolution,
ValueNS);
used_reexport = import_resolution.is_public.get();
value_used_reexport = import_resolution.is_public.get();
}
if type_result.is_unknown() {
type_result = get_binding(self, *import_resolution,
TypeNS);
used_reexport = import_resolution.is_public.get();
type_used_reexport = import_resolution.is_public.get();
}
}
@ -2375,7 +2401,8 @@ impl Resolver {
// If we didn't find a result in the type namespace, search the
// external modules.
let mut used_public = false;
let mut value_used_public = false;
let mut type_used_public = false;
match type_result {
BoundResult(..) => {}
_ => {
@ -2393,7 +2420,7 @@ impl Resolver {
module);
type_result = BoundResult(containing_module,
name_bindings);
used_public = true;
type_used_public = true;
}
}
}
@ -2412,7 +2439,7 @@ impl Resolver {
import_resolution.value_target.set(
Some(Target::new(target_module, name_bindings)));
import_resolution.value_id.set(directive.id);
used_public = name_bindings.defined_in_public_namespace(ValueNS);
value_used_public = name_bindings.defined_in_public_namespace(ValueNS);
}
UnboundResult => { /* Continue. */ }
UnknownResult => {
@ -2426,7 +2453,7 @@ impl Resolver {
import_resolution.type_target.set(
Some(Target::new(target_module, name_bindings)));
import_resolution.type_id.set(directive.id);
used_public = name_bindings.defined_in_public_namespace(TypeNS);
type_used_public = name_bindings.defined_in_public_namespace(TypeNS);
}
UnboundResult => { /* Continue. */ }
UnknownResult => {
@ -2443,7 +2470,8 @@ impl Resolver {
self.resolve_error(directive.span, msg);
return Failed;
}
let used_public = used_reexport || used_public;
let value_used_public = value_used_reexport || value_used_public;
let type_used_public = type_used_reexport || type_used_public;
assert!(import_resolution.outstanding_references.get() >= 1);
import_resolution.outstanding_references.set(
@ -2452,28 +2480,33 @@ impl Resolver {
// record what this import resolves to for later uses in documentation,
// this may resolve to either a value or a type, but for documentation
// purposes it's good enough to just favor one over the other.
match import_resolution.value_target.get() {
let value_private = match import_resolution.value_target.get() {
Some(target) => {
let def = target.bindings.def_for_namespace(ValueNS).unwrap();
let mut def_map = self.def_map.borrow_mut();
def_map.get().insert(directive.id, def);
let did = def_id_of_def(def);
self.last_private.insert(directive.id,
if used_public {lp} else {DependsOn(did)});
}
None => {}
}
match import_resolution.type_target.get() {
if value_used_public {Some(lp)} else {Some(DependsOn(did))}
},
// AllPublic here and below is a dummy value, it should never be used because
// _exists is false.
None => None,
};
let type_private = match import_resolution.type_target.get() {
Some(target) => {
let def = target.bindings.def_for_namespace(TypeNS).unwrap();
let mut def_map = self.def_map.borrow_mut();
def_map.get().insert(directive.id, def);
let did = def_id_of_def(def);
self.last_private.insert(directive.id,
if used_public {lp} else {DependsOn(did)});
}
None => {}
}
if type_used_public {Some(lp)} else {Some(DependsOn(did))}
},
None => None,
};
self.last_private.insert(directive.id, LastImport{value_priv: value_private,
value_used: Used,
type_priv: type_private,
type_used: Used});
debug!("(resolving single import) successfully resolved import");
return Success(());
@ -2732,7 +2765,7 @@ impl Resolver {
.get() {
Some(did) => {
closest_private =
DependsOn(did);
LastMod(DependsOn(did));
}
None => {}
}
@ -2817,7 +2850,7 @@ impl Resolver {
// resolution process at index zero.
search_module = self.graph_root.get_module();
start_index = 0;
last_private = AllPublic;
last_private = LastMod(AllPublic);
}
UseLexicalScope => {
// This is not a crate-relative path. We resolve the
@ -2839,7 +2872,7 @@ impl Resolver {
Success(containing_module) => {
search_module = containing_module;
start_index = 1;
last_private = AllPublic;
last_private = LastMod(AllPublic);
}
}
}
@ -2848,9 +2881,9 @@ impl Resolver {
Success(PrefixFound(containing_module, index)) => {
search_module = containing_module;
start_index = index;
last_private = DependsOn(containing_module.def_id
.get()
.unwrap());
last_private = LastMod(DependsOn(containing_module.def_id
.get()
.unwrap()));
}
}
@ -2914,7 +2947,7 @@ impl Resolver {
Some(target) => {
debug!("(resolving item in lexical scope) using \
import resolution");
self.used_imports.insert(import_resolution.id(namespace));
self.used_imports.insert((import_resolution.id(namespace), namespace));
return Success((target, false));
}
}
@ -3199,7 +3232,7 @@ impl Resolver {
Some(target) => {
debug!("(resolving name in module) resolved to \
import");
self.used_imports.insert(import_resolution.id(namespace));
self.used_imports.insert((import_resolution.id(namespace), namespace));
return Success((target, true));
}
}
@ -3808,7 +3841,7 @@ impl Resolver {
// Associate this type parameter with
// the item that bound it
self.record_def(type_parameter.id,
(DefTyParamBinder(node_id), AllPublic));
(DefTyParamBinder(node_id), LastMod(AllPublic)));
// plain insert (no renaming)
let mut bindings = function_type_rib.bindings
.borrow_mut();
@ -4269,7 +4302,7 @@ impl Resolver {
Some(&primitive_type) => {
result_def =
Some((DefPrimTy(primitive_type), AllPublic));
Some((DefPrimTy(primitive_type), LastMod(AllPublic)));
if path.segments
.iter()
@ -4438,7 +4471,7 @@ impl Resolver {
// will be able to distinguish variants from
// locals in patterns.
self.record_def(pattern.id, (def, AllPublic));
self.record_def(pattern.id, (def, LastMod(AllPublic)));
// Add the binding to the local ribs, if it
// doesn't already exist in the bindings list. (We
@ -4632,10 +4665,10 @@ impl Resolver {
// the lookup happened only within the current module.
match def.def {
def @ DefVariant(..) | def @ DefStruct(..) => {
return FoundStructOrEnumVariant(def, AllPublic);
return FoundStructOrEnumVariant(def, LastMod(AllPublic));
}
def @ DefStatic(_, false) => {
return FoundConst(def, AllPublic);
return FoundConst(def, LastMod(AllPublic));
}
_ => {
return BareIdentifierPatternUnresolved;
@ -4711,7 +4744,7 @@ impl Resolver {
namespace,
span) {
Some(def) => {
return Some((def, AllPublic));
return Some((def, LastMod(AllPublic)));
}
None => {
// Continue.
@ -4741,8 +4774,8 @@ impl Resolver {
// Found it. Stop the search here.
let p = child_name_bindings.defined_in_public_namespace(
namespace);
let lp = if p {AllPublic} else {
DependsOn(def_id_of_def(def))
let lp = if p {LastMod(AllPublic)} else {
LastMod(DependsOn(def_id_of_def(def)))
};
return ChildNameDefinition(def, lp);
}
@ -4764,8 +4797,8 @@ impl Resolver {
Some(def) => {
// Found it.
let id = import_resolution.id(namespace);
self.used_imports.insert(id);
return ImportNameDefinition(def, AllPublic);
self.used_imports.insert((id, namespace));
return ImportNameDefinition(def, LastMod(AllPublic));
}
None => {
// This can happen with external impls, due to
@ -4792,8 +4825,8 @@ impl Resolver {
match module.def_id.get() {
None => {} // Continue.
Some(def_id) => {
let lp = if module.is_public {AllPublic} else {
DependsOn(def_id)
let lp = if module.is_public {LastMod(AllPublic)} else {
LastMod(DependsOn(def_id))
};
return ChildNameDefinition(DefMod(def_id), lp);
}
@ -4887,7 +4920,7 @@ impl Resolver {
0,
path.span,
PathSearch,
AllPublic) {
LastMod(AllPublic)) {
Failed => {
let msg = format!("use of undeclared module `::{}`",
self.idents_to_str(module_path_idents));
@ -4983,7 +5016,7 @@ impl Resolver {
// This lookup is "all public" because it only searched
// for one identifier in the current module (couldn't
// have passed through reexports or anything like that.
return Some((def, AllPublic));
return Some((def, LastMod(AllPublic)));
}
}
}
@ -5194,8 +5227,8 @@ impl Resolver {
format!("use of undeclared label `{}`",
token::get_name(label))),
Some(DlDef(def @ DefLabel(_))) => {
// FIXME: is AllPublic correct?
self.record_def(expr.id, (def, AllPublic))
// Since this def is a label, it is never read.
self.record_def(expr.id, (def, LastMod(AllPublic)))
}
Some(_) => {
self.session.span_bug(expr.span,
@ -5353,7 +5386,7 @@ impl Resolver {
};
if candidate_traits.contains(&did) {
self.add_trait_info(&mut found_traits, did, name);
self.used_imports.insert(import.type_id.get());
self.used_imports.insert((import.type_id.get(), TypeNS));
}
}
@ -5395,6 +5428,8 @@ impl Resolver {
fn record_def(&mut self, node_id: NodeId, (def, lp): (Def, LastPrivate)) {
debug!("(recording def) recording {:?} for {:?}, last private {:?}",
def, node_id, lp);
assert!(match lp {LastImport{..} => false, _ => true},
"Import should only be used for `use` directives");
self.last_private.insert(node_id, lp);
let mut def_map = self.def_map.borrow_mut();
def_map.get().insert_or_update_with(node_id, def, |_, old_value| {
@ -5426,16 +5461,17 @@ impl Resolver {
//
// Unused import checking
//
// Although this is a lint pass, it lives in here because it depends on
// resolve data structures.
// Although this is mostly a lint pass, it lives in here because it depends on
// resolve data structures and because it finalises the privacy information for
// `use` directives.
//
fn check_for_unused_imports(&self, krate: &ast::Crate) {
fn check_for_unused_imports(&mut self, krate: &ast::Crate) {
let mut visitor = UnusedImportCheckVisitor{ resolver: self };
visit::walk_crate(&mut visitor, krate, ());
}
fn check_for_item_unused_imports(&self, vi: &ViewItem) {
fn check_for_item_unused_imports(&mut self, vi: &ViewItem) {
// Ignore is_public import statements because there's no way to be sure
// whether they're used or not. Also ignore imports with a dummy span
// because this means that they were generated in some fashion by the
@ -5448,29 +5484,73 @@ impl Resolver {
ViewItemUse(ref path) => {
for p in path.iter() {
match p.node {
ViewPathSimple(_, _, id) | ViewPathGlob(_, id) => {
if !self.used_imports.contains(&id) {
self.session.add_lint(UnusedImports,
id, p.span,
~"unused import");
}
}
ViewPathSimple(_, _, id) => self.finalize_import(id, p.span),
ViewPathList(_, ref list, _) => {
for i in list.iter() {
if !self.used_imports.contains(&i.node.id) {
self.session.add_lint(UnusedImports,
i.node.id, i.span,
~"unused import");
}
self.finalize_import(i.node.id, i.span);
}
}
},
ViewPathGlob(_, id) => {
if !self.used_imports.contains(&(id, TypeNS)) &&
!self.used_imports.contains(&(id, ValueNS)) {
self.session.add_lint(UnusedImports, id, p.span, ~"unused import");
}
},
}
}
}
}
}
// We have information about whether `use` (import) directives are actually used now.
// If an import is not used at all, we signal a lint error. If an import is only used
// for a single namespace, we remove the other namespace from the recorded privacy
// information. That means in privacy.rs, we will only check imports and namespaces
// which are used. In particular, this means that if an import could name either a
// public or private item, we will check the correct thing, dependent on how the import
// is used.
fn finalize_import(&mut self, id: NodeId, span: Span) {
debug!("finalizing import uses for {}", self.session.codemap.span_to_snippet(span));
if !self.used_imports.contains(&(id, TypeNS)) &&
!self.used_imports.contains(&(id, ValueNS)) {
self.session.add_lint(UnusedImports, id, span, ~"unused import");
}
let (v_priv, t_priv) = match self.last_private.find(&id) {
Some(&LastImport{value_priv: v,
value_used: _,
type_priv: t,
type_used: _}) => (v, t),
Some(_) => fail!("We should only have LastImport for `use` directives"),
_ => return,
};
let mut v_used = if self.used_imports.contains(&(id, ValueNS)) {
Used
} else {
Unused
};
let t_used = if self.used_imports.contains(&(id, TypeNS)) {
Used
} else {
Unused
};
match (v_priv, t_priv) {
// Since some items may be both in the value _and_ type namespaces (e.g., structs)
// we might have two LastPrivates pointing at the same thing. There is no point
// checking both, so lets not check the value one.
(Some(DependsOn(def_v)), Some(DependsOn(def_t))) if def_v == def_t => v_used = Unused,
_ => {},
}
self.last_private.insert(id, LastImport{value_priv: v_priv,
value_used: v_used,
type_priv: t_priv,
type_used: t_used});
}
//
// Diagnostics
//

View File

@ -0,0 +1,66 @@
// 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.
// Check we do the correct privacy checks when we import a name and there is an
// item with that name in both the value and type namespaces.
#[feature(globs)];
#[allow(dead_code)];
#[allow(unused_imports)];
// public type, private value
pub mod foo1 {
pub trait Bar {
}
pub struct Baz;
fn Bar() { }
}
fn test_glob1() {
use foo1::*;
Bar(); //~ ERROR unresolved name `Bar`.
}
// private type, public value
pub mod foo2 {
trait Bar {
}
pub struct Baz;
pub fn Bar() { }
}
fn test_glob2() {
use foo2::*;
let _x: ~Bar; //~ ERROR use of undeclared type name `Bar`
}
// neither public
pub mod foo3 {
trait Bar {
}
pub struct Baz;
fn Bar() { }
}
fn test_glob3() {
use foo3::*;
Bar(); //~ ERROR unresolved name `Bar`.
let _x: ~Bar; //~ ERROR use of undeclared type name `Bar`
}
fn main() {
}

View File

@ -0,0 +1,91 @@
// 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.
// Check we do the correct privacy checks when we import a name and there is an
// item with that name in both the value and type namespaces.
#[feature(globs)];
#[allow(dead_code)];
#[allow(unused_imports)];
// public type, private value
pub mod foo1 {
pub trait Bar {
}
pub struct Baz;
fn Bar() { }
}
fn test_single1() {
// In an ideal world, these would be private instead of inaccessible.
use foo1::Bar; //~ ERROR `Bar` is inaccessible
Bar();
}
fn test_list1() {
use foo1::{Bar,Baz}; //~ ERROR `Bar` is inaccessible
Bar();
}
// private type, public value
pub mod foo2 {
trait Bar {
}
pub struct Baz;
pub fn Bar() { }
}
fn test_single2() {
use foo2::Bar; //~ ERROR `Bar` is private
let _x : ~Bar;
}
fn test_list2() {
use foo2::{Bar,Baz}; //~ ERROR `Bar` is private
let _x: ~Bar;
}
// neither public
pub mod foo3 {
trait Bar {
}
pub struct Baz;
fn Bar() { }
}
fn test_unused3() {
use foo3::Bar; //~ ERROR `Bar` is private
use foo3::{Bar,Baz}; //~ ERROR `Bar` is private
}
fn test_single3() {
use foo3::Bar; //~ ERROR `Bar` is private
Bar();
let _x: ~Bar;
}
fn test_list3() {
use foo3::{Bar,Baz}; //~ ERROR `Bar` is private
Bar();
let _x: ~Bar;
}
fn main() {
}

View File

@ -0,0 +1,124 @@
// 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.
// ignore-fast
// Check we do the correct privacy checks when we import a name and there is an
// item with that name in both the value and type namespaces.
#[feature(globs)];
#[allow(dead_code)];
#[allow(unused_imports)];
// public type, private value
pub mod foo1 {
pub trait Bar {
}
pub struct Baz;
fn Bar() { }
}
fn test_unused1() {
use foo1::Bar;
use foo1::{Bar,Baz};
use foo1::*;
}
fn test_single1() {
use foo1::Bar;
let _x: ~Bar;
}
fn test_list1() {
use foo1::{Bar,Baz};
let _x: ~Bar;
}
fn test_glob1() {
use foo1::*;
let _x: ~Bar;
}
// private type, public value
pub mod foo2 {
trait Bar {
}
pub struct Baz;
pub fn Bar() { }
}
fn test_unused2() {
use foo2::Bar;
use foo2::{Bar,Baz};
use foo2::*;
}
fn test_single2() {
use foo2::Bar;
Bar();
}
fn test_list2() {
use foo2::{Bar,Baz};
Bar();
}
fn test_glob2() {
use foo2::*;
Bar();
}
// public type, public value
pub mod foo3 {
pub trait Bar {
}
pub struct Baz;
pub fn Bar() { }
}
fn test_unused3() {
use foo3::Bar;
use foo3::{Bar,Baz};
use foo3::*;
}
fn test_single3() {
use foo3::Bar;
Bar();
let _x: ~Bar;
}
fn test_list3() {
use foo3::{Bar,Baz};
Bar();
let _x: ~Bar;
}
fn test_glob3() {
use foo3::*;
Bar();
let _x: ~Bar;
}
fn main() {
}