Skip to content

Commit b20d567

Browse files
committed
Privacy check paths in resolve and typeck
1 parent 07957ff commit b20d567

File tree

4 files changed

+98
-13
lines changed

4 files changed

+98
-13
lines changed

src/librustc_resolve/build_reduced_graph.rs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -499,7 +499,7 @@ impl<'a, 'b:'a, 'tcx:'b> GraphBuilder<'a, 'b, 'tcx> {
499499
debug!("(building reduced graph for external crate) building external def {}, priv {:?}",
500500
final_ident,
501501
vis);
502-
let is_public = vis == hir::Public;
502+
let is_public = vis == hir::Public || new_parent.is_trait();
503503

504504
let mut modifiers = DefModifiers::empty();
505505
if is_public {

src/librustc_resolve/lib.rs

Lines changed: 62 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -934,6 +934,15 @@ impl<'a> ModuleS<'a> {
934934
}
935935
}
936936

937+
fn is_ancestor_of(&self, module: Module<'a>) -> bool {
938+
if self.def_id() == module.def_id() { return true }
939+
match module.parent_link {
940+
ParentLink::BlockParentLink(parent, _) |
941+
ParentLink::ModuleParentLink(parent, _) => self.is_ancestor_of(parent),
942+
_ => false,
943+
}
944+
}
945+
937946
pub fn inc_glob_count(&self) {
938947
self.glob_count.set(self.glob_count.get() + 1);
939948
}
@@ -1000,9 +1009,14 @@ enum NameBindingKind<'a> {
10001009
Import {
10011010
binding: &'a NameBinding<'a>,
10021011
id: NodeId,
1012+
// Some(error) if using this imported name causes the import to be a privacy error
1013+
privacy_error: Option<Box<PrivacyError<'a>>>,
10031014
},
10041015
}
10051016

1017+
#[derive(Clone, Debug)]
1018+
struct PrivacyError<'a>(Span, Name, &'a NameBinding<'a>);
1019+
10061020
impl<'a> NameBinding<'a> {
10071021
fn create_from_module(module: Module<'a>, span: Option<Span>) -> Self {
10081022
let modifiers = if module.is_public {
@@ -1145,6 +1159,7 @@ pub struct Resolver<'a, 'tcx: 'a> {
11451159
// The intention is that the callback modifies this flag.
11461160
// Once set, the resolver falls out of the walk, preserving the ribs.
11471161
resolved: bool,
1162+
privacy_errors: Vec<PrivacyError<'a>>,
11481163

11491164
arenas: &'a ResolverArenas<'a>,
11501165
}
@@ -1209,6 +1224,7 @@ impl<'a, 'tcx> Resolver<'a, 'tcx> {
12091224

12101225
callback: None,
12111226
resolved: false,
1227+
privacy_errors: Vec::new(),
12121228

12131229
arenas: arenas,
12141230
}
@@ -1255,12 +1271,15 @@ impl<'a, 'tcx> Resolver<'a, 'tcx> {
12551271
self.used_crates.insert(krate);
12561272
}
12571273

1258-
let import_id = match binding.kind {
1259-
NameBindingKind::Import { id, .. } => id,
1274+
let (import_id, privacy_error) = match binding.kind {
1275+
NameBindingKind::Import { id, ref privacy_error, .. } => (id, privacy_error),
12601276
_ => return,
12611277
};
12621278

12631279
self.used_imports.insert((import_id, ns));
1280+
if let Some(error) = privacy_error.as_ref() {
1281+
self.privacy_errors.push((**error).clone());
1282+
}
12641283

12651284
if !self.make_glob_map {
12661285
return;
@@ -1352,6 +1371,7 @@ impl<'a, 'tcx> Resolver<'a, 'tcx> {
13521371
// Check to see whether there are type bindings, and, if
13531372
// so, whether there is a module within.
13541373
if let Some(module_def) = binding.module() {
1374+
self.check_privacy(search_module, name, binding, span);
13551375
search_module = module_def;
13561376
} else {
13571377
let msg = format!("Not a module `{}`", name);
@@ -2911,7 +2931,10 @@ impl<'a, 'tcx> Resolver<'a, 'tcx> {
29112931

29122932
let name = segments.last().unwrap().identifier.name;
29132933
let result = self.resolve_name_in_module(containing_module, name, namespace, false, true);
2914-
result.success().map(|binding| binding.def().unwrap())
2934+
result.success().map(|binding| {
2935+
self.check_privacy(containing_module, name, binding, span);
2936+
binding.def().unwrap()
2937+
})
29152938
}
29162939

29172940
/// Invariant: This must be called only during main resolution, not during
@@ -2958,7 +2981,10 @@ impl<'a, 'tcx> Resolver<'a, 'tcx> {
29582981

29592982
let name = segments.last().unwrap().identifier.name;
29602983
let result = self.resolve_name_in_module(containing_module, name, namespace, false, true);
2961-
result.success().map(|binding| binding.def().unwrap())
2984+
result.success().map(|binding| {
2985+
self.check_privacy(containing_module, name, binding, span);
2986+
binding.def().unwrap()
2987+
})
29622988
}
29632989

29642990
fn resolve_identifier_in_local_ribs(&mut self,
@@ -3570,6 +3596,37 @@ impl<'a, 'tcx> Resolver<'a, 'tcx> {
35703596
}
35713597
}
35723598
}
3599+
3600+
fn is_visible(&self, binding: &'a NameBinding<'a>, parent: Module<'a>) -> bool {
3601+
binding.is_public() || parent.is_ancestor_of(self.current_module)
3602+
}
3603+
3604+
fn check_privacy(&mut self,
3605+
module: Module<'a>,
3606+
name: Name,
3607+
binding: &'a NameBinding<'a>,
3608+
span: Span) {
3609+
if !self.is_visible(binding, module) {
3610+
self.privacy_errors.push(PrivacyError(span, name, binding));
3611+
}
3612+
}
3613+
3614+
fn report_privacy_errors(&self) {
3615+
if self.privacy_errors.len() == 0 { return }
3616+
let mut reported_spans = HashSet::new();
3617+
for &PrivacyError(span, name, binding) in &self.privacy_errors {
3618+
if !reported_spans.insert(span) { continue }
3619+
if binding.is_extern_crate() {
3620+
// Warn when using an inaccessible extern crate.
3621+
let node_id = binding.module().unwrap().extern_crate_id.unwrap();
3622+
let msg = format!("extern crate `{}` is private", name);
3623+
self.session.add_lint(lint::builtin::INACCESSIBLE_EXTERN_CRATE, node_id, span, msg);
3624+
} else {
3625+
let def = binding.def().unwrap();
3626+
self.session.span_err(span, &format!("{} `{}` is private", def.kind_name(), name));
3627+
}
3628+
}
3629+
}
35733630
}
35743631

35753632

@@ -3726,6 +3783,7 @@ pub fn resolve_crate<'a, 'tcx>(session: &'a Session,
37263783
resolver.resolve_crate(krate);
37273784

37283785
check_unused::check_crate(&mut resolver, krate);
3786+
resolver.report_privacy_errors();
37293787

37303788
CrateMap {
37313789
def_map: resolver.def_map,

src/librustc_resolve/resolve_imports.rs

Lines changed: 26 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -13,7 +13,7 @@ use self::ImportDirectiveSubclass::*;
1313
use DefModifiers;
1414
use Module;
1515
use Namespace::{self, TypeNS, ValueNS};
16-
use {NameBinding, NameBindingKind};
16+
use {NameBinding, NameBindingKind, PrivacyError};
1717
use ResolveResult;
1818
use ResolveResult::*;
1919
use Resolver;
@@ -78,7 +78,9 @@ impl ImportDirective {
7878

7979
// Given the binding to which this directive resolves in a particular namespace,
8080
// this returns the binding for the name this directive defines in that namespace.
81-
fn import<'a>(&self, binding: &'a NameBinding<'a>) -> NameBinding<'a> {
81+
fn import<'a>(&self,
82+
binding: &'a NameBinding<'a>,
83+
privacy_error: Option<Box<PrivacyError<'a>>>) -> NameBinding<'a> {
8284
let mut modifiers = match self.is_public {
8385
true => DefModifiers::PUBLIC | DefModifiers::IMPORTABLE,
8486
false => DefModifiers::empty(),
@@ -91,7 +93,11 @@ impl ImportDirective {
9193
}
9294

9395
NameBinding {
94-
kind: NameBindingKind::Import { binding: binding, id: self.id },
96+
kind: NameBindingKind::Import {
97+
binding: binding,
98+
id: self.id,
99+
privacy_error: privacy_error,
100+
},
95101
span: Some(self.span),
96102
modifiers: modifiers,
97103
}
@@ -219,7 +225,7 @@ impl<'a, 'b:'a, 'tcx:'b> ImportResolver<'a, 'b, 'tcx> {
219225
span: None,
220226
});
221227
let dummy_binding =
222-
self.resolver.new_name_binding(e.import_directive.import(dummy_binding));
228+
self.resolver.new_name_binding(e.import_directive.import(dummy_binding, None));
223229

224230
let _ = e.source_module.try_define_child(target, ValueNS, dummy_binding);
225231
let _ = e.source_module.try_define_child(target, TypeNS, dummy_binding);
@@ -419,17 +425,31 @@ impl<'a, 'b:'a, 'tcx:'b> ImportResolver<'a, 'b, 'tcx> {
419425
_ => {}
420426
}
421427

428+
let mut privacy_error = None;
429+
let mut report_privacy_error = true;
422430
for &(ns, result) in &[(ValueNS, &value_result), (TypeNS, &type_result)] {
423431
if let Success(binding) = *result {
424432
if !binding.defined_with(DefModifiers::IMPORTABLE) {
425433
let msg = format!("`{}` is not directly importable", target);
426434
span_err!(self.resolver.session, directive.span, E0253, "{}", &msg);
427435
}
428436

429-
self.define(module_, target, ns, directive.import(binding));
437+
privacy_error = if !self.resolver.is_visible(binding, target_module) {
438+
Some(Box::new(PrivacyError(directive.span, source, binding)))
439+
} else {
440+
report_privacy_error = false;
441+
None
442+
};
443+
444+
self.define(module_, target, ns, directive.import(binding, privacy_error.clone()));
430445
}
431446
}
432447

448+
if report_privacy_error { // then all successful namespaces are privacy errors
449+
// We report here so there is an error even if the imported name is not used
450+
self.resolver.privacy_errors.push(*privacy_error.unwrap());
451+
}
452+
433453
// Record what this import resolves to for later uses in documentation,
434454
// this may resolve to either a value or a type, but for documentation
435455
// purposes it's good enough to just favor one over the other.
@@ -472,7 +492,7 @@ impl<'a, 'b:'a, 'tcx:'b> ImportResolver<'a, 'b, 'tcx> {
472492
build_reduced_graph::populate_module_if_necessary(self.resolver, target_module);
473493
target_module.for_each_child(|name, ns, binding| {
474494
if !binding.defined_with(DefModifiers::IMPORTABLE | DefModifiers::PUBLIC) { return }
475-
self.define(module_, name, ns, directive.import(binding));
495+
self.define(module_, name, ns, directive.import(binding, None));
476496

477497
if ns == TypeNS && directive.is_public &&
478498
binding.defined_with(DefModifiers::PRIVATE_VARIANT) {

src/librustc_typeck/check/method/mod.rs

Lines changed: 9 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -337,9 +337,16 @@ pub fn resolve_ufcs<'a, 'tcx>(fcx: &FnCtxt<'a, 'tcx>,
337337
{
338338
let mode = probe::Mode::Path;
339339
let pick = try!(probe::probe(fcx, span, mode, method_name, self_ty, expr_id));
340-
Ok(pick.item.def())
341-
}
340+
let def = pick.item.def();
342341

342+
if let probe::InherentImplPick = pick.kind {
343+
if pick.item.vis() != hir::Public && !fcx.private_item_is_visible(def.def_id()) {
344+
let msg = format!("{} `{}` is private", def.kind_name(), &method_name.as_str());
345+
fcx.tcx().sess.span_err(span, &msg);
346+
}
347+
}
348+
Ok(def)
349+
}
343350

344351
/// Find item with name `item_name` defined in `trait_def_id`
345352
/// and return it, or `None`, if no such item.

0 commit comments

Comments
 (0)