diff --git a/compiler/rustc_resolve/src/late/diagnostics.rs b/compiler/rustc_resolve/src/late/diagnostics.rs index c24b383f3b811..cafceff4f29ed 100644 --- a/compiler/rustc_resolve/src/late/diagnostics.rs +++ b/compiler/rustc_resolve/src/late/diagnostics.rs @@ -917,54 +917,71 @@ impl<'a: 'ast, 'ast> LateResolutionVisitor<'a, '_, 'ast> { self.suggest_using_enum_variant(err, source, def_id, span); } (Res::Def(DefKind::Struct, def_id), _) if ns == ValueNS => { - if let Some((ctor_def, ctor_vis, fields)) = - self.r.struct_constructors.get(&def_id).cloned() + let (ctor_def, ctor_vis, fields) = + if let Some(struct_ctor) = self.r.struct_constructors.get(&def_id).cloned() { + struct_ctor + } else { + bad_struct_syntax_suggestion(def_id); + return true; + }; + + let is_accessible = self.r.is_accessible_from(ctor_vis, self.parent_scope.module); + if !is_expected(ctor_def) || is_accessible { + return true; + } + + let field_spans = match source { + // e.g. `if let Enum::TupleVariant(field1, field2) = _` + PathSource::TupleStruct(_, pattern_spans) => { + err.set_primary_message( + "cannot match against a tuple struct which contains private fields", + ); + + // Use spans of the tuple struct pattern. + Some(Vec::from(pattern_spans)) + } + // e.g. `let _ = Enum::TupleVariant(field1, field2);` + _ if source.is_call() => { + err.set_primary_message( + "cannot initialize a tuple struct which contains private fields", + ); + + // Use spans of the tuple struct definition. + self.r + .field_names + .get(&def_id) + .map(|fields| fields.iter().map(|f| f.span).collect::>()) + } + _ => None, + }; + + if let Some(spans) = + field_spans.filter(|spans| spans.len() > 0 && fields.len() == spans.len()) { - let accessible_ctor = - self.r.is_accessible_from(ctor_vis, self.parent_scope.module); - if is_expected(ctor_def) && !accessible_ctor { - let mut better_diag = false; - if let PathSource::TupleStruct(_, pattern_spans) = source { - if pattern_spans.len() > 0 && fields.len() == pattern_spans.len() { - let non_visible_spans: Vec = fields - .iter() - .zip(pattern_spans.iter()) - .filter_map(|(vis, span)| { - match self - .r - .is_accessible_from(*vis, self.parent_scope.module) - { - true => None, - false => Some(*span), - } - }) - .collect(); - // Extra check to be sure - if non_visible_spans.len() > 0 { - let mut m: rustc_span::MultiSpan = - non_visible_spans.clone().into(); - non_visible_spans.into_iter().for_each(|s| { - m.push_span_label(s, "private field".to_string()) - }); - err.span_note( - m, - "constructor is not visible here due to private fields", - ); - better_diag = true; - } - } - } + let non_visible_spans: Vec = fields + .iter() + .zip(spans.iter()) + .filter(|(vis, _)| { + !self.r.is_accessible_from(**vis, self.parent_scope.module) + }) + .map(|(_, span)| *span) + .collect(); - if !better_diag { - err.span_label( - span, - "constructor is not visible here due to private fields".to_string(), - ); - } + if non_visible_spans.len() > 0 { + let mut m: rustc_span::MultiSpan = non_visible_spans.clone().into(); + non_visible_spans + .into_iter() + .for_each(|s| m.push_span_label(s, "private field".to_string())); + err.span_note(m, "constructor is not visible here due to private fields"); } - } else { - bad_struct_syntax_suggestion(def_id); + + return true; } + + err.span_label( + span, + "constructor is not visible here due to private fields".to_string(), + ); } ( Res::Def( diff --git a/src/test/ui/issues/issue-38412.rs b/src/test/ui/issues/issue-38412.rs index 058e1be756577..96bd93af51405 100644 --- a/src/test/ui/issues/issue-38412.rs +++ b/src/test/ui/issues/issue-38412.rs @@ -1,6 +1,6 @@ fn main() { let Box(a) = loop { }; - //~^ ERROR expected tuple struct or tuple variant, found struct `Box` + //~^ ERROR cannot match against a tuple struct which contains private fields // (The below is a trick to allow compiler to infer a type for // variable `a` without attempting to ascribe a type to the diff --git a/src/test/ui/issues/issue-38412.stderr b/src/test/ui/issues/issue-38412.stderr index 318c92ad35fc5..610696f84d5f0 100644 --- a/src/test/ui/issues/issue-38412.stderr +++ b/src/test/ui/issues/issue-38412.stderr @@ -1,4 +1,4 @@ -error[E0532]: expected tuple struct or tuple variant, found struct `Box` +error[E0532]: cannot match against a tuple struct which contains private fields --> $DIR/issue-38412.rs:2:9 | LL | let Box(a) = loop { }; diff --git a/src/test/ui/issues/issue-42944.rs b/src/test/ui/issues/issue-42944.rs index a088f91554dfb..a4404857a56af 100644 --- a/src/test/ui/issues/issue-42944.rs +++ b/src/test/ui/issues/issue-42944.rs @@ -7,7 +7,7 @@ mod bar { fn foo() { Bx(()); - //~^ ERROR expected function, tuple struct or tuple variant, found struct `Bx` [E0423] + //~^ ERROR cannot initialize a tuple struct which contains private fields [E0423] } } diff --git a/src/test/ui/issues/issue-42944.stderr b/src/test/ui/issues/issue-42944.stderr index 9fad43757ba62..008492529d18c 100644 --- a/src/test/ui/issues/issue-42944.stderr +++ b/src/test/ui/issues/issue-42944.stderr @@ -1,8 +1,14 @@ -error[E0423]: expected function, tuple struct or tuple variant, found struct `Bx` +error[E0423]: cannot initialize a tuple struct which contains private fields --> $DIR/issue-42944.rs:9:9 | LL | Bx(()); - | ^^ constructor is not visible here due to private fields + | ^^ + | +note: constructor is not visible here due to private fields + --> $DIR/issue-42944.rs:2:19 + | +LL | pub struct Bx(()); + | ^^ private field error[E0425]: cannot find function, tuple struct or tuple variant `Bx` in this scope --> $DIR/issue-42944.rs:16:9 diff --git a/src/test/ui/issues/issue-75906.rs b/src/test/ui/issues/issue-75906.rs new file mode 100644 index 0000000000000..710039d79e77b --- /dev/null +++ b/src/test/ui/issues/issue-75906.rs @@ -0,0 +1,13 @@ +mod m { + pub struct Foo { x: u8 } + + pub struct Bar(u8); +} + +use m::{Foo, Bar}; + +fn main() { + let x = Foo { x: 12 }; + let y = Bar(12); + //~^ ERROR cannot initialize a tuple struct which contains private fields [E0423] +} diff --git a/src/test/ui/issues/issue-75906.stderr b/src/test/ui/issues/issue-75906.stderr new file mode 100644 index 0000000000000..4c6a68646adc8 --- /dev/null +++ b/src/test/ui/issues/issue-75906.stderr @@ -0,0 +1,15 @@ +error[E0423]: cannot initialize a tuple struct which contains private fields + --> $DIR/issue-75906.rs:11:13 + | +LL | let y = Bar(12); + | ^^^ + | +note: constructor is not visible here due to private fields + --> $DIR/issue-75906.rs:4:20 + | +LL | pub struct Bar(u8); + | ^^ private field + +error: aborting due to previous error + +For more information about this error, try `rustc --explain E0423`. diff --git a/src/test/ui/issues/issue-75907.rs b/src/test/ui/issues/issue-75907.rs index 8c155d9be3565..1534b6d07deb0 100644 --- a/src/test/ui/issues/issue-75907.rs +++ b/src/test/ui/issues/issue-75907.rs @@ -13,6 +13,6 @@ use foo::{make_bar, Bar, Foo}; fn main() { let Bar(x, y, Foo(z)) = make_bar(); - //~^ ERROR expected tuple struct - //~| ERROR expected tuple struct + //~^ ERROR cannot match against a tuple struct which contains private fields + //~| ERROR cannot match against a tuple struct which contains private fields } diff --git a/src/test/ui/issues/issue-75907.stderr b/src/test/ui/issues/issue-75907.stderr index 65b9a51e01dee..2f89e31a31a1e 100644 --- a/src/test/ui/issues/issue-75907.stderr +++ b/src/test/ui/issues/issue-75907.stderr @@ -1,4 +1,4 @@ -error[E0532]: expected tuple struct or tuple variant, found struct `Bar` +error[E0532]: cannot match against a tuple struct which contains private fields --> $DIR/issue-75907.rs:15:9 | LL | let Bar(x, y, Foo(z)) = make_bar(); @@ -12,7 +12,7 @@ LL | let Bar(x, y, Foo(z)) = make_bar(); | | | private field -error[E0532]: expected tuple struct or tuple variant, found struct `Foo` +error[E0532]: cannot match against a tuple struct which contains private fields --> $DIR/issue-75907.rs:15:19 | LL | let Bar(x, y, Foo(z)) = make_bar(); diff --git a/src/test/ui/issues/issue-75907_b.rs b/src/test/ui/issues/issue-75907_b.rs index fdd3bc6d7244e..a775845279eb8 100644 --- a/src/test/ui/issues/issue-75907_b.rs +++ b/src/test/ui/issues/issue-75907_b.rs @@ -7,5 +7,5 @@ use a::{make_bar, Bar}; fn main() { let Bar(x, y, z) = make_bar(); - //~^ ERROR expected tuple struct + //~^ ERROR cannot match against a tuple struct which contains private fields } diff --git a/src/test/ui/issues/issue-75907_b.stderr b/src/test/ui/issues/issue-75907_b.stderr index cdd21de6c33e4..8884484e18d81 100644 --- a/src/test/ui/issues/issue-75907_b.stderr +++ b/src/test/ui/issues/issue-75907_b.stderr @@ -1,4 +1,4 @@ -error[E0532]: expected tuple struct or tuple variant, found struct `Bar` +error[E0532]: cannot match against a tuple struct which contains private fields --> $DIR/issue-75907_b.rs:9:9 | LL | let Bar(x, y, z) = make_bar(); diff --git a/src/test/ui/rfc-2008-non-exhaustive/struct.rs b/src/test/ui/rfc-2008-non-exhaustive/struct.rs index 8cff35c4bc5ec..07e093c152d6b 100644 --- a/src/test/ui/rfc-2008-non-exhaustive/struct.rs +++ b/src/test/ui/rfc-2008-non-exhaustive/struct.rs @@ -18,7 +18,7 @@ fn main() { //~^ ERROR `..` required with struct marked as non-exhaustive let ts = TupleStruct(640, 480); - //~^ ERROR expected function, tuple struct or tuple variant, found struct `TupleStruct` [E0423] + //~^ ERROR cannot initialize a tuple struct which contains private fields [E0423] let ts_explicit = structs::TupleStruct(640, 480); //~^ ERROR tuple struct constructor `TupleStruct` is private [E0603] diff --git a/src/test/ui/rfc-2008-non-exhaustive/struct.stderr b/src/test/ui/rfc-2008-non-exhaustive/struct.stderr index 3bc38830537cf..e2ee8d6a6fe5e 100644 --- a/src/test/ui/rfc-2008-non-exhaustive/struct.stderr +++ b/src/test/ui/rfc-2008-non-exhaustive/struct.stderr @@ -1,4 +1,4 @@ -error[E0423]: expected function, tuple struct or tuple variant, found struct `TupleStruct` +error[E0423]: cannot initialize a tuple struct which contains private fields --> $DIR/struct.rs:20:14 | LL | let ts = TupleStruct(640, 480);