Skip to content

Commit a9836e7

Browse files
committed
auto merge of #9856 : alexcrichton/rust/privacy-errors, r=huonw
This stops labeling everything as "is private" when in fact the destination may be public. Instead, the clause "is inaccessible" is used and the private part of the flag is called out with a "is private" message. Closes #9793
2 parents df187a0 + 082cc96 commit a9836e7

File tree

3 files changed

+95
-45
lines changed

3 files changed

+95
-45
lines changed

src/librustc/middle/privacy.rs

Lines changed: 83 additions & 38 deletions
Original file line numberDiff line numberDiff line change
@@ -21,7 +21,7 @@ use middle::typeck::{method_static, method_object};
2121

2222
use syntax::ast;
2323
use syntax::ast_map;
24-
use syntax::ast_util::is_local;
24+
use syntax::ast_util::{is_local, def_id_of_def};
2525
use syntax::attr;
2626
use syntax::codemap::Span;
2727
use syntax::parse::token;
@@ -250,6 +250,12 @@ struct PrivacyVisitor<'self> {
250250
last_private_map: resolve::LastPrivateMap,
251251
}
252252

253+
enum PrivacyResult {
254+
Allowable,
255+
ExternallyDenied,
256+
DisallowedBy(ast::NodeId),
257+
}
258+
253259
impl<'self> PrivacyVisitor<'self> {
254260
// used when debugging
255261
fn nodestr(&self, id: ast::NodeId) -> ~str {
@@ -258,11 +264,11 @@ impl<'self> PrivacyVisitor<'self> {
258264

259265
// Determines whether the given definition is public from the point of view
260266
// of the current item.
261-
fn def_public(&self, did: ast::DefId) -> bool {
267+
fn def_privacy(&self, did: ast::DefId) -> PrivacyResult {
262268
if !is_local(did) {
263269
if self.external_exports.contains(&did) {
264270
debug2!("privacy - {:?} was externally exported", did);
265-
return true;
271+
return Allowable;
266272
}
267273
debug2!("privacy - is {:?} a public method", did);
268274
return match self.tcx.methods.find(&did) {
@@ -271,38 +277,42 @@ impl<'self> PrivacyVisitor<'self> {
271277
match meth.container {
272278
ty::TraitContainer(id) => {
273279
debug2!("privacy - recursing on trait {:?}", id);
274-
self.def_public(id)
280+
self.def_privacy(id)
275281
}
276282
ty::ImplContainer(id) => {
277283
match ty::impl_trait_ref(self.tcx, id) {
278284
Some(t) => {
279285
debug2!("privacy - impl of trait {:?}", id);
280-
self.def_public(t.def_id)
286+
self.def_privacy(t.def_id)
281287
}
282288
None => {
283289
debug2!("privacy - found a method {:?}",
284290
meth.vis);
285-
meth.vis == ast::public
291+
if meth.vis == ast::public {
292+
Allowable
293+
} else {
294+
ExternallyDenied
295+
}
286296
}
287297
}
288298
}
289299
}
290300
}
291301
None => {
292302
debug2!("privacy - nope, not even a method");
293-
false
303+
ExternallyDenied
294304
}
295305
};
296306
} else if self.exported_items.contains(&did.node) {
297307
debug2!("privacy - exported item {}", self.nodestr(did.node));
298-
return true;
308+
return Allowable;
299309
}
300310

301311
debug2!("privacy - local {:?} not public all the way down", did);
302312
// return quickly for things in the same module
303313
if self.parents.find(&did.node) == self.parents.find(&self.curitem) {
304314
debug2!("privacy - same parent, we're done here");
305-
return true;
315+
return Allowable;
306316
}
307317

308318
// We now know that there is at least one private member between the
@@ -330,7 +340,11 @@ impl<'self> PrivacyVisitor<'self> {
330340
assert!(closest_private_id != ast::DUMMY_NODE_ID);
331341
}
332342
debug2!("privacy - closest priv {}", self.nodestr(closest_private_id));
333-
return self.private_accessible(closest_private_id);
343+
if self.private_accessible(closest_private_id) {
344+
Allowable
345+
} else {
346+
DisallowedBy(closest_private_id)
347+
}
334348
}
335349

336350
/// For a local private node in the AST, this function will determine
@@ -365,12 +379,51 @@ impl<'self> PrivacyVisitor<'self> {
365379
}
366380
}
367381

382+
/// Guarantee that a particular definition is public, possibly emitting an
383+
/// error message if it's not.
384+
fn ensure_public(&self, span: Span, to_check: ast::DefId,
385+
source_did: Option<ast::DefId>, msg: &str) -> bool {
386+
match self.def_privacy(to_check) {
387+
ExternallyDenied => {
388+
self.tcx.sess.span_err(span, format!("{} is private", msg))
389+
}
390+
DisallowedBy(id) => {
391+
if id == source_did.unwrap_or(to_check).node {
392+
self.tcx.sess.span_err(span, format!("{} is private", msg));
393+
return false;
394+
} else {
395+
self.tcx.sess.span_err(span, format!("{} is inaccessible",
396+
msg));
397+
}
398+
match self.tcx.items.find(&id) {
399+
Some(&ast_map::node_item(item, _)) => {
400+
let desc = match item.node {
401+
ast::item_mod(*) => "module",
402+
ast::item_trait(*) => "trait",
403+
_ => return false,
404+
};
405+
let msg = format!("{} `{}` is private", desc,
406+
token::ident_to_str(&item.ident));
407+
self.tcx.sess.span_note(span, msg);
408+
}
409+
Some(*) | None => {}
410+
}
411+
}
412+
Allowable => return true
413+
}
414+
return false;
415+
}
416+
368417
// Checks that a dereference of a univariant enum can occur.
369418
fn check_variant(&self, span: Span, enum_id: ast::DefId) {
370419
let variant_info = ty::enum_variants(self.tcx, enum_id)[0];
371-
if !self.def_public(variant_info.id) {
372-
self.tcx.sess.span_err(span, "can only dereference enums \
373-
with a single, public variant");
420+
421+
match self.def_privacy(variant_info.id) {
422+
Allowable => {}
423+
ExternallyDenied | DisallowedBy(*) => {
424+
self.tcx.sess.span_err(span, "can only dereference enums \
425+
with a single, public variant");
426+
}
374427
}
375428
}
376429

@@ -399,29 +452,24 @@ impl<'self> PrivacyVisitor<'self> {
399452
let method_id = ty::method(self.tcx, method_id).provided_source
400453
.unwrap_or(method_id);
401454

402-
if !self.def_public(method_id) {
403-
debug2!("private: {:?}", method_id);
404-
self.tcx.sess.span_err(span, format!("method `{}` is private",
405-
token::ident_to_str(name)));
406-
}
455+
self.ensure_public(span, method_id, None,
456+
format!("method `{}`", token::ident_to_str(name)));
407457
}
408458

409459
// Checks that a path is in scope.
410460
fn check_path(&mut self, span: Span, path_id: ast::NodeId, path: &ast::Path) {
411461
debug2!("privacy - path {}", self.nodestr(path_id));
462+
let def = self.tcx.def_map.get_copy(&path_id);
412463
let ck = |tyname: &str| {
413-
let last_private = *self.last_private_map.get(&path_id);
414-
debug2!("privacy - {:?}", last_private);
415-
let public = match last_private {
416-
resolve::AllPublic => true,
417-
resolve::DependsOn(def) => self.def_public(def),
418-
};
419-
if !public {
420-
debug2!("denying {:?}", path);
421-
let name = token::ident_to_str(&path.segments.last()
422-
.identifier);
423-
self.tcx.sess.span_err(span,
424-
format!("{} `{}` is private", tyname, name));
464+
let origdid = def_id_of_def(def);
465+
match *self.last_private_map.get(&path_id) {
466+
resolve::AllPublic => {},
467+
resolve::DependsOn(def) => {
468+
let name = token::ident_to_str(&path.segments.last()
469+
.identifier);
470+
self.ensure_public(span, def, Some(origdid),
471+
format!("{} `{}`", tyname, name));
472+
}
425473
}
426474
};
427475
match self.tcx.def_map.get_copy(&path_id) {
@@ -456,9 +504,8 @@ impl<'self> PrivacyVisitor<'self> {
456504
method_num: method_num,
457505
_
458506
}) => {
459-
if !self.def_public(trait_id) {
460-
self.tcx.sess.span_err(span, "source trait is private");
461-
return;
507+
if !self.ensure_public(span, trait_id, None, "source trait") {
508+
return
462509
}
463510
match self.tcx.items.find(&trait_id.node) {
464511
Some(&ast_map::node_item(item, _)) => {
@@ -470,12 +517,10 @@ impl<'self> PrivacyVisitor<'self> {
470517
node: method.id,
471518
crate: trait_id.crate,
472519
};
473-
if self.def_public(def) { return }
474-
let msg = format!("method `{}` is \
475-
private",
520+
self.ensure_public(span, def, None,
521+
format!("method `{}`",
476522
token::ident_to_str(
477-
&method.ident));
478-
self.tcx.sess.span_err(span, msg);
523+
&method.ident)));
479524
}
480525
ast::required(_) => {
481526
// Required methods can't be private.

src/test/compile-fail/export-tag-variant.rs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -14,4 +14,4 @@ mod foo {
1414
enum y { y1, }
1515
}
1616

17-
fn main() { let z = foo::y1; } //~ ERROR: is private
17+
fn main() { let z = foo::y1; } //~ ERROR: is inaccessible

src/test/compile-fail/privacy1.rs

Lines changed: 11 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -100,11 +100,14 @@ mod foo {
100100
::bar::A::bar(); //~ ERROR: method `bar` is private
101101
::bar::A.foo2();
102102
::bar::A.bar2(); //~ ERROR: method `bar2` is private
103-
::bar::baz::A::foo(); //~ ERROR: method `foo` is private
103+
::bar::baz::A::foo(); //~ ERROR: method `foo` is inaccessible
104+
//~^ NOTE: module `baz` is private
104105
::bar::baz::A::bar(); //~ ERROR: method `bar` is private
105-
::bar::baz::A.foo2(); //~ ERROR: struct `A` is private
106-
::bar::baz::A.bar2(); //~ ERROR: struct `A` is private
106+
::bar::baz::A.foo2(); //~ ERROR: struct `A` is inaccessible
107+
//~^ NOTE: module `baz` is private
108+
::bar::baz::A.bar2(); //~ ERROR: struct `A` is inaccessible
107109
//~^ ERROR: method `bar2` is private
110+
//~^^ NOTE: module `baz` is private
108111
::lol();
109112

110113
::bar::Priv; //~ ERROR: variant `Priv` is private
@@ -120,13 +123,14 @@ mod foo {
120123

121124
::bar::gpub();
122125

123-
::bar::baz::foo(); //~ ERROR: function `foo` is private
126+
::bar::baz::foo(); //~ ERROR: function `foo` is inaccessible
127+
//~^ NOTE: module `baz` is private
124128
::bar::baz::bar(); //~ ERROR: function `bar` is private
125129
}
126130

127131
fn test2() {
128132
use bar::baz::{foo, bar};
129-
//~^ ERROR: function `foo` is private
133+
//~^ ERROR: function `foo` is inaccessible
130134
//~^^ ERROR: function `bar` is private
131135
foo();
132136
bar();
@@ -155,7 +159,8 @@ pub mod mytest {
155159
// external crates through `foo::foo`, it should not be accessible through
156160
// its definition path (which has the private `i` module).
157161
use self::foo::foo;
158-
use self::foo::i::A; //~ ERROR: type `A` is private
162+
use self::foo::i::A; //~ ERROR: type `A` is inaccessible
163+
//~^ NOTE: module `i` is private
159164

160165
pub mod foo {
161166
pub use foo = self::i::A;

0 commit comments

Comments
 (0)