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
This commit is contained in:
parent
ba25fecfef
commit
c33cedf359
2 changed files with 80 additions and 29 deletions
|
@ -405,7 +405,8 @@ impl<'a> PrivacyVisitor<'a> {
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
debug!("privacy - local {:?} not public all the way down", did);
|
debug!("privacy - local {} not public all the way down",
|
||||||
|
self.tcx.map.node_to_str(did.node));
|
||||||
// return quickly for things in the same module
|
// return quickly for things in the same module
|
||||||
if self.parents.find(&did.node) == self.parents.find(&self.curitem) {
|
if self.parents.find(&did.node) == self.parents.find(&self.curitem) {
|
||||||
debug!("privacy - same parent, we're done here");
|
debug!("privacy - same parent, we're done here");
|
||||||
|
@ -526,31 +527,60 @@ impl<'a> PrivacyVisitor<'a> {
|
||||||
/// If the result is `None`, no errors were found.
|
/// If the result is `None`, no errors were found.
|
||||||
fn ensure_public(&self, span: Span, to_check: ast::DefId,
|
fn ensure_public(&self, span: Span, to_check: ast::DefId,
|
||||||
source_did: Option<ast::DefId>, msg: &str) -> CheckResult {
|
source_did: Option<ast::DefId>, msg: &str) -> CheckResult {
|
||||||
match self.def_privacy(to_check) {
|
let id = match self.def_privacy(to_check) {
|
||||||
ExternallyDenied => Some((span, format!("{} is private", msg), None)),
|
ExternallyDenied => {
|
||||||
DisallowedBy(id) => {
|
return Some((span, format!("{} is private", msg), None))
|
||||||
let (err_span, err_msg) = if id == source_did.unwrap_or(to_check).node {
|
}
|
||||||
return Some((span, format!("{} is private", msg), None));
|
Allowable => return None,
|
||||||
} else {
|
DisallowedBy(id) => id,
|
||||||
(span, format!("{} is inaccessible", msg))
|
};
|
||||||
};
|
|
||||||
match self.tcx.map.find(id) {
|
// If we're disallowed by a particular id, then we attempt to give a
|
||||||
Some(ast_map::NodeItem(item)) => {
|
// nice error message to say why it was disallowed. It was either
|
||||||
let desc = match item.node {
|
// because the item itself is private or because its parent is private
|
||||||
ast::ItemMod(..) => "module",
|
// and its parent isn't in our ancestry.
|
||||||
ast::ItemTrait(..) => "trait",
|
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))
|
||||||
|
};
|
||||||
|
let item = match self.tcx.map.find(id) {
|
||||||
|
Some(ast_map::NodeItem(item)) => {
|
||||||
|
match item.node {
|
||||||
|
// If an impl disallowed this item, then this is resolve's
|
||||||
|
// way of saying that a struct/enum's static method was
|
||||||
|
// invoked, and the struct/enum itself is private. Crawl
|
||||||
|
// back up the chains to find the relevant struct/enum that
|
||||||
|
// was private.
|
||||||
|
ast::ItemImpl(_, _, ref ty, _) => {
|
||||||
|
let id = match ty.node {
|
||||||
|
ast::TyPath(_, _, id) => id,
|
||||||
_ => return Some((err_span, err_msg, None)),
|
_ => return Some((err_span, err_msg, None)),
|
||||||
};
|
};
|
||||||
let msg = format!("{} `{}` is private",
|
let def = self.tcx.def_map.borrow().get_copy(&id);
|
||||||
desc,
|
let did = def_id_of_def(def);
|
||||||
token::get_ident(item.ident));
|
assert!(is_local(did));
|
||||||
Some((err_span, err_msg, Some((span, msg))))
|
match self.tcx.map.get(did.node) {
|
||||||
},
|
ast_map::NodeItem(item) => item,
|
||||||
_ => Some((err_span, err_msg, None)),
|
_ => self.tcx.sess.span_bug(item.span,
|
||||||
|
"path is not an item")
|
||||||
|
}
|
||||||
|
}
|
||||||
|
_ => item
|
||||||
}
|
}
|
||||||
},
|
}
|
||||||
Allowable => None,
|
Some(..) | None => return Some((err_span, err_msg, None)),
|
||||||
}
|
};
|
||||||
|
let desc = match item.node {
|
||||||
|
ast::ItemMod(..) => "module",
|
||||||
|
ast::ItemTrait(..) => "trait",
|
||||||
|
ast::ItemStruct(..) => "struct",
|
||||||
|
ast::ItemEnum(..) => "enum",
|
||||||
|
_ => return Some((err_span, err_msg, None))
|
||||||
|
};
|
||||||
|
let msg = format!("{} `{}` is private", desc,
|
||||||
|
token::get_ident(item.ident));
|
||||||
|
Some((err_span, err_msg, Some((span, msg))))
|
||||||
}
|
}
|
||||||
|
|
||||||
// Checks that a field is in scope.
|
// Checks that a field is in scope.
|
||||||
|
@ -622,12 +652,8 @@ impl<'a> PrivacyVisitor<'a> {
|
||||||
.unwrap()
|
.unwrap()
|
||||||
.identifier);
|
.identifier);
|
||||||
let origdid = def_id_of_def(orig_def);
|
let origdid = def_id_of_def(orig_def);
|
||||||
self.ensure_public(span,
|
self.ensure_public(span, def, Some(origdid),
|
||||||
def,
|
format!("{} `{}`", tyname, name))
|
||||||
Some(origdid),
|
|
||||||
format!("{} `{}`",
|
|
||||||
tyname,
|
|
||||||
name))
|
|
||||||
};
|
};
|
||||||
|
|
||||||
match *self.last_private_map.get(&path_id) {
|
match *self.last_private_map.get(&path_id) {
|
||||||
|
|
25
src/test/compile-fail/issue-13641.rs
Normal file
25
src/test/compile-fail/issue-13641.rs
Normal file
|
@ -0,0 +1,25 @@
|
||||||
|
// 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.
|
||||||
|
|
||||||
|
mod a {
|
||||||
|
struct Foo;
|
||||||
|
impl Foo { pub fn new() {} }
|
||||||
|
enum Bar {}
|
||||||
|
impl Bar { pub fn new() {} }
|
||||||
|
}
|
||||||
|
|
||||||
|
fn main() {
|
||||||
|
a::Foo::new();
|
||||||
|
//~^ ERROR: static method `new` is inaccessible
|
||||||
|
//~^^ NOTE: struct `Foo` is private
|
||||||
|
a::Bar::new();
|
||||||
|
//~^ ERROR: static method `new` is inaccessible
|
||||||
|
//~^^ NOTE: enum `Bar` is private
|
||||||
|
}
|
Loading…
Add table
Add a link
Reference in a new issue