diff --git a/compiler/rustc_typeck/src/check/pat.rs b/compiler/rustc_typeck/src/check/pat.rs index f8ca916caf1..733f8e3dc9d 100644 --- a/compiler/rustc_typeck/src/check/pat.rs +++ b/compiler/rustc_typeck/src/check/pat.rs @@ -1176,6 +1176,7 @@ fn check_struct_pat_fields( let mut no_field_errors = true; let mut inexistent_fields = vec![]; + let mut invisible_fields = vec![]; // Typecheck each field. for field in fields { let span = field.span; @@ -1191,6 +1192,12 @@ fn check_struct_pat_fields( field_map .get(&ident) .map(|(i, f)| { + if !f + .vis + .is_accessible_from(tcx.parent_module(pat.hir_id).to_def_id(), tcx) + { + invisible_fields.push(field.ident); + } self.write_field_index(field.hir_id, *i); self.tcx.check_stability(f.did, Some(pat.hir_id), span); self.field_ty(span, f, substs) @@ -1281,6 +1288,13 @@ fn check_struct_pat_fields( self.error_tuple_variant_index_shorthand(variant, pat, fields) { err.emit(); + } else if !invisible_fields.is_empty() { + let mut err = self.error_invisible_fields( + adt.variant_descr(), + &invisible_fields, + variant, + ); + err.emit(); } } } @@ -1359,6 +1373,41 @@ fn error_field_already_bound(&self, span: Span, ident: Ident, other_field: Span) .emit(); } + fn error_invisible_fields( + &self, + kind_name: &str, + invisible_fields: &[Ident], + variant: &ty::VariantDef, + ) -> DiagnosticBuilder<'tcx> { + let spans = invisible_fields.iter().map(|ident| ident.span).collect::>(); + let (field_names, t) = if invisible_fields.len() == 1 { + (format!("a field named `{}`", invisible_fields[0]), "is") + } else { + ( + format!( + "fields named {}", + invisible_fields + .iter() + .map(|ident| format!("`{}`", ident)) + .collect::>() + .join(", ") + ), + "are", + ) + }; + let err = struct_span_err!( + self.tcx.sess, + spans, + E0603, + "cannot match on {} of {} `{}`, which {} not accessible in current scope", + field_names, + kind_name, + self.tcx.def_path_str(variant.def_id), + t + ); + err + } + fn error_inexistent_fields( &self, kind_name: &str, diff --git a/src/test/ui/structs/struct-variant-privacy-xc.rs b/src/test/ui/structs/struct-variant-privacy-xc.rs index 10e9639096f..bf765be75dd 100644 --- a/src/test/ui/structs/struct-variant-privacy-xc.rs +++ b/src/test/ui/structs/struct-variant-privacy-xc.rs @@ -1,9 +1,11 @@ // aux-build:struct_variant_privacy.rs extern crate struct_variant_privacy; -fn f(b: struct_variant_privacy::Bar) { //~ ERROR enum `Bar` is private +fn f(b: struct_variant_privacy::Bar) { + //~^ ERROR enum `Bar` is private match b { - struct_variant_privacy::Bar::Baz { a: _a } => {} //~ ERROR enum `Bar` is private + struct_variant_privacy::Bar::Baz { a: _a } => {} //~ ERROR cannot match on + //~^ ERROR enum `Bar` is private } } diff --git a/src/test/ui/structs/struct-variant-privacy-xc.stderr b/src/test/ui/structs/struct-variant-privacy-xc.stderr index 4e022cef1b2..03de40b488c 100644 --- a/src/test/ui/structs/struct-variant-privacy-xc.stderr +++ b/src/test/ui/structs/struct-variant-privacy-xc.stderr @@ -11,7 +11,7 @@ LL | enum Bar { | ^^^^^^^^ error[E0603]: enum `Bar` is private - --> $DIR/struct-variant-privacy-xc.rs:6:33 + --> $DIR/struct-variant-privacy-xc.rs:7:33 | LL | struct_variant_privacy::Bar::Baz { a: _a } => {} | ^^^ private enum @@ -22,6 +22,12 @@ note: the enum `Bar` is defined here LL | enum Bar { | ^^^^^^^^ -error: aborting due to 2 previous errors +error[E0603]: cannot match on a field named `a` of variant `struct_variant_privacy::Bar::Baz`, which is not accessible in current scope + --> $DIR/struct-variant-privacy-xc.rs:7:44 + | +LL | struct_variant_privacy::Bar::Baz { a: _a } => {} + | ^ + +error: aborting due to 3 previous errors For more information about this error, try `rustc --explain E0603`. diff --git a/src/test/ui/structs/struct-variant-privacy.rs b/src/test/ui/structs/struct-variant-privacy.rs index 8355879e7d9..7ce8ce9e290 100644 --- a/src/test/ui/structs/struct-variant-privacy.rs +++ b/src/test/ui/structs/struct-variant-privacy.rs @@ -1,12 +1,14 @@ mod foo { enum Bar { - Baz { a: isize } + Baz { a: isize }, } } -fn f(b: foo::Bar) { //~ ERROR enum `Bar` is private +fn f(b: foo::Bar) { + //~^ ERROR enum `Bar` is private match b { foo::Bar::Baz { a: _a } => {} //~ ERROR enum `Bar` is private + //~^ ERROR cannot match on } } diff --git a/src/test/ui/structs/struct-variant-privacy.stderr b/src/test/ui/structs/struct-variant-privacy.stderr index a6bc381ff6b..a69a888553b 100644 --- a/src/test/ui/structs/struct-variant-privacy.stderr +++ b/src/test/ui/structs/struct-variant-privacy.stderr @@ -11,7 +11,7 @@ LL | enum Bar { | ^^^^^^^^ error[E0603]: enum `Bar` is private - --> $DIR/struct-variant-privacy.rs:9:14 + --> $DIR/struct-variant-privacy.rs:10:14 | LL | foo::Bar::Baz { a: _a } => {} | ^^^ private enum @@ -22,6 +22,12 @@ note: the enum `Bar` is defined here LL | enum Bar { | ^^^^^^^^ -error: aborting due to 2 previous errors +error[E0603]: cannot match on a field named `a` of variant `Bar::Baz`, which is not accessible in current scope + --> $DIR/struct-variant-privacy.rs:10:25 + | +LL | foo::Bar::Baz { a: _a } => {} + | ^ + +error: aborting due to 3 previous errors For more information about this error, try `rustc --explain E0603`. diff --git a/src/test/ui/typeck/issue-82772.rs b/src/test/ui/typeck/issue-82772.rs new file mode 100644 index 00000000000..62eb5f7a021 --- /dev/null +++ b/src/test/ui/typeck/issue-82772.rs @@ -0,0 +1,13 @@ +// edition:2018 + +fn main() { + use a::LocalModPrivateStruct; + let Box { 1: _, .. }: Box<()>; //~ ERROR cannot match on + let LocalModPrivateStruct { 1: _, .. } = LocalModPrivateStruct::default(); + //~^ ERROR cannot match on +} + +mod a { + #[derive(Default)] + pub struct LocalModPrivateStruct(u8, u8); +} diff --git a/src/test/ui/typeck/issue-82772.stderr b/src/test/ui/typeck/issue-82772.stderr new file mode 100644 index 00000000000..5bc6a5aa9e3 --- /dev/null +++ b/src/test/ui/typeck/issue-82772.stderr @@ -0,0 +1,15 @@ +error[E0603]: cannot match on a field named `1` of struct `Box`, which is not accessible in current scope + --> $DIR/issue-82772.rs:5:15 + | +LL | let Box { 1: _, .. }: Box<()>; + | ^ + +error[E0603]: cannot match on a field named `1` of struct `LocalModPrivateStruct`, which is not accessible in current scope + --> $DIR/issue-82772.rs:6:33 + | +LL | let LocalModPrivateStruct { 1: _, .. } = LocalModPrivateStruct::default(); + | ^ + +error: aborting due to 2 previous errors + +For more information about this error, try `rustc --explain E0603`.