// Do not remove on snapshot creation. Needed for bootstrap. (Issue #22364)
#![cfg_attr(stage0, feature(custom_attribute))]
#![crate_name = "rustc_privacy"]
-#![unstable(feature = "rustc_private")]
+#![unstable(feature = "rustc_private", issue = "27812")]
#![staged_api]
#![crate_type = "dylib"]
#![crate_type = "rlib"]
-#![doc(html_logo_url = "http://www.rust-lang.org/logos/rust-logo-128x128-blk-v2.png",
+#![doc(html_logo_url = "https://www.rust-lang.org/logos/rust-logo-128x128-blk-v2.png",
html_favicon_url = "https://doc.rust-lang.org/favicon.ico",
- html_root_url = "http://doc.rust-lang.org/nightly/")]
+ html_root_url = "https://doc.rust-lang.org/nightly/")]
#![feature(rustc_diagnostic_macros)]
#![feature(rustc_private)]
use std::mem::replace;
use rustc::ast_map;
-use rustc::metadata::csearch;
use rustc::middle::def;
+use rustc::middle::def_id::DefId;
use rustc::middle::privacy::ImportUse::*;
use rustc::middle::privacy::LastPrivate::*;
use rustc::middle::privacy::PrivateDep::*;
use rustc::util::nodemap::{NodeMap, NodeSet};
use syntax::ast;
-use syntax::ast_util::{is_local, local_def};
use syntax::codemap::Span;
use syntax::visit::{self, Visitor};
def::DefPrimTy(..) => true,
def => {
let did = def.def_id();
- !is_local(did) ||
+ !did.is_local() ||
self.exported_items.contains(&did.node)
}
}
}
_ => true,
};
- let tr = self.tcx.impl_trait_ref(local_def(item.id));
+ let tr = self.tcx.impl_trait_ref(DefId::local(item.id));
let public_trait = tr.clone().map_or(false, |tr| {
- !is_local(tr.def_id) ||
+ !tr.def_id.is_local() ||
self.exported_items.contains(&tr.def_id.node)
});
def::DefPrimTy(..) | def::DefTyParam(..) => {},
def => {
let did = def.def_id();
- if is_local(did) {
+ if did.is_local() {
self.exported_items.insert(did.node);
}
}
if self.prev_exported {
assert!(self.export_map.contains_key(&id), "wut {}", id);
for export in self.export_map.get(&id).unwrap() {
- if is_local(export.def_id) {
+ if export.def_id.is_local() {
self.reexports.insert(export.def_id.node);
}
}
// Determines whether the given definition is public from the point of view
// of the current item.
- fn def_privacy(&self, did: ast::DefId) -> PrivacyResult {
- if !is_local(did) {
+ fn def_privacy(&self, did: DefId) -> PrivacyResult {
+ if !did.is_local() {
if self.external_exports.contains(&did) {
debug!("privacy - {:?} was externally exported", did);
return Allowable;
/// Guarantee that a particular definition is public. Returns a CheckResult
/// which contains any errors found. These can be reported using `report_error`.
/// If the result is `None`, no errors were found.
- fn ensure_public(&self, span: Span, to_check: ast::DefId,
- source_did: Option<ast::DefId>, msg: &str) -> CheckResult {
+ fn ensure_public(&self, span: Span, to_check: DefId,
+ source_did: Option<DefId>, msg: &str) -> CheckResult {
let id = match self.def_privacy(to_check) {
ExternallyDenied => {
return Some((span, format!("{} is private", msg), None))
};
let def = self.tcx.def_map.borrow().get(&ty.id).unwrap().full_def();
let did = def.def_id();
- assert!(is_local(did));
+ assert!(did.is_local());
match self.tcx.map.get(did.node) {
ast_map::NodeItem(item) => item,
_ => self.tcx.sess.span_bug(item.span,
// Checks that a field is in scope.
fn check_field(&mut self,
span: Span,
- id: ast::DefId,
+ def: ty::AdtDef<'tcx>,
+ v: ty::VariantDef<'tcx>,
name: FieldName) {
- let fields = self.tcx.lookup_struct_fields(id);
let field = match name {
NamedField(f_name) => {
- debug!("privacy - check named field {} in struct {:?}", f_name, id);
- fields.iter().find(|f| f.name == f_name).unwrap()
+ debug!("privacy - check named field {} in struct {:?}", f_name, def);
+ v.field_named(f_name)
}
- UnnamedField(idx) => &fields[idx]
+ UnnamedField(idx) => &v.fields[idx]
};
if field.vis == ast::Public ||
- (is_local(field.id) && self.private_accessible(field.id.node)) {
+ (field.did.is_local() && self.private_accessible(field.did.node)) {
return
}
- let struct_type = self.tcx.lookup_item_type(id).ty;
- let struct_desc = match struct_type.sty {
- ty::TyStruct(_, _) =>
- format!("struct `{}`", self.tcx.item_path_str(id)),
+ let struct_desc = match def.adt_kind() {
+ ty::AdtKind::Struct =>
+ format!("struct `{}`", self.tcx.item_path_str(def.did)),
// struct variant fields have inherited visibility
- ty::TyEnum(..) => return,
- _ => self.tcx.sess.span_bug(span, "can't find struct for field")
+ ty::AdtKind::Enum => return
};
let msg = match name {
NamedField(name) => format!("field `{}` of {} is private",
// Given the ID of a method, checks to ensure it's in scope.
fn check_static_method(&mut self,
span: Span,
- method_id: ast::DefId,
+ method_id: DefId,
name: ast::Name) {
// If the method is a default method, we need to use the def_id of
// the default implementation.
debug!("privacy - path {}", self.nodestr(path_id));
let path_res = *self.tcx.def_map.borrow().get(&path_id).unwrap();
let ck = |tyname: &str| {
- let ck_public = |def: ast::DefId| {
+ let ck_public = |def: DefId| {
debug!("privacy - ck_public {:?}", def);
let origdid = path_res.def_id();
self.ensure_public(span,
}
// Checks that a method is in scope.
- fn check_method(&mut self, span: Span, method_def_id: ast::DefId,
+ fn check_method(&mut self, span: Span, method_def_id: DefId,
name: ast::Name) {
match self.tcx.impl_or_trait_item(method_def_id).container() {
ty::ImplContainer(_) => {
if let ast::ViewPathList(ref prefix, ref list) = vpath.node {
for pid in list {
match pid.node {
- ast::PathListIdent { id, name } => {
+ ast::PathListIdent { id, name, .. } => {
debug!("privacy - ident item {}", id);
self.check_path(pid.span, id, name.name);
}
- ast::PathListMod { id } => {
+ ast::PathListMod { id, .. } => {
debug!("privacy - mod item {}", id);
let name = prefix.segments.last().unwrap().identifier.name;
self.check_path(pid.span, id, name);
fn visit_expr(&mut self, expr: &ast::Expr) {
match expr.node {
ast::ExprField(ref base, ident) => {
- if let ty::TyStruct(id, _) = self.tcx.expr_ty_adjusted(&**base).sty {
- self.check_field(expr.span, id, NamedField(ident.node.name));
+ if let ty::TyStruct(def, _) = self.tcx.expr_ty_adjusted(&**base).sty {
+ self.check_field(expr.span,
+ def,
+ def.struct_variant(),
+ NamedField(ident.node.name));
}
}
ast::ExprTupField(ref base, idx) => {
- if let ty::TyStruct(id, _) = self.tcx.expr_ty_adjusted(&**base).sty {
- self.check_field(expr.span, id, UnnamedField(idx.node));
+ if let ty::TyStruct(def, _) = self.tcx.expr_ty_adjusted(&**base).sty {
+ self.check_field(expr.span,
+ def,
+ def.struct_variant(),
+ UnnamedField(idx.node));
}
}
ast::ExprMethodCall(ident, _, _) => {
debug!("(privacy checking) checking impl method");
self.check_method(expr.span, method.def_id, ident.node.name);
}
- ast::ExprStruct(_, ref fields, _) => {
- match self.tcx.expr_ty(expr).sty {
- ty::TyStruct(ctor_id, _) => {
- // RFC 736: ensure all unmentioned fields are visible.
- // Rather than computing the set of unmentioned fields
- // (i.e. `all_fields - fields`), just check them all.
- let all_fields = self.tcx.lookup_struct_fields(ctor_id);
- for field in all_fields {
- self.check_field(expr.span, ctor_id,
- NamedField(field.name));
- }
- }
- ty::TyEnum(_, _) => {
- match self.tcx.def_map.borrow().get(&expr.id).unwrap().full_def() {
- def::DefVariant(_, variant_id, _) => {
- for field in fields {
- self.check_field(expr.span, variant_id,
- NamedField(field.ident.node.name));
- }
- }
- _ => self.tcx.sess.span_bug(expr.span,
- "resolve didn't \
- map enum struct \
- constructor to a \
- variant def"),
- }
- }
- _ => self.tcx.sess.span_bug(expr.span, "struct expr \
- didn't have \
- struct type?!"),
+ ast::ExprStruct(..) => {
+ let adt = self.tcx.expr_ty(expr).ty_adt_def().unwrap();
+ let variant = adt.variant_of_def(self.tcx.resolve_expr(expr));
+ // RFC 736: ensure all unmentioned fields are visible.
+ // Rather than computing the set of unmentioned fields
+ // (i.e. `all_fields - fields`), just check them all.
+ for field in &variant.fields {
+ self.check_field(expr.span, adt, variant, NamedField(field.name));
}
}
ast::ExprPath(..) => {
- let guard = |did: ast::DefId| {
- let fields = self.tcx.lookup_struct_fields(did);
- let any_priv = fields.iter().any(|f| {
+
+ if let def::DefStruct(_) = self.tcx.resolve_expr(expr) {
+ let expr_ty = self.tcx.expr_ty(expr);
+ let def = match expr_ty.sty {
+ ty::TyBareFn(_, &ty::BareFnTy { sig: ty::Binder(ty::FnSig {
+ output: ty::FnConverging(ty), ..
+ }), ..}) => ty,
+ _ => expr_ty
+ }.ty_adt_def().unwrap();
+ let any_priv = def.struct_variant().fields.iter().any(|f| {
f.vis != ast::Public && (
- !is_local(f.id) ||
- !self.private_accessible(f.id.node))
- });
+ !f.did.is_local() ||
+ !self.private_accessible(f.did.node))
+ });
if any_priv {
self.tcx.sess.span_err(expr.span,
- "cannot invoke tuple struct constructor \
- with private fields");
- }
- };
- match self.tcx.def_map.borrow().get(&expr.id).map(|d| d.full_def()) {
- Some(def::DefStruct(did)) => {
- guard(if is_local(did) {
- local_def(self.tcx.map.get_parent(did.node))
- } else {
- // "tuple structs" with zero fields (such as
- // `pub struct Foo;`) don't have a ctor_id, hence
- // the unwrap_or to the same struct id.
- let maybe_did =
- csearch::get_tuple_struct_definition_if_ctor(
- &self.tcx.sess.cstore, did);
- maybe_did.unwrap_or(did)
- })
+ "cannot invoke tuple struct constructor \
+ with private fields");
}
- _ => {}
}
}
_ => {}
match pattern.node {
ast::PatStruct(_, ref fields, _) => {
- match self.tcx.pat_ty(pattern).sty {
- ty::TyStruct(id, _) => {
- for field in fields {
- self.check_field(pattern.span, id,
- NamedField(field.node.ident.name));
- }
- }
- ty::TyEnum(_, _) => {
- match self.tcx.def_map.borrow().get(&pattern.id).map(|d| d.full_def()) {
- Some(def::DefVariant(_, variant_id, _)) => {
- for field in fields {
- self.check_field(pattern.span, variant_id,
- NamedField(field.node.ident.name));
- }
- }
- _ => self.tcx.sess.span_bug(pattern.span,
- "resolve didn't \
- map enum struct \
- pattern to a \
- variant def"),
- }
- }
- _ => self.tcx.sess.span_bug(pattern.span,
- "struct pattern didn't have \
- struct type?!"),
+ let adt = self.tcx.pat_ty(pattern).ty_adt_def().unwrap();
+ let def = self.tcx.def_map.borrow().get(&pattern.id).unwrap().full_def();
+ let variant = adt.variant_of_def(def);
+ for field in fields {
+ self.check_field(pattern.span, adt, variant,
+ NamedField(field.node.ident.name));
}
}
// elsewhere).
ast::PatEnum(_, Some(ref fields)) => {
match self.tcx.pat_ty(pattern).sty {
- ty::TyStruct(id, _) => {
+ ty::TyStruct(def, _) => {
for (i, field) in fields.iter().enumerate() {
if let ast::PatWild(..) = field.node {
continue
}
- self.check_field(field.span, id, UnnamedField(i));
+ self.check_field(field.span,
+ def,
+ def.struct_variant(),
+ UnnamedField(i));
}
}
ty::TyEnum(..) => {
};
// A path can only be private if:
// it's in this crate...
- if !is_local(did) {
+ if !did.is_local() {
return false
}
|tr| {
let did = self.tcx.trait_ref_to_def_id(tr);
- !is_local(did) || self.trait_is_public(did.node)
+ !did.is_local() || self.trait_is_public(did.node)
});
// `true` iff this is a trait impl or at least one method is public.