about summary refs log tree commit diff
path: root/src
diff options
context:
space:
mode:
authorEduard-Mihai Burtescu <edy.burt@gmail.com>2020-06-25 22:23:41 +0300
committerEduard-Mihai Burtescu <edy.burt@gmail.com>2020-07-02 16:49:41 +0300
commit780d6cb1408717f968a21d627cc34c8ffa7f6fe8 (patch)
tree7fb840e65368edb4e2ccc7856d786068b96a31e5 /src
parent883ece499fef22b4703f5b04133bb2beff08c794 (diff)
downloadrust-780d6cb1408717f968a21d627cc34c8ffa7f6fe8.tar.gz
rust-780d6cb1408717f968a21d627cc34c8ffa7f6fe8.zip
rustc_privacy: avoid using TypeckTables::empty for {Name,Type}PrivacyVisitor.
Diffstat (limited to 'src')
-rw-r--r--src/librustc_privacy/lib.rs156
1 files changed, 58 insertions, 98 deletions
diff --git a/src/librustc_privacy/lib.rs b/src/librustc_privacy/lib.rs
index 20f09ef52f0..de21365c536 100644
--- a/src/librustc_privacy/lib.rs
+++ b/src/librustc_privacy/lib.rs
@@ -2,6 +2,7 @@
 #![feature(in_band_lifetimes)]
 #![feature(nll)]
 #![feature(or_patterns)]
+#![cfg_attr(bootstrap, feature(track_caller))]
 #![recursion_limit = "256"]
 
 use rustc_attr as attr;
@@ -345,17 +346,6 @@ fn def_id_visibility<'tcx>(
     }
 }
 
-// Set the correct `TypeckTables` for the given `item_id` (or an empty table if
-// there is no `TypeckTables` for the item).
-fn item_tables<'a, 'tcx>(
-    tcx: TyCtxt<'tcx>,
-    hir_id: hir::HirId,
-    empty_tables: &'a ty::TypeckTables<'tcx>,
-) -> &'a ty::TypeckTables<'tcx> {
-    let def_id = tcx.hir().local_def_id(hir_id);
-    if tcx.has_typeck_tables(def_id) { tcx.typeck_tables_of(def_id) } else { empty_tables }
-}
-
 fn min(vis1: ty::Visibility, vis2: ty::Visibility, tcx: TyCtxt<'_>) -> ty::Visibility {
     if vis1.is_at_least(vis2, tcx) { vis2 } else { vis1 }
 }
@@ -1029,14 +1019,21 @@ impl DefIdVisitor<'tcx> for ReachEverythingInTheInterfaceVisitor<'_, 'tcx> {
 /// This pass performs remaining checks for fields in struct expressions and patterns.
 //////////////////////////////////////////////////////////////////////////////////////
 
-struct NamePrivacyVisitor<'a, 'tcx> {
+struct NamePrivacyVisitor<'tcx> {
     tcx: TyCtxt<'tcx>,
-    tables: &'a ty::TypeckTables<'tcx>,
+    maybe_typeck_tables: Option<&'tcx ty::TypeckTables<'tcx>>,
     current_item: Option<hir::HirId>,
-    empty_tables: &'a ty::TypeckTables<'tcx>,
 }
 
-impl<'a, 'tcx> NamePrivacyVisitor<'a, 'tcx> {
+impl<'tcx> NamePrivacyVisitor<'tcx> {
+    /// Gets the type-checking side-tables for the current body.
+    /// As this will ICE if called outside bodies, only call when working with
+    /// `Expr` or `Pat` nodes (they are guaranteed to be found only in bodies).
+    #[track_caller]
+    fn tables(&self) -> &'tcx ty::TypeckTables<'tcx> {
+        self.maybe_typeck_tables.expect("`NamePrivacyVisitor::tables` called outside of body")
+    }
+
     // Checks that a field in a struct constructor (expression or pattern) is accessible.
     fn check_field(
         &mut self,
@@ -1072,7 +1069,7 @@ impl<'a, 'tcx> NamePrivacyVisitor<'a, 'tcx> {
     }
 }
 
-impl<'a, 'tcx> Visitor<'tcx> for NamePrivacyVisitor<'a, 'tcx> {
+impl<'tcx> Visitor<'tcx> for NamePrivacyVisitor<'tcx> {
     type Map = Map<'tcx>;
 
     /// We want to visit items in the context of their containing
@@ -1087,39 +1084,22 @@ impl<'a, 'tcx> Visitor<'tcx> for NamePrivacyVisitor<'a, 'tcx> {
     }
 
     fn visit_nested_body(&mut self, body: hir::BodyId) {
-        let orig_tables = mem::replace(&mut self.tables, self.tcx.body_tables(body));
+        let old_maybe_typeck_tables = self.maybe_typeck_tables.replace(self.tcx.body_tables(body));
         let body = self.tcx.hir().body(body);
         self.visit_body(body);
-        self.tables = orig_tables;
+        self.maybe_typeck_tables = old_maybe_typeck_tables;
     }
 
     fn visit_item(&mut self, item: &'tcx hir::Item<'tcx>) {
-        let orig_current_item = mem::replace(&mut self.current_item, Some(item.hir_id));
-        let orig_tables =
-            mem::replace(&mut self.tables, item_tables(self.tcx, item.hir_id, self.empty_tables));
+        let orig_current_item = self.current_item.replace(item.hir_id);
         intravisit::walk_item(self, item);
         self.current_item = orig_current_item;
-        self.tables = orig_tables;
-    }
-
-    fn visit_trait_item(&mut self, ti: &'tcx hir::TraitItem<'tcx>) {
-        let orig_tables =
-            mem::replace(&mut self.tables, item_tables(self.tcx, ti.hir_id, self.empty_tables));
-        intravisit::walk_trait_item(self, ti);
-        self.tables = orig_tables;
-    }
-
-    fn visit_impl_item(&mut self, ii: &'tcx hir::ImplItem<'tcx>) {
-        let orig_tables =
-            mem::replace(&mut self.tables, item_tables(self.tcx, ii.hir_id, self.empty_tables));
-        intravisit::walk_impl_item(self, ii);
-        self.tables = orig_tables;
     }
 
     fn visit_expr(&mut self, expr: &'tcx hir::Expr<'tcx>) {
         if let hir::ExprKind::Struct(ref qpath, fields, ref base) = expr.kind {
-            let res = self.tables.qpath_res(qpath, expr.hir_id);
-            let adt = self.tables.expr_ty(expr).ty_adt_def().unwrap();
+            let res = self.tables().qpath_res(qpath, expr.hir_id);
+            let adt = self.tables().expr_ty(expr).ty_adt_def().unwrap();
             let variant = adt.variant_of_res(res);
             if let Some(ref base) = *base {
                 // 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> {
                 for (vf_index, variant_field) in variant.fields.iter().enumerate() {
                     let field = fields
                         .iter()
-                        .find(|f| self.tcx.field_index(f.hir_id, self.tables) == vf_index);
+                        .find(|f| self.tcx.field_index(f.hir_id, self.tables()) == vf_index);
                     let (use_ctxt, span) = match field {
                         Some(field) => (field.ident.span, field.span),
                         None => (base.span, base.span),
@@ -1138,7 +1118,7 @@ impl<'a, 'tcx> Visitor<'tcx> for NamePrivacyVisitor<'a, 'tcx> {
             } else {
                 for field in fields {
                     let use_ctxt = field.ident.span;
-                    let index = self.tcx.field_index(field.hir_id, self.tables);
+                    let index = self.tcx.field_index(field.hir_id, self.tables());
                     self.check_field(use_ctxt, field.span, adt, &variant.fields[index], false);
                 }
             }
@@ -1149,12 +1129,12 @@ impl<'a, 'tcx> Visitor<'tcx> for NamePrivacyVisitor<'a, 'tcx> {
 
     fn visit_pat(&mut self, pat: &'tcx hir::Pat<'tcx>) {
         if let PatKind::Struct(ref qpath, fields, _) = pat.kind {
-            let res = self.tables.qpath_res(qpath, pat.hir_id);
-            let adt = self.tables.pat_ty(pat).ty_adt_def().unwrap();
+            let res = self.tables().qpath_res(qpath, pat.hir_id);
+            let adt = self.tables().pat_ty(pat).ty_adt_def().unwrap();
             let variant = adt.variant_of_res(res);
             for field in fields {
                 let use_ctxt = field.ident.span;
-                let index = self.tcx.field_index(field.hir_id, self.tables);
+                let index = self.tcx.field_index(field.hir_id, self.tables());
                 self.check_field(use_ctxt, field.span, adt, &variant.fields[index], false);
             }
         }
@@ -1169,16 +1149,22 @@ impl<'a, 'tcx> Visitor<'tcx> for NamePrivacyVisitor<'a, 'tcx> {
 /// Checks are performed on "semantic" types regardless of names and their hygiene.
 ////////////////////////////////////////////////////////////////////////////////////////////
 
-struct TypePrivacyVisitor<'a, 'tcx> {
+struct TypePrivacyVisitor<'tcx> {
     tcx: TyCtxt<'tcx>,
-    tables: &'a ty::TypeckTables<'tcx>,
+    maybe_typeck_tables: Option<&'tcx ty::TypeckTables<'tcx>>,
     current_item: LocalDefId,
-    in_body: bool,
     span: Span,
-    empty_tables: &'a ty::TypeckTables<'tcx>,
 }
 
-impl<'a, 'tcx> TypePrivacyVisitor<'a, 'tcx> {
+impl<'tcx> TypePrivacyVisitor<'tcx> {
+    /// Gets the type-checking side-tables for the current body.
+    /// As this will ICE if called outside bodies, only call when working with
+    /// `Expr` or `Pat` nodes (they are guaranteed to be found only in bodies).
+    #[track_caller]
+    fn tables(&self) -> &'tcx ty::TypeckTables<'tcx> {
+        self.maybe_typeck_tables.expect("`TypePrivacyVisitor::tables` called outside of body")
+    }
+
     fn item_is_accessible(&self, did: DefId) -> bool {
         def_id_visibility(self.tcx, did)
             .0
@@ -1188,10 +1174,11 @@ impl<'a, 'tcx> TypePrivacyVisitor<'a, 'tcx> {
     // Take node-id of an expression or pattern and check its type for privacy.
     fn check_expr_pat_type(&mut self, id: hir::HirId, span: Span) -> bool {
         self.span = span;
-        if self.visit(self.tables.node_type(id)) || self.visit(self.tables.node_substs(id)) {
+        let tables = self.tables();
+        if self.visit(tables.node_type(id)) || self.visit(tables.node_substs(id)) {
             return true;
         }
-        if let Some(adjustments) = self.tables.adjustments().get(id) {
+        if let Some(adjustments) = tables.adjustments().get(id) {
             for adjustment in adjustments {
                 if self.visit(adjustment.target) {
                     return true;
@@ -1214,7 +1201,7 @@ impl<'a, 'tcx> TypePrivacyVisitor<'a, 'tcx> {
     }
 }
 
-impl<'a, 'tcx> Visitor<'tcx> for TypePrivacyVisitor<'a, 'tcx> {
+impl<'tcx> Visitor<'tcx> for TypePrivacyVisitor<'tcx> {
     type Map = Map<'tcx>;
 
     /// We want to visit items in the context of their containing
@@ -1229,19 +1216,17 @@ impl<'a, 'tcx> Visitor<'tcx> for TypePrivacyVisitor<'a, 'tcx> {
     }
 
     fn visit_nested_body(&mut self, body: hir::BodyId) {
-        let orig_tables = mem::replace(&mut self.tables, self.tcx.body_tables(body));
-        let orig_in_body = mem::replace(&mut self.in_body, true);
+        let old_maybe_typeck_tables = self.maybe_typeck_tables.replace(self.tcx.body_tables(body));
         let body = self.tcx.hir().body(body);
         self.visit_body(body);
-        self.tables = orig_tables;
-        self.in_body = orig_in_body;
+        self.maybe_typeck_tables = old_maybe_typeck_tables;
     }
 
     fn visit_ty(&mut self, hir_ty: &'tcx hir::Ty<'tcx>) {
         self.span = hir_ty.span;
-        if self.in_body {
+        if let Some(tables) = self.maybe_typeck_tables {
             // Types in bodies.
-            if self.visit(self.tables.node_type(hir_ty.hir_id)) {
+            if self.visit(tables.node_type(hir_ty.hir_id)) {
                 return;
             }
         } else {
@@ -1258,7 +1243,7 @@ impl<'a, 'tcx> Visitor<'tcx> for TypePrivacyVisitor<'a, 'tcx> {
 
     fn visit_trait_ref(&mut self, trait_ref: &'tcx hir::TraitRef<'tcx>) {
         self.span = trait_ref.path.span;
-        if !self.in_body {
+        if self.maybe_typeck_tables.is_none() {
             // Avoid calling `hir_trait_to_predicates` in bodies, it will ICE.
             // The traits' privacy in bodies is already checked as a part of trait object types.
             let bounds = rustc_typeck::hir_trait_to_predicates(
@@ -1304,7 +1289,7 @@ impl<'a, 'tcx> Visitor<'tcx> for TypePrivacyVisitor<'a, 'tcx> {
             hir::ExprKind::MethodCall(_, span, _, _) => {
                 // Method calls have to be checked specially.
                 self.span = span;
-                if let Some(def_id) = self.tables.type_dependent_def_id(expr.hir_id) {
+                if let Some(def_id) = self.tables().type_dependent_def_id(expr.hir_id) {
                     if self.visit(self.tcx.type_of(def_id)) {
                         return;
                     }
@@ -1327,9 +1312,14 @@ impl<'a, 'tcx> Visitor<'tcx> for TypePrivacyVisitor<'a, 'tcx> {
     // more code internal visibility at link time. (Access to private functions
     // is already prohibited by type privacy for function types.)
     fn visit_qpath(&mut self, qpath: &'tcx hir::QPath<'tcx>, id: hir::HirId, span: Span) {
-        let def = match self.tables.qpath_res(qpath, id) {
-            Res::Def(kind, def_id) => Some((kind, def_id)),
-            _ => None,
+        let def = match qpath {
+            hir::QPath::Resolved(_, path) => match path.res {
+                Res::Def(kind, def_id) => Some((kind, def_id)),
+                _ => None,
+            },
+            hir::QPath::TypeRelative(..) => {
+                self.maybe_typeck_tables.and_then(|tables| tables.type_dependent_def(id))
+            }
         };
         let def = def.filter(|(kind, _)| match kind {
             DefKind::AssocFn | DefKind::AssocConst | DefKind::AssocTy | DefKind::Static => true,
@@ -1385,31 +1375,14 @@ impl<'a, 'tcx> Visitor<'tcx> for TypePrivacyVisitor<'a, 'tcx> {
     fn visit_item(&mut self, item: &'tcx hir::Item<'tcx>) {
         let orig_current_item =
             mem::replace(&mut self.current_item, self.tcx.hir().local_def_id(item.hir_id));
-        let orig_in_body = mem::replace(&mut self.in_body, false);
-        let orig_tables =
-            mem::replace(&mut self.tables, item_tables(self.tcx, item.hir_id, self.empty_tables));
+        let old_maybe_typeck_tables = self.maybe_typeck_tables.take();
         intravisit::walk_item(self, item);
-        self.tables = orig_tables;
-        self.in_body = orig_in_body;
+        self.maybe_typeck_tables = old_maybe_typeck_tables;
         self.current_item = orig_current_item;
     }
-
-    fn visit_trait_item(&mut self, ti: &'tcx hir::TraitItem<'tcx>) {
-        let orig_tables =
-            mem::replace(&mut self.tables, item_tables(self.tcx, ti.hir_id, self.empty_tables));
-        intravisit::walk_trait_item(self, ti);
-        self.tables = orig_tables;
-    }
-
-    fn visit_impl_item(&mut self, ii: &'tcx hir::ImplItem<'tcx>) {
-        let orig_tables =
-            mem::replace(&mut self.tables, item_tables(self.tcx, ii.hir_id, self.empty_tables));
-        intravisit::walk_impl_item(self, ii);
-        self.tables = orig_tables;
-    }
 }
 
-impl DefIdVisitor<'tcx> for TypePrivacyVisitor<'a, 'tcx> {
+impl DefIdVisitor<'tcx> for TypePrivacyVisitor<'tcx> {
     fn tcx(&self) -> TyCtxt<'tcx> {
         self.tcx
     }
@@ -2066,29 +2039,16 @@ pub fn provide(providers: &mut Providers<'_>) {
 }
 
 fn check_mod_privacy(tcx: TyCtxt<'_>, module_def_id: LocalDefId) {
-    let empty_tables = ty::TypeckTables::empty(None);
-
     // Check privacy of names not checked in previous compilation stages.
-    let mut visitor = NamePrivacyVisitor {
-        tcx,
-        tables: &empty_tables,
-        current_item: None,
-        empty_tables: &empty_tables,
-    };
+    let mut visitor = NamePrivacyVisitor { tcx, maybe_typeck_tables: None, current_item: None };
     let (module, span, hir_id) = tcx.hir().get_module(module_def_id);
 
     intravisit::walk_mod(&mut visitor, module, hir_id);
 
     // Check privacy of explicitly written types and traits as well as
     // inferred types of expressions and patterns.
-    let mut visitor = TypePrivacyVisitor {
-        tcx,
-        tables: &empty_tables,
-        current_item: module_def_id,
-        in_body: false,
-        span,
-        empty_tables: &empty_tables,
-    };
+    let mut visitor =
+        TypePrivacyVisitor { tcx, maybe_typeck_tables: None, current_item: module_def_id, span };
     intravisit::walk_mod(&mut visitor, module, hir_id);
 }