Skip to content

Commit 7e7114f

Browse files
committed
Auto merge of #41332 - petrochenkov:privti, r=eddyb
Check privacy of trait items in all contexts Fixes #28514 This is a sufficiently rare scenario and it's currently guarded by `private_in_public` lint, so it shouldn't be a [breaking-change] in practice.
2 parents 2b4c911 + 4bd417e commit 7e7114f

File tree

10 files changed

+227
-248
lines changed

10 files changed

+227
-248
lines changed

src/librustc/ty/mod.rs

+11-14
Original file line numberDiff line numberDiff line change
@@ -2156,6 +2156,7 @@ impl<'a, 'gcx, 'tcx> TyCtxt<'a, 'gcx, 'tcx> {
21562156

21572157
fn associated_item_from_trait_item_ref(self,
21582158
parent_def_id: DefId,
2159+
parent_vis: &hir::Visibility,
21592160
trait_item_ref: &hir::TraitItemRef)
21602161
-> AssociatedItem {
21612162
let def_id = self.hir.local_def_id(trait_item_ref.id.node_id);
@@ -2170,7 +2171,8 @@ impl<'a, 'gcx, 'tcx> TyCtxt<'a, 'gcx, 'tcx> {
21702171
AssociatedItem {
21712172
name: trait_item_ref.name,
21722173
kind: kind,
2173-
vis: Visibility::from_hir(&hir::Inherited, trait_item_ref.id.node_id, self),
2174+
// Visibility of trait items is inherited from their traits.
2175+
vis: Visibility::from_hir(parent_vis, trait_item_ref.id.node_id, self),
21742176
defaultness: trait_item_ref.defaultness,
21752177
def_id: def_id,
21762178
container: TraitContainer(parent_def_id),
@@ -2180,7 +2182,6 @@ impl<'a, 'gcx, 'tcx> TyCtxt<'a, 'gcx, 'tcx> {
21802182

21812183
fn associated_item_from_impl_item_ref(self,
21822184
parent_def_id: DefId,
2183-
from_trait_impl: bool,
21842185
impl_item_ref: &hir::ImplItemRef)
21852186
-> AssociatedItem {
21862187
let def_id = self.hir.local_def_id(impl_item_ref.id.node_id);
@@ -2192,14 +2193,11 @@ impl<'a, 'gcx, 'tcx> TyCtxt<'a, 'gcx, 'tcx> {
21922193
hir::AssociatedItemKind::Type => (ty::AssociatedKind::Type, false),
21932194
};
21942195

2195-
// Trait impl items are always public.
2196-
let public = hir::Public;
2197-
let vis = if from_trait_impl { &public } else { &impl_item_ref.vis };
2198-
21992196
ty::AssociatedItem {
22002197
name: impl_item_ref.name,
22012198
kind: kind,
2202-
vis: ty::Visibility::from_hir(vis, impl_item_ref.id.node_id, self),
2199+
// Visibility of trait impl items doesn't matter.
2200+
vis: ty::Visibility::from_hir(&impl_item_ref.vis, impl_item_ref.id.node_id, self),
22032201
defaultness: impl_item_ref.defaultness,
22042202
def_id: def_id,
22052203
container: ImplContainer(parent_def_id),
@@ -2639,21 +2637,20 @@ fn associated_item<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>, def_id: DefId)
26392637
let parent_def_id = tcx.hir.local_def_id(parent_id);
26402638
let parent_item = tcx.hir.expect_item(parent_id);
26412639
match parent_item.node {
2642-
hir::ItemImpl(.., ref impl_trait_ref, _, ref impl_item_refs) => {
2640+
hir::ItemImpl(.., ref impl_item_refs) => {
26432641
if let Some(impl_item_ref) = impl_item_refs.iter().find(|i| i.id.node_id == id) {
2644-
let assoc_item =
2645-
tcx.associated_item_from_impl_item_ref(parent_def_id,
2646-
impl_trait_ref.is_some(),
2647-
impl_item_ref);
2642+
let assoc_item = tcx.associated_item_from_impl_item_ref(parent_def_id,
2643+
impl_item_ref);
26482644
debug_assert_eq!(assoc_item.def_id, def_id);
26492645
return assoc_item;
26502646
}
26512647
}
26522648

26532649
hir::ItemTrait(.., ref trait_item_refs) => {
26542650
if let Some(trait_item_ref) = trait_item_refs.iter().find(|i| i.id.node_id == id) {
2655-
let assoc_item =
2656-
tcx.associated_item_from_trait_item_ref(parent_def_id, trait_item_ref);
2651+
let assoc_item = tcx.associated_item_from_trait_item_ref(parent_def_id,
2652+
&parent_item.vis,
2653+
trait_item_ref);
26572654
debug_assert_eq!(assoc_item.def_id, def_id);
26582655
return assoc_item;
26592656
}

src/librustc_privacy/lib.rs

+38-97
Original file line numberDiff line numberDiff line change
@@ -13,8 +13,8 @@
1313
#![crate_type = "dylib"]
1414
#![crate_type = "rlib"]
1515
#![doc(html_logo_url = "https://www.rust-lang.org/logos/rust-logo-128x128-blk-v2.png",
16-
html_favicon_url = "https://doc.rust-lang.org/favicon.ico",
17-
html_root_url = "https://doc.rust-lang.org/nightly/")]
16+
html_favicon_url = "https://doc.rust-lang.org/favicon.ico",
17+
html_root_url = "https://doc.rust-lang.org/nightly/")]
1818
#![deny(warnings)]
1919

2020
#![feature(rustc_diagnostic_macros)]
@@ -30,7 +30,6 @@ use rustc::hir::def::Def;
3030
use rustc::hir::def_id::{CRATE_DEF_INDEX, LOCAL_CRATE, CrateNum, DefId};
3131
use rustc::hir::intravisit::{self, Visitor, NestedVisitorMap};
3232
use rustc::hir::itemlikevisit::DeepVisitor;
33-
use rustc::hir::pat_util::EnumerateAndAdjustIterator;
3433
use rustc::lint;
3534
use rustc::middle::privacy::{AccessLevel, AccessLevels};
3635
use rustc::ty::{self, TyCtxt, Ty, TypeFoldable};
@@ -415,97 +414,69 @@ impl<'b, 'a, 'tcx> TypeVisitor<'tcx> for ReachEverythingInTheInterfaceVisitor<'b
415414
}
416415
}
417416

418-
////////////////////////////////////////////////////////////////////////////////
419-
/// The privacy visitor, where privacy checks take place (violations reported)
420-
////////////////////////////////////////////////////////////////////////////////
417+
//////////////////////////////////////////////////////////////////////////////////////
418+
/// Name privacy visitor, checks privacy and reports violations.
419+
/// Most of name privacy checks are performed during the main resolution phase,
420+
/// or later in type checking when field accesses and associated items are resolved.
421+
/// This pass performs remaining checks for fields in struct expressions and patterns.
422+
//////////////////////////////////////////////////////////////////////////////////////
421423

422-
struct PrivacyVisitor<'a, 'tcx: 'a> {
424+
struct NamePrivacyVisitor<'a, 'tcx: 'a> {
423425
tcx: TyCtxt<'a, 'tcx, 'tcx>,
424-
curitem: DefId,
425-
in_foreign: bool,
426426
tables: &'a ty::TypeckTables<'tcx>,
427+
current_item: DefId,
427428
}
428429

429-
impl<'a, 'tcx> PrivacyVisitor<'a, 'tcx> {
430-
fn item_is_accessible(&self, did: DefId) -> bool {
431-
match self.tcx.hir.as_local_node_id(did) {
432-
Some(node_id) =>
433-
ty::Visibility::from_hir(&self.tcx.hir.expect_item(node_id).vis, node_id, self.tcx),
434-
None => self.tcx.sess.cstore.visibility(did),
435-
}.is_accessible_from(self.curitem, self.tcx)
436-
}
437-
438-
// Checks that a field is in scope.
430+
impl<'a, 'tcx> NamePrivacyVisitor<'a, 'tcx> {
431+
// Checks that a field is accessible.
439432
fn check_field(&mut self, span: Span, def: &'tcx ty::AdtDef, field: &'tcx ty::FieldDef) {
440-
if !def.is_enum() && !field.vis.is_accessible_from(self.curitem, self.tcx) {
433+
if !def.is_enum() && !field.vis.is_accessible_from(self.current_item, self.tcx) {
441434
struct_span_err!(self.tcx.sess, span, E0451, "field `{}` of {} `{}` is private",
442-
field.name, def.variant_descr(), self.tcx.item_path_str(def.did))
435+
field.name, def.variant_descr(), self.tcx.item_path_str(def.did))
443436
.span_label(span, &format!("field `{}` is private", field.name))
444437
.emit();
445438
}
446439
}
447-
448-
// Checks that a method is in scope.
449-
fn check_method(&mut self, span: Span, method_def_id: DefId) {
450-
match self.tcx.associated_item(method_def_id).container {
451-
// Trait methods are always all public. The only controlling factor
452-
// is whether the trait itself is accessible or not.
453-
ty::TraitContainer(trait_def_id) if !self.item_is_accessible(trait_def_id) => {
454-
let msg = format!("source trait `{}` is private",
455-
self.tcx.item_path_str(trait_def_id));
456-
self.tcx.sess.span_err(span, &msg);
457-
}
458-
_ => {}
459-
}
460-
}
461440
}
462441

463-
impl<'a, 'tcx> Visitor<'tcx> for PrivacyVisitor<'a, 'tcx> {
442+
impl<'a, 'tcx> Visitor<'tcx> for NamePrivacyVisitor<'a, 'tcx> {
464443
/// We want to visit items in the context of their containing
465444
/// module and so forth, so supply a crate for doing a deep walk.
466445
fn nested_visit_map<'this>(&'this mut self) -> NestedVisitorMap<'this, 'tcx> {
467446
NestedVisitorMap::All(&self.tcx.hir)
468447
}
469448

470449
fn visit_nested_body(&mut self, body: hir::BodyId) {
471-
let old_tables = self.tables;
472-
self.tables = self.tcx.body_tables(body);
450+
let orig_tables = replace(&mut self.tables, self.tcx.body_tables(body));
473451
let body = self.tcx.hir.body(body);
474452
self.visit_body(body);
475-
self.tables = old_tables;
453+
self.tables = orig_tables;
476454
}
477455

478456
fn visit_item(&mut self, item: &'tcx hir::Item) {
479-
let orig_curitem = replace(&mut self.curitem, self.tcx.hir.local_def_id(item.id));
457+
let orig_current_item = replace(&mut self.current_item, self.tcx.hir.local_def_id(item.id));
480458
intravisit::walk_item(self, item);
481-
self.curitem = orig_curitem;
459+
self.current_item = orig_current_item;
482460
}
483461

484462
fn visit_expr(&mut self, expr: &'tcx hir::Expr) {
485463
match expr.node {
486-
hir::ExprMethodCall(..) => {
487-
let method_call = ty::MethodCall::expr(expr.id);
488-
let method = self.tables.method_map[&method_call];
489-
self.check_method(expr.span, method.def_id);
490-
}
491-
hir::ExprStruct(ref qpath, ref expr_fields, _) => {
464+
hir::ExprStruct(ref qpath, ref fields, ref base) => {
492465
let def = self.tables.qpath_def(qpath, expr.id);
493466
let adt = self.tables.expr_ty(expr).ty_adt_def().unwrap();
494467
let variant = adt.variant_of_def(def);
495-
// RFC 736: ensure all unmentioned fields are visible.
496-
// Rather than computing the set of unmentioned fields
497-
// (i.e. `all_fields - fields`), just check them all,
498-
// unless the ADT is a union, then unmentioned fields
499-
// are not checked.
500-
if adt.is_union() {
501-
for expr_field in expr_fields {
502-
self.check_field(expr.span, adt, variant.field_named(expr_field.name.node));
468+
if let Some(ref base) = *base {
469+
// If the expression uses FRU we need to make sure all the unmentioned fields
470+
// are checked for privacy (RFC 736). Rather than computing the set of
471+
// unmentioned fields, just check them all.
472+
for variant_field in &variant.fields {
473+
let field = fields.iter().find(|f| f.name.node == variant_field.name);
474+
let span = if let Some(f) = field { f.span } else { base.span };
475+
self.check_field(span, adt, variant_field);
503476
}
504477
} else {
505-
for field in &variant.fields {
506-
let expr_field = expr_fields.iter().find(|f| f.name.node == field.name);
507-
let span = if let Some(f) = expr_field { f.span } else { expr.span };
508-
self.check_field(span, adt, field);
478+
for field in fields {
479+
self.check_field(field.span, adt, variant.field_named(field.name.node));
509480
}
510481
}
511482
}
@@ -515,47 +486,20 @@ impl<'a, 'tcx> Visitor<'tcx> for PrivacyVisitor<'a, 'tcx> {
515486
intravisit::walk_expr(self, expr);
516487
}
517488

518-
fn visit_pat(&mut self, pattern: &'tcx hir::Pat) {
519-
// Foreign functions do not have their patterns mapped in the def_map,
520-
// and there's nothing really relevant there anyway, so don't bother
521-
// checking privacy. If you can name the type then you can pass it to an
522-
// external C function anyway.
523-
if self.in_foreign { return }
524-
525-
match pattern.node {
489+
fn visit_pat(&mut self, pat: &'tcx hir::Pat) {
490+
match pat.node {
526491
PatKind::Struct(ref qpath, ref fields, _) => {
527-
let def = self.tables.qpath_def(qpath, pattern.id);
528-
let adt = self.tables.pat_ty(pattern).ty_adt_def().unwrap();
492+
let def = self.tables.qpath_def(qpath, pat.id);
493+
let adt = self.tables.pat_ty(pat).ty_adt_def().unwrap();
529494
let variant = adt.variant_of_def(def);
530495
for field in fields {
531496
self.check_field(field.span, adt, variant.field_named(field.node.name));
532497
}
533498
}
534-
PatKind::TupleStruct(_, ref fields, ddpos) => {
535-
match self.tables.pat_ty(pattern).sty {
536-
// enum fields have no privacy at this time
537-
ty::TyAdt(def, _) if !def.is_enum() => {
538-
let expected_len = def.struct_variant().fields.len();
539-
for (i, field) in fields.iter().enumerate_and_adjust(expected_len, ddpos) {
540-
if let PatKind::Wild = field.node {
541-
continue
542-
}
543-
self.check_field(field.span, def, &def.struct_variant().fields[i]);
544-
}
545-
}
546-
_ => {}
547-
}
548-
}
549499
_ => {}
550500
}
551501

552-
intravisit::walk_pat(self, pattern);
553-
}
554-
555-
fn visit_foreign_item(&mut self, fi: &'tcx hir::ForeignItem) {
556-
self.in_foreign = true;
557-
intravisit::walk_foreign_item(self, fi);
558-
self.in_foreign = false;
502+
intravisit::walk_pat(self, pat);
559503
}
560504
}
561505

@@ -1233,17 +1177,14 @@ fn privacy_access_levels<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>,
12331177

12341178
let krate = tcx.hir.krate();
12351179

1236-
// Use the parent map to check the privacy of everything
1237-
let mut visitor = PrivacyVisitor {
1238-
curitem: DefId::local(CRATE_DEF_INDEX),
1239-
in_foreign: false,
1180+
// Check privacy of names not checked in previous compilation stages.
1181+
let mut visitor = NamePrivacyVisitor {
12401182
tcx: tcx,
12411183
tables: &ty::TypeckTables::empty(),
1184+
current_item: DefId::local(CRATE_DEF_INDEX),
12421185
};
12431186
intravisit::walk_crate(&mut visitor, krate);
12441187

1245-
tcx.sess.abort_if_errors();
1246-
12471188
// Build up a set of all exported items in the AST. This is a set of all
12481189
// items which are reachable from external crates based on visibility.
12491190
let mut visitor = EmbargoVisitor {

src/librustc_typeck/astconv.rs

+10-4
Original file line numberDiff line numberDiff line change
@@ -903,10 +903,16 @@ impl<'o, 'gcx: 'tcx, 'tcx> AstConv<'gcx, 'tcx>+'o {
903903
let ty = self.projected_ty_from_poly_trait_ref(span, bound, assoc_name);
904904
let ty = self.normalize_ty(span, ty);
905905

906-
let item = tcx.associated_items(trait_did).find(|i| i.name == assoc_name);
907-
let def_id = item.expect("missing associated type").def_id;
908-
tcx.check_stability(def_id, ref_id, span);
909-
(ty, Def::AssociatedTy(def_id))
906+
let item = tcx.associated_items(trait_did).find(|i| i.name == assoc_name)
907+
.expect("missing associated type");
908+
let def = Def::AssociatedTy(item.def_id);
909+
if !tcx.vis_is_accessible_from(item.vis, ref_id) {
910+
let msg = format!("{} `{}` is private", def.kind_name(), assoc_name);
911+
tcx.sess.span_err(span, &msg);
912+
}
913+
tcx.check_stability(item.def_id, ref_id, span);
914+
915+
(ty, def)
910916
}
911917

912918
fn qpath_to_ty(&self,

src/librustc_typeck/check/method/mod.rs

-7
Original file line numberDiff line numberDiff line change
@@ -349,15 +349,8 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> {
349349
}
350350

351351
let def = pick.item.def();
352-
353352
self.tcx.check_stability(def.def_id(), expr_id, span);
354353

355-
if let probe::InherentImplPick = pick.kind {
356-
if !self.tcx.vis_is_accessible_from(pick.item.vis, self.body_id) {
357-
let msg = format!("{} `{}` is private", def.kind_name(), method_name);
358-
self.tcx.sess.span_err(span, &msg);
359-
}
360-
}
361354
Ok(def)
362355
}
363356

0 commit comments

Comments
 (0)