about summary refs log tree commit diff
diff options
context:
space:
mode:
authorthreadexception <hannes.gaumann@outlook.de>2022-01-18 17:09:17 +0100
committerthreadexception <hannes.gaumann@outlook.de>2022-01-26 09:47:52 +0100
commitecd06e1e6ad28daab4e0ed5a8d6014a3ca2affb9 (patch)
tree60cf758dc2db6c0121d382e4b256c0f40fc84e81
parent7bc7be860f99f4a40d45b0f74e2d01b02e072357 (diff)
downloadrust-ecd06e1e6ad28daab4e0ed5a8d6014a3ca2affb9.tar.gz
rust-ecd06e1e6ad28daab4e0ed5a8d6014a3ca2affb9.zip
Don't suggest inaccessible fields
-rw-r--r--compiler/rustc_typeck/src/check/expr.rs28
-rw-r--r--src/test/ui/suggestions/private-field.rs19
-rw-r--r--src/test/ui/suggestions/private-field.stderr11
3 files changed, 49 insertions, 9 deletions
diff --git a/compiler/rustc_typeck/src/check/expr.rs b/compiler/rustc_typeck/src/check/expr.rs
index 3e73cc659ec..af2ac9bb2ee 100644
--- a/compiler/rustc_typeck/src/check/expr.rs
+++ b/compiler/rustc_typeck/src/check/expr.rs
@@ -31,7 +31,7 @@ use rustc_hir as hir;
 use rustc_hir::def::{CtorKind, DefKind, Res};
 use rustc_hir::def_id::DefId;
 use rustc_hir::intravisit::Visitor;
-use rustc_hir::{ExprKind, QPath};
+use rustc_hir::{ExprKind, HirId, QPath};
 use rustc_infer::infer;
 use rustc_infer::infer::type_variable::{TypeVariableOrigin, TypeVariableOriginKind};
 use rustc_infer::infer::InferOk;
@@ -1948,7 +1948,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
             "ban_nonexisting_field: field={:?}, base={:?}, expr={:?}, expr_ty={:?}",
             field, base, expr, expr_t
         );
-        let mut err = self.no_such_field_err(field, expr_t);
+        let mut err = self.no_such_field_err(field, expr_t, base.hir_id);
 
         match *expr_t.peel_refs().kind() {
             ty::Array(_, len) => {
@@ -2186,6 +2186,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
         &self,
         field: Ident,
         expr_t: &'tcx ty::TyS<'tcx>,
+        id: HirId,
     ) -> DiagnosticBuilder<'_> {
         let span = field.span;
         debug!("no_such_field_err(span: {:?}, field: {:?}, expr_t: {:?})", span, field, expr_t);
@@ -2203,9 +2204,14 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
         // try to add a suggestion in case the field is a nested field of a field of the Adt
         if let Some((fields, substs)) = self.get_field_candidates(span, &expr_t) {
             for candidate_field in fields.iter() {
-                if let Some(field_path) =
-                    self.check_for_nested_field(span, field, candidate_field, substs, vec![])
-                {
+                if let Some(field_path) = self.check_for_nested_field(
+                    span,
+                    field,
+                    candidate_field,
+                    substs,
+                    vec![],
+                    self.tcx.parent_module(id).to_def_id(),
+                ) {
                     let field_path_str = field_path
                         .iter()
                         .map(|id| id.name.to_ident_string())
@@ -2257,6 +2263,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
         candidate_field: &ty::FieldDef,
         subst: SubstsRef<'tcx>,
         mut field_path: Vec<Ident>,
+        id: DefId,
     ) -> Option<Vec<Ident>> {
         debug!(
             "check_for_nested_field(span: {:?}, candidate_field: {:?}, field_path: {:?}",
@@ -2276,10 +2283,12 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
             let field_ty = candidate_field.ty(self.tcx, subst);
             if let Some((nested_fields, subst)) = self.get_field_candidates(span, &field_ty) {
                 for field in nested_fields.iter() {
-                    let ident = field.ident(self.tcx).normalize_to_macros_2_0();
-                    if ident == target_field {
-                        return Some(field_path);
-                    } else {
+                    let accessible = field.vis.is_accessible_from(id, self.tcx);
+                    if accessible {
+                        let ident = field.ident(self.tcx).normalize_to_macros_2_0();
+                        if ident == target_field {
+                            return Some(field_path);
+                        }
                         let field_path = field_path.clone();
                         if let Some(path) = self.check_for_nested_field(
                             span,
@@ -2287,6 +2296,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
                             field,
                             subst,
                             field_path,
+                            id,
                         ) {
                             return Some(path);
                         }
diff --git a/src/test/ui/suggestions/private-field.rs b/src/test/ui/suggestions/private-field.rs
new file mode 100644
index 00000000000..1cc4d2a4d06
--- /dev/null
+++ b/src/test/ui/suggestions/private-field.rs
@@ -0,0 +1,19 @@
+// compile-flags: --crate-type lib
+pub struct S {
+    pub val: string::MyString,
+}
+
+pub fn test(s: S) {
+    dbg!(s.cap) //~ ERROR: no field `cap` on type `S` [E0609]
+}
+
+pub(crate) mod string {
+
+    pub struct MyString {
+        buf: MyVec,
+    }
+
+    struct MyVec {
+        cap: usize,
+    }
+}
diff --git a/src/test/ui/suggestions/private-field.stderr b/src/test/ui/suggestions/private-field.stderr
new file mode 100644
index 00000000000..c38c795e07a
--- /dev/null
+++ b/src/test/ui/suggestions/private-field.stderr
@@ -0,0 +1,11 @@
+error[E0609]: no field `cap` on type `S`
+  --> $DIR/private-field.rs:7:12
+   |
+LL |     dbg!(s.cap)
+   |            ^^^ unknown field
+   |
+   = note: available fields are: `val`
+
+error: aborting due to previous error
+
+For more information about this error, try `rustc --explain E0609`.