Skip to content

Commit 780d6cb

Browse files
committed
rustc_privacy: avoid using TypeckTables::empty for {Name,Type}PrivacyVisitor.
1 parent 883ece4 commit 780d6cb

File tree

1 file changed

+58
-98
lines changed

1 file changed

+58
-98
lines changed

src/librustc_privacy/lib.rs

+58-98
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,7 @@
22
#![feature(in_band_lifetimes)]
33
#![feature(nll)]
44
#![feature(or_patterns)]
5+
#![cfg_attr(bootstrap, feature(track_caller))]
56
#![recursion_limit = "256"]
67

78
use rustc_attr as attr;
@@ -345,17 +346,6 @@ fn def_id_visibility<'tcx>(
345346
}
346347
}
347348

348-
// Set the correct `TypeckTables` for the given `item_id` (or an empty table if
349-
// there is no `TypeckTables` for the item).
350-
fn item_tables<'a, 'tcx>(
351-
tcx: TyCtxt<'tcx>,
352-
hir_id: hir::HirId,
353-
empty_tables: &'a ty::TypeckTables<'tcx>,
354-
) -> &'a ty::TypeckTables<'tcx> {
355-
let def_id = tcx.hir().local_def_id(hir_id);
356-
if tcx.has_typeck_tables(def_id) { tcx.typeck_tables_of(def_id) } else { empty_tables }
357-
}
358-
359349
fn min(vis1: ty::Visibility, vis2: ty::Visibility, tcx: TyCtxt<'_>) -> ty::Visibility {
360350
if vis1.is_at_least(vis2, tcx) { vis2 } else { vis1 }
361351
}
@@ -1029,14 +1019,21 @@ impl DefIdVisitor<'tcx> for ReachEverythingInTheInterfaceVisitor<'_, 'tcx> {
10291019
/// This pass performs remaining checks for fields in struct expressions and patterns.
10301020
//////////////////////////////////////////////////////////////////////////////////////
10311021

1032-
struct NamePrivacyVisitor<'a, 'tcx> {
1022+
struct NamePrivacyVisitor<'tcx> {
10331023
tcx: TyCtxt<'tcx>,
1034-
tables: &'a ty::TypeckTables<'tcx>,
1024+
maybe_typeck_tables: Option<&'tcx ty::TypeckTables<'tcx>>,
10351025
current_item: Option<hir::HirId>,
1036-
empty_tables: &'a ty::TypeckTables<'tcx>,
10371026
}
10381027

1039-
impl<'a, 'tcx> NamePrivacyVisitor<'a, 'tcx> {
1028+
impl<'tcx> NamePrivacyVisitor<'tcx> {
1029+
/// Gets the type-checking side-tables for the current body.
1030+
/// As this will ICE if called outside bodies, only call when working with
1031+
/// `Expr` or `Pat` nodes (they are guaranteed to be found only in bodies).
1032+
#[track_caller]
1033+
fn tables(&self) -> &'tcx ty::TypeckTables<'tcx> {
1034+
self.maybe_typeck_tables.expect("`NamePrivacyVisitor::tables` called outside of body")
1035+
}
1036+
10401037
// Checks that a field in a struct constructor (expression or pattern) is accessible.
10411038
fn check_field(
10421039
&mut self,
@@ -1072,7 +1069,7 @@ impl<'a, 'tcx> NamePrivacyVisitor<'a, 'tcx> {
10721069
}
10731070
}
10741071

1075-
impl<'a, 'tcx> Visitor<'tcx> for NamePrivacyVisitor<'a, 'tcx> {
1072+
impl<'tcx> Visitor<'tcx> for NamePrivacyVisitor<'tcx> {
10761073
type Map = Map<'tcx>;
10771074

10781075
/// We want to visit items in the context of their containing
@@ -1087,39 +1084,22 @@ impl<'a, 'tcx> Visitor<'tcx> for NamePrivacyVisitor<'a, 'tcx> {
10871084
}
10881085

10891086
fn visit_nested_body(&mut self, body: hir::BodyId) {
1090-
let orig_tables = mem::replace(&mut self.tables, self.tcx.body_tables(body));
1087+
let old_maybe_typeck_tables = self.maybe_typeck_tables.replace(self.tcx.body_tables(body));
10911088
let body = self.tcx.hir().body(body);
10921089
self.visit_body(body);
1093-
self.tables = orig_tables;
1090+
self.maybe_typeck_tables = old_maybe_typeck_tables;
10941091
}
10951092

10961093
fn visit_item(&mut self, item: &'tcx hir::Item<'tcx>) {
1097-
let orig_current_item = mem::replace(&mut self.current_item, Some(item.hir_id));
1098-
let orig_tables =
1099-
mem::replace(&mut self.tables, item_tables(self.tcx, item.hir_id, self.empty_tables));
1094+
let orig_current_item = self.current_item.replace(item.hir_id);
11001095
intravisit::walk_item(self, item);
11011096
self.current_item = orig_current_item;
1102-
self.tables = orig_tables;
1103-
}
1104-
1105-
fn visit_trait_item(&mut self, ti: &'tcx hir::TraitItem<'tcx>) {
1106-
let orig_tables =
1107-
mem::replace(&mut self.tables, item_tables(self.tcx, ti.hir_id, self.empty_tables));
1108-
intravisit::walk_trait_item(self, ti);
1109-
self.tables = orig_tables;
1110-
}
1111-
1112-
fn visit_impl_item(&mut self, ii: &'tcx hir::ImplItem<'tcx>) {
1113-
let orig_tables =
1114-
mem::replace(&mut self.tables, item_tables(self.tcx, ii.hir_id, self.empty_tables));
1115-
intravisit::walk_impl_item(self, ii);
1116-
self.tables = orig_tables;
11171097
}
11181098

11191099
fn visit_expr(&mut self, expr: &'tcx hir::Expr<'tcx>) {
11201100
if let hir::ExprKind::Struct(ref qpath, fields, ref base) = expr.kind {
1121-
let res = self.tables.qpath_res(qpath, expr.hir_id);
1122-
let adt = self.tables.expr_ty(expr).ty_adt_def().unwrap();
1101+
let res = self.tables().qpath_res(qpath, expr.hir_id);
1102+
let adt = self.tables().expr_ty(expr).ty_adt_def().unwrap();
11231103
let variant = adt.variant_of_res(res);
11241104
if let Some(ref base) = *base {
11251105
// If the expression uses FRU we need to make sure all the unmentioned fields
@@ -1128,7 +1108,7 @@ impl<'a, 'tcx> Visitor<'tcx> for NamePrivacyVisitor<'a, 'tcx> {
11281108
for (vf_index, variant_field) in variant.fields.iter().enumerate() {
11291109
let field = fields
11301110
.iter()
1131-
.find(|f| self.tcx.field_index(f.hir_id, self.tables) == vf_index);
1111+
.find(|f| self.tcx.field_index(f.hir_id, self.tables()) == vf_index);
11321112
let (use_ctxt, span) = match field {
11331113
Some(field) => (field.ident.span, field.span),
11341114
None => (base.span, base.span),
@@ -1138,7 +1118,7 @@ impl<'a, 'tcx> Visitor<'tcx> for NamePrivacyVisitor<'a, 'tcx> {
11381118
} else {
11391119
for field in fields {
11401120
let use_ctxt = field.ident.span;
1141-
let index = self.tcx.field_index(field.hir_id, self.tables);
1121+
let index = self.tcx.field_index(field.hir_id, self.tables());
11421122
self.check_field(use_ctxt, field.span, adt, &variant.fields[index], false);
11431123
}
11441124
}
@@ -1149,12 +1129,12 @@ impl<'a, 'tcx> Visitor<'tcx> for NamePrivacyVisitor<'a, 'tcx> {
11491129

11501130
fn visit_pat(&mut self, pat: &'tcx hir::Pat<'tcx>) {
11511131
if let PatKind::Struct(ref qpath, fields, _) = pat.kind {
1152-
let res = self.tables.qpath_res(qpath, pat.hir_id);
1153-
let adt = self.tables.pat_ty(pat).ty_adt_def().unwrap();
1132+
let res = self.tables().qpath_res(qpath, pat.hir_id);
1133+
let adt = self.tables().pat_ty(pat).ty_adt_def().unwrap();
11541134
let variant = adt.variant_of_res(res);
11551135
for field in fields {
11561136
let use_ctxt = field.ident.span;
1157-
let index = self.tcx.field_index(field.hir_id, self.tables);
1137+
let index = self.tcx.field_index(field.hir_id, self.tables());
11581138
self.check_field(use_ctxt, field.span, adt, &variant.fields[index], false);
11591139
}
11601140
}
@@ -1169,16 +1149,22 @@ impl<'a, 'tcx> Visitor<'tcx> for NamePrivacyVisitor<'a, 'tcx> {
11691149
/// Checks are performed on "semantic" types regardless of names and their hygiene.
11701150
////////////////////////////////////////////////////////////////////////////////////////////
11711151

1172-
struct TypePrivacyVisitor<'a, 'tcx> {
1152+
struct TypePrivacyVisitor<'tcx> {
11731153
tcx: TyCtxt<'tcx>,
1174-
tables: &'a ty::TypeckTables<'tcx>,
1154+
maybe_typeck_tables: Option<&'tcx ty::TypeckTables<'tcx>>,
11751155
current_item: LocalDefId,
1176-
in_body: bool,
11771156
span: Span,
1178-
empty_tables: &'a ty::TypeckTables<'tcx>,
11791157
}
11801158

1181-
impl<'a, 'tcx> TypePrivacyVisitor<'a, 'tcx> {
1159+
impl<'tcx> TypePrivacyVisitor<'tcx> {
1160+
/// Gets the type-checking side-tables for the current body.
1161+
/// As this will ICE if called outside bodies, only call when working with
1162+
/// `Expr` or `Pat` nodes (they are guaranteed to be found only in bodies).
1163+
#[track_caller]
1164+
fn tables(&self) -> &'tcx ty::TypeckTables<'tcx> {
1165+
self.maybe_typeck_tables.expect("`TypePrivacyVisitor::tables` called outside of body")
1166+
}
1167+
11821168
fn item_is_accessible(&self, did: DefId) -> bool {
11831169
def_id_visibility(self.tcx, did)
11841170
.0
@@ -1188,10 +1174,11 @@ impl<'a, 'tcx> TypePrivacyVisitor<'a, 'tcx> {
11881174
// Take node-id of an expression or pattern and check its type for privacy.
11891175
fn check_expr_pat_type(&mut self, id: hir::HirId, span: Span) -> bool {
11901176
self.span = span;
1191-
if self.visit(self.tables.node_type(id)) || self.visit(self.tables.node_substs(id)) {
1177+
let tables = self.tables();
1178+
if self.visit(tables.node_type(id)) || self.visit(tables.node_substs(id)) {
11921179
return true;
11931180
}
1194-
if let Some(adjustments) = self.tables.adjustments().get(id) {
1181+
if let Some(adjustments) = tables.adjustments().get(id) {
11951182
for adjustment in adjustments {
11961183
if self.visit(adjustment.target) {
11971184
return true;
@@ -1214,7 +1201,7 @@ impl<'a, 'tcx> TypePrivacyVisitor<'a, 'tcx> {
12141201
}
12151202
}
12161203

1217-
impl<'a, 'tcx> Visitor<'tcx> for TypePrivacyVisitor<'a, 'tcx> {
1204+
impl<'tcx> Visitor<'tcx> for TypePrivacyVisitor<'tcx> {
12181205
type Map = Map<'tcx>;
12191206

12201207
/// We want to visit items in the context of their containing
@@ -1229,19 +1216,17 @@ impl<'a, 'tcx> Visitor<'tcx> for TypePrivacyVisitor<'a, 'tcx> {
12291216
}
12301217

12311218
fn visit_nested_body(&mut self, body: hir::BodyId) {
1232-
let orig_tables = mem::replace(&mut self.tables, self.tcx.body_tables(body));
1233-
let orig_in_body = mem::replace(&mut self.in_body, true);
1219+
let old_maybe_typeck_tables = self.maybe_typeck_tables.replace(self.tcx.body_tables(body));
12341220
let body = self.tcx.hir().body(body);
12351221
self.visit_body(body);
1236-
self.tables = orig_tables;
1237-
self.in_body = orig_in_body;
1222+
self.maybe_typeck_tables = old_maybe_typeck_tables;
12381223
}
12391224

12401225
fn visit_ty(&mut self, hir_ty: &'tcx hir::Ty<'tcx>) {
12411226
self.span = hir_ty.span;
1242-
if self.in_body {
1227+
if let Some(tables) = self.maybe_typeck_tables {
12431228
// Types in bodies.
1244-
if self.visit(self.tables.node_type(hir_ty.hir_id)) {
1229+
if self.visit(tables.node_type(hir_ty.hir_id)) {
12451230
return;
12461231
}
12471232
} else {
@@ -1258,7 +1243,7 @@ impl<'a, 'tcx> Visitor<'tcx> for TypePrivacyVisitor<'a, 'tcx> {
12581243

12591244
fn visit_trait_ref(&mut self, trait_ref: &'tcx hir::TraitRef<'tcx>) {
12601245
self.span = trait_ref.path.span;
1261-
if !self.in_body {
1246+
if self.maybe_typeck_tables.is_none() {
12621247
// Avoid calling `hir_trait_to_predicates` in bodies, it will ICE.
12631248
// The traits' privacy in bodies is already checked as a part of trait object types.
12641249
let bounds = rustc_typeck::hir_trait_to_predicates(
@@ -1304,7 +1289,7 @@ impl<'a, 'tcx> Visitor<'tcx> for TypePrivacyVisitor<'a, 'tcx> {
13041289
hir::ExprKind::MethodCall(_, span, _, _) => {
13051290
// Method calls have to be checked specially.
13061291
self.span = span;
1307-
if let Some(def_id) = self.tables.type_dependent_def_id(expr.hir_id) {
1292+
if let Some(def_id) = self.tables().type_dependent_def_id(expr.hir_id) {
13081293
if self.visit(self.tcx.type_of(def_id)) {
13091294
return;
13101295
}
@@ -1327,9 +1312,14 @@ impl<'a, 'tcx> Visitor<'tcx> for TypePrivacyVisitor<'a, 'tcx> {
13271312
// more code internal visibility at link time. (Access to private functions
13281313
// is already prohibited by type privacy for function types.)
13291314
fn visit_qpath(&mut self, qpath: &'tcx hir::QPath<'tcx>, id: hir::HirId, span: Span) {
1330-
let def = match self.tables.qpath_res(qpath, id) {
1331-
Res::Def(kind, def_id) => Some((kind, def_id)),
1332-
_ => None,
1315+
let def = match qpath {
1316+
hir::QPath::Resolved(_, path) => match path.res {
1317+
Res::Def(kind, def_id) => Some((kind, def_id)),
1318+
_ => None,
1319+
},
1320+
hir::QPath::TypeRelative(..) => {
1321+
self.maybe_typeck_tables.and_then(|tables| tables.type_dependent_def(id))
1322+
}
13331323
};
13341324
let def = def.filter(|(kind, _)| match kind {
13351325
DefKind::AssocFn | DefKind::AssocConst | DefKind::AssocTy | DefKind::Static => true,
@@ -1385,31 +1375,14 @@ impl<'a, 'tcx> Visitor<'tcx> for TypePrivacyVisitor<'a, 'tcx> {
13851375
fn visit_item(&mut self, item: &'tcx hir::Item<'tcx>) {
13861376
let orig_current_item =
13871377
mem::replace(&mut self.current_item, self.tcx.hir().local_def_id(item.hir_id));
1388-
let orig_in_body = mem::replace(&mut self.in_body, false);
1389-
let orig_tables =
1390-
mem::replace(&mut self.tables, item_tables(self.tcx, item.hir_id, self.empty_tables));
1378+
let old_maybe_typeck_tables = self.maybe_typeck_tables.take();
13911379
intravisit::walk_item(self, item);
1392-
self.tables = orig_tables;
1393-
self.in_body = orig_in_body;
1380+
self.maybe_typeck_tables = old_maybe_typeck_tables;
13941381
self.current_item = orig_current_item;
13951382
}
1396-
1397-
fn visit_trait_item(&mut self, ti: &'tcx hir::TraitItem<'tcx>) {
1398-
let orig_tables =
1399-
mem::replace(&mut self.tables, item_tables(self.tcx, ti.hir_id, self.empty_tables));
1400-
intravisit::walk_trait_item(self, ti);
1401-
self.tables = orig_tables;
1402-
}
1403-
1404-
fn visit_impl_item(&mut self, ii: &'tcx hir::ImplItem<'tcx>) {
1405-
let orig_tables =
1406-
mem::replace(&mut self.tables, item_tables(self.tcx, ii.hir_id, self.empty_tables));
1407-
intravisit::walk_impl_item(self, ii);
1408-
self.tables = orig_tables;
1409-
}
14101383
}
14111384

1412-
impl DefIdVisitor<'tcx> for TypePrivacyVisitor<'a, 'tcx> {
1385+
impl DefIdVisitor<'tcx> for TypePrivacyVisitor<'tcx> {
14131386
fn tcx(&self) -> TyCtxt<'tcx> {
14141387
self.tcx
14151388
}
@@ -2066,29 +2039,16 @@ pub fn provide(providers: &mut Providers<'_>) {
20662039
}
20672040

20682041
fn check_mod_privacy(tcx: TyCtxt<'_>, module_def_id: LocalDefId) {
2069-
let empty_tables = ty::TypeckTables::empty(None);
2070-
20712042
// Check privacy of names not checked in previous compilation stages.
2072-
let mut visitor = NamePrivacyVisitor {
2073-
tcx,
2074-
tables: &empty_tables,
2075-
current_item: None,
2076-
empty_tables: &empty_tables,
2077-
};
2043+
let mut visitor = NamePrivacyVisitor { tcx, maybe_typeck_tables: None, current_item: None };
20782044
let (module, span, hir_id) = tcx.hir().get_module(module_def_id);
20792045

20802046
intravisit::walk_mod(&mut visitor, module, hir_id);
20812047

20822048
// Check privacy of explicitly written types and traits as well as
20832049
// inferred types of expressions and patterns.
2084-
let mut visitor = TypePrivacyVisitor {
2085-
tcx,
2086-
tables: &empty_tables,
2087-
current_item: module_def_id,
2088-
in_body: false,
2089-
span,
2090-
empty_tables: &empty_tables,
2091-
};
2050+
let mut visitor =
2051+
TypePrivacyVisitor { tcx, maybe_typeck_tables: None, current_item: module_def_id, span };
20922052
intravisit::walk_mod(&mut visitor, module, hir_id);
20932053
}
20942054

0 commit comments

Comments
 (0)