Skip to content

Commit ec0fdd5

Browse files
committed
Lay the groundwork for privacy checking in typeck
1 parent c9852e2 commit ec0fdd5

File tree

6 files changed

+72
-50
lines changed

6 files changed

+72
-50
lines changed

src/librustc/front/map/mod.rs

Lines changed: 24 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -495,6 +495,30 @@ impl<'ast> Map<'ast> {
495495
}
496496
}
497497

498+
/// Returns the NodeId of `id`'s nearest module parent, or `id` itself if no
499+
/// module parent is in this map.
500+
fn get_module_parent(&self, id: NodeId) -> NodeId {
501+
match self.walk_parent_nodes(id, |node| match *node {
502+
NodeItem(&Item { node: Item_::ItemMod(_), .. }) => true,
503+
_ => false,
504+
}) {
505+
Ok(id) => id,
506+
Err(id) => id,
507+
}
508+
}
509+
510+
pub fn private_item_is_visible_from(&self, item: NodeId, block: NodeId) -> bool {
511+
// A private item is visible from everything in its nearest module parent.
512+
let visibility = self.get_module_parent(item);
513+
let mut block_ancestor = self.get_module_parent(block);
514+
loop {
515+
if block_ancestor == visibility { return true }
516+
let block_ancestor_parent = self.get_module_parent(block_ancestor);
517+
if block_ancestor_parent == block_ancestor { return false }
518+
block_ancestor = block_ancestor_parent;
519+
}
520+
}
521+
498522
/// Returns the nearest enclosing scope. A scope is an item or block.
499523
/// FIXME it is not clear to me that all items qualify as scopes - statics
500524
/// and associated types probably shouldn't, for example. Behaviour in this

src/librustc/middle/def.rs

Lines changed: 25 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -152,4 +152,29 @@ impl Def {
152152
_ => None
153153
}
154154
}
155+
156+
pub fn kind_name(&self) -> &'static str {
157+
match *self {
158+
Def::Fn(..) => "function",
159+
Def::Mod(..) => "module",
160+
Def::ForeignMod(..) => "foreign module",
161+
Def::Static(..) => "static",
162+
Def::Variant(..) => "variant",
163+
Def::Enum(..) => "enum",
164+
Def::TyAlias(..) => "type",
165+
Def::AssociatedTy(..) => "associated type",
166+
Def::Struct(..) => "struct",
167+
Def::Trait(..) => "trait",
168+
Def::Method(..) => "method",
169+
Def::Const(..) => "const",
170+
Def::AssociatedConst(..) => "associated const",
171+
Def::TyParam(..) => "type parameter",
172+
Def::PrimTy(..) => "builtin type",
173+
Def::Local(..) => "local variable",
174+
Def::Upvar(..) => "closure capture",
175+
Def::Label(..) => "label",
176+
Def::SelfTy(..) => "self type",
177+
Def::Err => "unresolved item",
178+
}
179+
}
155180
}

src/librustc/middle/ty/mod.rs

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -173,6 +173,14 @@ impl<'tcx> ImplOrTraitItem<'tcx> {
173173
}
174174
}
175175

176+
pub fn def(&self) -> Def {
177+
match *self {
178+
ConstTraitItem(ref associated_const) => Def::AssociatedConst(associated_const.def_id),
179+
MethodTraitItem(ref method) => Def::Method(method.def_id),
180+
TypeTraitItem(ref ty) => Def::AssociatedTy(ty.container.id(), ty.def_id),
181+
}
182+
}
183+
176184
pub fn def_id(&self) -> DefId {
177185
match *self {
178186
ConstTraitItem(ref associated_const) => associated_const.def_id,

src/librustc_privacy/lib.rs

Lines changed: 6 additions & 41 deletions
Original file line numberDiff line numberDiff line change
@@ -692,32 +692,7 @@ impl<'a, 'tcx> PrivacyVisitor<'a, 'tcx> {
692692
/// whether the node is accessible by the current module that iteration is
693693
/// inside.
694694
fn private_accessible(&self, id: ast::NodeId) -> bool {
695-
let parent = *self.parents.get(&id).unwrap();
696-
debug!("privacy - accessible parent {}", self.nodestr(parent));
697-
698-
// After finding `did`'s closest private member, we roll ourselves back
699-
// to see if this private member's parent is anywhere in our ancestry.
700-
// By the privacy rules, we can access all of our ancestor's private
701-
// members, so that's why we test the parent, and not the did itself.
702-
let mut cur = self.curitem;
703-
loop {
704-
debug!("privacy - questioning {}, {}", self.nodestr(cur), cur);
705-
match cur {
706-
// If the relevant parent is in our history, then we're allowed
707-
// to look inside any of our ancestor's immediate private items,
708-
// so this access is valid.
709-
x if x == parent => return true,
710-
711-
// If we've reached the root, then we couldn't access this item
712-
// in the first place
713-
ast::DUMMY_NODE_ID => return false,
714-
715-
// Keep going up
716-
_ => {}
717-
}
718-
719-
cur = *self.parents.get(&cur).unwrap();
720-
}
695+
self.tcx.map.private_item_is_visible_from(id, self.curitem)
721696
}
722697

723698
fn report_error(&self, result: CheckResult) -> bool {
@@ -835,7 +810,7 @@ impl<'a, 'tcx> PrivacyVisitor<'a, 'tcx> {
835810
}
836811
UnnamedField(idx) => &v.fields[idx]
837812
};
838-
if field.vis == hir::Public || self.local_private_accessible(field.did) {
813+
if field.vis == hir::Public || self.local_private_accessible(def.did) {
839814
return;
840815
}
841816

@@ -945,19 +920,9 @@ impl<'a, 'tcx> PrivacyVisitor<'a, 'tcx> {
945920
// def map is not. Therefore the names we work out below will not always
946921
// be accurate and we can get slightly wonky error messages (but type
947922
// checking is always correct).
948-
match path_res.full_def() {
949-
Def::Fn(..) => ck("function"),
950-
Def::Static(..) => ck("static"),
951-
Def::Const(..) => ck("const"),
952-
Def::AssociatedConst(..) => ck("associated const"),
953-
Def::Variant(..) => ck("variant"),
954-
Def::TyAlias(..) => ck("type"),
955-
Def::Enum(..) => ck("enum"),
956-
Def::Trait(..) => ck("trait"),
957-
Def::Struct(..) => ck("struct"),
958-
Def::Method(..) => ck("method"),
959-
Def::Mod(..) => ck("module"),
960-
_ => {}
923+
let def = path_res.full_def();
924+
if def != Def::Err {
925+
ck(def.kind_name());
961926
}
962927
}
963928

@@ -1036,7 +1001,7 @@ impl<'a, 'tcx, 'v> Visitor<'v> for PrivacyVisitor<'a, 'tcx> {
10361001
_ => expr_ty
10371002
}.ty_adt_def().unwrap();
10381003
let any_priv = def.struct_variant().fields.iter().any(|f| {
1039-
f.vis != hir::Public && !self.local_private_accessible(f.did)
1004+
f.vis != hir::Public && !self.local_private_accessible(def.did)
10401005
});
10411006
if any_priv {
10421007
span_err!(self.tcx.sess, expr.span, E0450,

src/librustc_typeck/check/method/mod.rs

Lines changed: 2 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -338,20 +338,13 @@ pub fn resolve_ufcs<'a, 'tcx>(fcx: &FnCtxt<'a, 'tcx>,
338338
{
339339
let mode = probe::Mode::Path;
340340
let pick = try!(probe::probe(fcx, span, mode, method_name, self_ty, expr_id));
341-
let def_id = pick.item.def_id();
341+
let def_result = pick.item.def();
342342
let mut lp = LastMod(AllPublic);
343343
if let probe::InherentImplPick = pick.kind {
344344
if pick.item.vis() != hir::Public {
345-
lp = LastMod(DependsOn(def_id));
345+
lp = LastMod(DependsOn(def_result.def_id()));
346346
}
347347
}
348-
let def_result = match pick.item {
349-
ty::ImplOrTraitItem::MethodTraitItem(..) => Def::Method(def_id),
350-
ty::ImplOrTraitItem::ConstTraitItem(..) => Def::AssociatedConst(def_id),
351-
ty::ImplOrTraitItem::TypeTraitItem(..) => {
352-
fcx.tcx().sess.span_bug(span, "resolve_ufcs: probe picked associated type");
353-
}
354-
};
355348
Ok((def_result, lp))
356349
}
357350

src/librustc_typeck/check/mod.rs

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2022,6 +2022,13 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
20222022
Err(errors) => { report_fulfillment_errors(self.infcx(), &errors); }
20232023
}
20242024
}
2025+
2026+
fn private_item_is_visible(&self, def_id: DefId) -> bool {
2027+
match self.tcx().map.as_local_node_id(def_id) {
2028+
Some(node_id) => self.tcx().map.private_item_is_visible_from(node_id, self.body_id),
2029+
None => false, // Private items from other crates are never visible
2030+
}
2031+
}
20252032
}
20262033

20272034
impl<'a, 'tcx> RegionScope for FnCtxt<'a, 'tcx> {

0 commit comments

Comments
 (0)