Skip to content

Commit c33cedf

Browse files
committed
rustc: Improve errors on private static methods
This gives a better NOTE error message when a privacy error is encountered with a static method. Previously no note was emitted (due to lack of support), but now a note is emitted indicating that the struct/enum itself is private. Closes #13641
1 parent ba25fec commit c33cedf

File tree

2 files changed

+80
-29
lines changed

2 files changed

+80
-29
lines changed

src/librustc/middle/privacy.rs

+55-29
Original file line numberDiff line numberDiff line change
@@ -405,7 +405,8 @@ impl<'a> PrivacyVisitor<'a> {
405405
};
406406
}
407407

408-
debug!("privacy - local {:?} not public all the way down", did);
408+
debug!("privacy - local {} not public all the way down",
409+
self.tcx.map.node_to_str(did.node));
409410
// return quickly for things in the same module
410411
if self.parents.find(&did.node) == self.parents.find(&self.curitem) {
411412
debug!("privacy - same parent, we're done here");
@@ -526,31 +527,60 @@ impl<'a> PrivacyVisitor<'a> {
526527
/// If the result is `None`, no errors were found.
527528
fn ensure_public(&self, span: Span, to_check: ast::DefId,
528529
source_did: Option<ast::DefId>, msg: &str) -> CheckResult {
529-
match self.def_privacy(to_check) {
530-
ExternallyDenied => Some((span, format!("{} is private", msg), None)),
531-
DisallowedBy(id) => {
532-
let (err_span, err_msg) = if id == source_did.unwrap_or(to_check).node {
533-
return Some((span, format!("{} is private", msg), None));
534-
} else {
535-
(span, format!("{} is inaccessible", msg))
536-
};
537-
match self.tcx.map.find(id) {
538-
Some(ast_map::NodeItem(item)) => {
539-
let desc = match item.node {
540-
ast::ItemMod(..) => "module",
541-
ast::ItemTrait(..) => "trait",
530+
let id = match self.def_privacy(to_check) {
531+
ExternallyDenied => {
532+
return Some((span, format!("{} is private", msg), None))
533+
}
534+
Allowable => return None,
535+
DisallowedBy(id) => id,
536+
};
537+
538+
// If we're disallowed by a particular id, then we attempt to give a
539+
// nice error message to say why it was disallowed. It was either
540+
// because the item itself is private or because its parent is private
541+
// and its parent isn't in our ancestry.
542+
let (err_span, err_msg) = if id == source_did.unwrap_or(to_check).node {
543+
return Some((span, format!("{} is private", msg), None));
544+
} else {
545+
(span, format!("{} is inaccessible", msg))
546+
};
547+
let item = match self.tcx.map.find(id) {
548+
Some(ast_map::NodeItem(item)) => {
549+
match item.node {
550+
// If an impl disallowed this item, then this is resolve's
551+
// way of saying that a struct/enum's static method was
552+
// invoked, and the struct/enum itself is private. Crawl
553+
// back up the chains to find the relevant struct/enum that
554+
// was private.
555+
ast::ItemImpl(_, _, ref ty, _) => {
556+
let id = match ty.node {
557+
ast::TyPath(_, _, id) => id,
542558
_ => return Some((err_span, err_msg, None)),
543559
};
544-
let msg = format!("{} `{}` is private",
545-
desc,
546-
token::get_ident(item.ident));
547-
Some((err_span, err_msg, Some((span, msg))))
548-
},
549-
_ => Some((err_span, err_msg, None)),
560+
let def = self.tcx.def_map.borrow().get_copy(&id);
561+
let did = def_id_of_def(def);
562+
assert!(is_local(did));
563+
match self.tcx.map.get(did.node) {
564+
ast_map::NodeItem(item) => item,
565+
_ => self.tcx.sess.span_bug(item.span,
566+
"path is not an item")
567+
}
568+
}
569+
_ => item
550570
}
551-
},
552-
Allowable => None,
553-
}
571+
}
572+
Some(..) | None => return Some((err_span, err_msg, None)),
573+
};
574+
let desc = match item.node {
575+
ast::ItemMod(..) => "module",
576+
ast::ItemTrait(..) => "trait",
577+
ast::ItemStruct(..) => "struct",
578+
ast::ItemEnum(..) => "enum",
579+
_ => return Some((err_span, err_msg, None))
580+
};
581+
let msg = format!("{} `{}` is private", desc,
582+
token::get_ident(item.ident));
583+
Some((err_span, err_msg, Some((span, msg))))
554584
}
555585

556586
// Checks that a field is in scope.
@@ -622,12 +652,8 @@ impl<'a> PrivacyVisitor<'a> {
622652
.unwrap()
623653
.identifier);
624654
let origdid = def_id_of_def(orig_def);
625-
self.ensure_public(span,
626-
def,
627-
Some(origdid),
628-
format!("{} `{}`",
629-
tyname,
630-
name))
655+
self.ensure_public(span, def, Some(origdid),
656+
format!("{} `{}`", tyname, name))
631657
};
632658

633659
match *self.last_private_map.get(&path_id) {

src/test/compile-fail/issue-13641.rs

+25
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,25 @@
1+
// Copyright 2014 The Rust Project Developers. See the COPYRIGHT
2+
// file at the top-level directory of this distribution and at
3+
// http://rust-lang.org/COPYRIGHT.
4+
//
5+
// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
6+
// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
7+
// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
8+
// option. This file may not be copied, modified, or distributed
9+
// except according to those terms.
10+
11+
mod a {
12+
struct Foo;
13+
impl Foo { pub fn new() {} }
14+
enum Bar {}
15+
impl Bar { pub fn new() {} }
16+
}
17+
18+
fn main() {
19+
a::Foo::new();
20+
//~^ ERROR: static method `new` is inaccessible
21+
//~^^ NOTE: struct `Foo` is private
22+
a::Bar::new();
23+
//~^ ERROR: static method `new` is inaccessible
24+
//~^^ NOTE: enum `Bar` is private
25+
}

0 commit comments

Comments
 (0)