From 2fd2796aae18a7e7a736346f344daa56fae37c41 Mon Sep 17 00:00:00 2001 From: csmoe Date: Fri, 5 Mar 2021 13:54:35 +0800 Subject: [PATCH 1/2] add ui testcase for issue 82772 --- compiler/rustc_typeck/src/check/pat.rs | 49 +++++++++++++++++++ .../ui/structs/struct-variant-privacy-xc.rs | 6 ++- .../structs/struct-variant-privacy-xc.stderr | 10 +++- src/test/ui/structs/struct-variant-privacy.rs | 6 ++- .../ui/structs/struct-variant-privacy.stderr | 10 +++- src/test/ui/typeck/issue-82772.rs | 13 +++++ src/test/ui/typeck/issue-82772.stderr | 15 ++++++ 7 files changed, 101 insertions(+), 8 deletions(-) create mode 100644 src/test/ui/typeck/issue-82772.rs create mode 100644 src/test/ui/typeck/issue-82772.stderr diff --git a/compiler/rustc_typeck/src/check/pat.rs b/compiler/rustc_typeck/src/check/pat.rs index f8ca916caf127..733f8e3dc9d8f 100644 --- a/compiler/rustc_typeck/src/check/pat.rs +++ b/compiler/rustc_typeck/src/check/pat.rs @@ -1176,6 +1176,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { 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 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { 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 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { 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 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { .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 10e9639096f0f..bf765be75dd8c 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 4e022cef1b2d3..03de40b488ca9 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 8355879e7d94d..7ce8ce9e290c8 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 a6bc381ff6b38..a69a888553b7a 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 0000000000000..62eb5f7a02147 --- /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 0000000000000..5bc6a5aa9e32f --- /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`. From 77fb6a0f32408925f212d1fb877e900f9736840d Mon Sep 17 00:00:00 2001 From: csmoe Date: Fri, 12 Mar 2021 01:49:27 +0800 Subject: [PATCH 2/2] fix: check before index into generated patterns --- .../src/thir/pattern/deconstruct_pat.rs | 4 +- compiler/rustc_typeck/src/check/pat.rs | 49 ------------------- .../ui/structs/struct-variant-privacy-xc.rs | 3 +- .../structs/struct-variant-privacy-xc.stderr | 8 +-- src/test/ui/structs/struct-variant-privacy.rs | 1 - .../ui/structs/struct-variant-privacy.stderr | 8 +-- src/test/ui/typeck/issue-82772.rs | 10 ++-- src/test/ui/typeck/issue-82772.stderr | 22 ++++++--- 8 files changed, 25 insertions(+), 80 deletions(-) diff --git a/compiler/rustc_mir_build/src/thir/pattern/deconstruct_pat.rs b/compiler/rustc_mir_build/src/thir/pattern/deconstruct_pat.rs index 3a67eeff92c31..8c740a7ec155a 100644 --- a/compiler/rustc_mir_build/src/thir/pattern/deconstruct_pat.rs +++ b/compiler/rustc_mir_build/src/thir/pattern/deconstruct_pat.rs @@ -1343,7 +1343,9 @@ impl<'p, 'tcx> Fields<'p, 'tcx> { match &mut fields { Fields::Vec(pats) => { for (i, pat) in new_pats { - pats[i] = pat + if let Some(p) = pats.get_mut(i) { + *p = pat; + } } } Fields::Filtered { fields, .. } => { diff --git a/compiler/rustc_typeck/src/check/pat.rs b/compiler/rustc_typeck/src/check/pat.rs index 733f8e3dc9d8f..f8ca916caf127 100644 --- a/compiler/rustc_typeck/src/check/pat.rs +++ b/compiler/rustc_typeck/src/check/pat.rs @@ -1176,7 +1176,6 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { 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; @@ -1192,12 +1191,6 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { 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) @@ -1288,13 +1281,6 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { 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(); } } } @@ -1373,41 +1359,6 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { .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 bf765be75dd8c..763ab952738b7 100644 --- a/src/test/ui/structs/struct-variant-privacy-xc.rs +++ b/src/test/ui/structs/struct-variant-privacy-xc.rs @@ -4,8 +4,7 @@ extern crate struct_variant_privacy; fn f(b: struct_variant_privacy::Bar) { //~^ ERROR enum `Bar` is private match b { - struct_variant_privacy::Bar::Baz { a: _a } => {} //~ ERROR cannot match on - //~^ ERROR enum `Bar` is private + struct_variant_privacy::Bar::Baz { a: _a } => {} //~ 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 03de40b488ca9..1c1caaef8b79d 100644 --- a/src/test/ui/structs/struct-variant-privacy-xc.stderr +++ b/src/test/ui/structs/struct-variant-privacy-xc.stderr @@ -22,12 +22,6 @@ note: the enum `Bar` is defined here LL | enum Bar { | ^^^^^^^^ -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 +error: aborting due to 2 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 7ce8ce9e290c8..fcdf9a22baf4b 100644 --- a/src/test/ui/structs/struct-variant-privacy.rs +++ b/src/test/ui/structs/struct-variant-privacy.rs @@ -8,7 +8,6 @@ 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 a69a888553b7a..eafd26c716f11 100644 --- a/src/test/ui/structs/struct-variant-privacy.stderr +++ b/src/test/ui/structs/struct-variant-privacy.stderr @@ -22,12 +22,6 @@ note: the enum `Bar` is defined here LL | enum Bar { | ^^^^^^^^ -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 +error: aborting due to 2 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 index 62eb5f7a02147..326273bfe9229 100644 --- a/src/test/ui/typeck/issue-82772.rs +++ b/src/test/ui/typeck/issue-82772.rs @@ -1,13 +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 + use a::ModPrivateStruct; + let Box { 0: _, .. }: Box<()>; //~ ERROR field `0` of + let Box { 1: _, .. }: Box<()>; //~ ERROR field `1` of + let ModPrivateStruct { 1: _, .. } = ModPrivateStruct::default(); //~ ERROR field `1` of } mod a { #[derive(Default)] - pub struct LocalModPrivateStruct(u8, u8); + pub struct ModPrivateStruct(u8, u8); } diff --git a/src/test/ui/typeck/issue-82772.stderr b/src/test/ui/typeck/issue-82772.stderr index 5bc6a5aa9e32f..321143cb9683d 100644 --- a/src/test/ui/typeck/issue-82772.stderr +++ b/src/test/ui/typeck/issue-82772.stderr @@ -1,15 +1,21 @@ -error[E0603]: cannot match on a field named `1` of struct `Box`, which is not accessible in current scope +error[E0451]: field `0` of struct `Box` is private --> $DIR/issue-82772.rs:5:15 | +LL | let Box { 0: _, .. }: Box<()>; + | ^^^^ private field + +error[E0451]: field `1` of struct `Box` is private + --> $DIR/issue-82772.rs:6:15 + | LL | let Box { 1: _, .. }: Box<()>; - | ^ + | ^^^^ private field -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 +error[E0451]: field `1` of struct `ModPrivateStruct` is private + --> $DIR/issue-82772.rs:7:28 | -LL | let LocalModPrivateStruct { 1: _, .. } = LocalModPrivateStruct::default(); - | ^ +LL | let ModPrivateStruct { 1: _, .. } = ModPrivateStruct::default(); + | ^^^^ private field -error: aborting due to 2 previous errors +error: aborting due to 3 previous errors -For more information about this error, try `rustc --explain E0603`. +For more information about this error, try `rustc --explain E0451`.