From 00d54c879bfb6adb5b7a611af6bd522499d07a1d Mon Sep 17 00:00:00 2001 From: Michael Goulet Date: Thu, 6 Apr 2023 16:49:43 +0000 Subject: [PATCH 1/2] Label non_exhaustive on privacy errors --- compiler/rustc_resolve/src/diagnostics.rs | 8 +++++- .../ui/rfc-2008-non-exhaustive/struct.stderr | 11 +++++--- .../ui/rfc-2008-non-exhaustive/variant.stderr | 25 +++++++++++++++++++ 3 files changed, 40 insertions(+), 4 deletions(-) diff --git a/compiler/rustc_resolve/src/diagnostics.rs b/compiler/rustc_resolve/src/diagnostics.rs index e69a9d0aeca..bb473d62a7b 100644 --- a/compiler/rustc_resolve/src/diagnostics.rs +++ b/compiler/rustc_resolve/src/diagnostics.rs @@ -1607,7 +1607,13 @@ fn report_privacy_error(&self, privacy_error: &PrivacyError<'_>) { let mut err = struct_span_err!(self.tcx.sess, ident.span, E0603, "{} `{}` is private", descr, ident); err.span_label(ident.span, &format!("private {}", descr)); - if let Some(span) = ctor_fields_span { + + if let Some(def_id) = res.opt_def_id() + && !def_id.is_local() + && let Some(attr) = self.tcx.get_attr(def_id, sym::non_exhaustive) + { + err.span_label(attr.span, format!("the {nonimport_descr} is `#[non_exhaustive]`")); + } else if let Some(span) = ctor_fields_span { err.span_label(span, "a constructor is private if any of the fields is private"); if let Res::Def(_, d) = res && let Some(fields) = self.field_visibility_spans.get(&d) { err.multipart_suggestion_verbose( diff --git a/tests/ui/rfc-2008-non-exhaustive/struct.stderr b/tests/ui/rfc-2008-non-exhaustive/struct.stderr index 2cb9ba0d1d1..36154fe51a4 100644 --- a/tests/ui/rfc-2008-non-exhaustive/struct.stderr +++ b/tests/ui/rfc-2008-non-exhaustive/struct.stderr @@ -10,10 +10,10 @@ error[E0603]: tuple struct constructor `TupleStruct` is private LL | let ts_explicit = structs::TupleStruct(640, 480); | ^^^^^^^^^^^ private tuple struct constructor | - ::: $DIR/auxiliary/structs.rs:12:24 + ::: $DIR/auxiliary/structs.rs:11:1 | -LL | pub struct TupleStruct(pub u16, pub u16); - | ---------------- a constructor is private if any of the fields is private +LL | #[non_exhaustive] + | ----------------- the tuple struct constructor is `#[non_exhaustive]` | note: the tuple struct constructor `TupleStruct` is defined here --> $DIR/auxiliary/structs.rs:12:1 @@ -27,6 +27,11 @@ error[E0603]: unit struct `UnitStruct` is private LL | let us_explicit = structs::UnitStruct; | ^^^^^^^^^^ private unit struct | + ::: $DIR/auxiliary/structs.rs:8:1 + | +LL | #[non_exhaustive] + | ----------------- the unit struct is `#[non_exhaustive]` + | note: the unit struct `UnitStruct` is defined here --> $DIR/auxiliary/structs.rs:9:1 | diff --git a/tests/ui/rfc-2008-non-exhaustive/variant.stderr b/tests/ui/rfc-2008-non-exhaustive/variant.stderr index 720b7b119ce..551ecb5acf2 100644 --- a/tests/ui/rfc-2008-non-exhaustive/variant.stderr +++ b/tests/ui/rfc-2008-non-exhaustive/variant.stderr @@ -4,6 +4,11 @@ error[E0603]: tuple variant `Tuple` is private LL | let variant_tuple = NonExhaustiveVariants::Tuple(640); | ^^^^^ private tuple variant | + ::: $DIR/auxiliary/variants.rs:5:5 + | +LL | #[non_exhaustive] Tuple(u32), + | ----------------- the tuple variant is `#[non_exhaustive]` + | note: the tuple variant `Tuple` is defined here --> $DIR/auxiliary/variants.rs:5:23 | @@ -16,6 +21,11 @@ error[E0603]: unit variant `Unit` is private LL | let variant_unit = NonExhaustiveVariants::Unit; | ^^^^ private unit variant | + ::: $DIR/auxiliary/variants.rs:4:5 + | +LL | #[non_exhaustive] Unit, + | ----------------- the unit variant is `#[non_exhaustive]` + | note: the unit variant `Unit` is defined here --> $DIR/auxiliary/variants.rs:4:23 | @@ -28,6 +38,11 @@ error[E0603]: unit variant `Unit` is private LL | NonExhaustiveVariants::Unit => "", | ^^^^ private unit variant | + ::: $DIR/auxiliary/variants.rs:4:5 + | +LL | #[non_exhaustive] Unit, + | ----------------- the unit variant is `#[non_exhaustive]` + | note: the unit variant `Unit` is defined here --> $DIR/auxiliary/variants.rs:4:23 | @@ -40,6 +55,11 @@ error[E0603]: tuple variant `Tuple` is private LL | NonExhaustiveVariants::Tuple(fe_tpl) => "", | ^^^^^ private tuple variant | + ::: $DIR/auxiliary/variants.rs:5:5 + | +LL | #[non_exhaustive] Tuple(u32), + | ----------------- the tuple variant is `#[non_exhaustive]` + | note: the tuple variant `Tuple` is defined here --> $DIR/auxiliary/variants.rs:5:23 | @@ -52,6 +72,11 @@ error[E0603]: tuple variant `Tuple` is private LL | if let NonExhaustiveVariants::Tuple(fe_tpl) = variant_struct { | ^^^^^ private tuple variant | + ::: $DIR/auxiliary/variants.rs:5:5 + | +LL | #[non_exhaustive] Tuple(u32), + | ----------------- the tuple variant is `#[non_exhaustive]` + | note: the tuple variant `Tuple` is defined here --> $DIR/auxiliary/variants.rs:5:23 | From 8ed2dc0bcee8c7ca43d2b6a66c9743cacf8dcddf Mon Sep 17 00:00:00 2001 From: Michael Goulet Date: Thu, 6 Apr 2023 16:52:17 +0000 Subject: [PATCH 2/2] Make span a bit better --- compiler/rustc_resolve/src/diagnostics.rs | 14 +++++- .../ui/rfc-2008-non-exhaustive/struct.stderr | 14 ++---- .../ui/rfc-2008-non-exhaustive/variant.stderr | 45 +++++++------------ 3 files changed, 32 insertions(+), 41 deletions(-) diff --git a/compiler/rustc_resolve/src/diagnostics.rs b/compiler/rustc_resolve/src/diagnostics.rs index bb473d62a7b..0c9d306081e 100644 --- a/compiler/rustc_resolve/src/diagnostics.rs +++ b/compiler/rustc_resolve/src/diagnostics.rs @@ -1608,11 +1608,15 @@ fn report_privacy_error(&self, privacy_error: &PrivacyError<'_>) { struct_span_err!(self.tcx.sess, ident.span, E0603, "{} `{}` is private", descr, ident); err.span_label(ident.span, &format!("private {}", descr)); + let mut non_exhaustive = None; + // If an ADT is foreign and marked as `non_exhaustive`, then that's + // probably why we have the privacy error. + // Otherwise, point out if the struct has any private fields. if let Some(def_id) = res.opt_def_id() && !def_id.is_local() && let Some(attr) = self.tcx.get_attr(def_id, sym::non_exhaustive) { - err.span_label(attr.span, format!("the {nonimport_descr} is `#[non_exhaustive]`")); + non_exhaustive = Some(attr.span); } else if let Some(span) = ctor_fields_span { err.span_label(span, "a constructor is private if any of the fields is private"); if let Res::Def(_, d) = res && let Some(fields) = self.field_visibility_spans.get(&d) { @@ -1662,6 +1666,14 @@ fn report_privacy_error(&self, privacy_error: &PrivacyError<'_>) { if !first && binding.vis.is_public() { note_span.push_span_label(def_span, "consider importing it directly"); } + // Final step in the import chain, point out if the ADT is `non_exhaustive` + // which is probably why this privacy violation occurred. + if next_binding.is_none() && let Some(span) = non_exhaustive { + note_span.push_span_label( + span, + format!("cannot be constructed because it is `#[non_exhaustive]`"), + ); + } err.span_note(note_span, &msg); } diff --git a/tests/ui/rfc-2008-non-exhaustive/struct.stderr b/tests/ui/rfc-2008-non-exhaustive/struct.stderr index 36154fe51a4..39b1ef1e078 100644 --- a/tests/ui/rfc-2008-non-exhaustive/struct.stderr +++ b/tests/ui/rfc-2008-non-exhaustive/struct.stderr @@ -10,14 +10,11 @@ error[E0603]: tuple struct constructor `TupleStruct` is private LL | let ts_explicit = structs::TupleStruct(640, 480); | ^^^^^^^^^^^ private tuple struct constructor | - ::: $DIR/auxiliary/structs.rs:11:1 - | -LL | #[non_exhaustive] - | ----------------- the tuple struct constructor is `#[non_exhaustive]` - | note: the tuple struct constructor `TupleStruct` is defined here --> $DIR/auxiliary/structs.rs:12:1 | +LL | #[non_exhaustive] + | ----------------- cannot be constructed because it is `#[non_exhaustive]` LL | pub struct TupleStruct(pub u16, pub u16); | ^^^^^^^^^^^^^^^^^^^^^^ @@ -27,14 +24,11 @@ error[E0603]: unit struct `UnitStruct` is private LL | let us_explicit = structs::UnitStruct; | ^^^^^^^^^^ private unit struct | - ::: $DIR/auxiliary/structs.rs:8:1 - | -LL | #[non_exhaustive] - | ----------------- the unit struct is `#[non_exhaustive]` - | note: the unit struct `UnitStruct` is defined here --> $DIR/auxiliary/structs.rs:9:1 | +LL | #[non_exhaustive] + | ----------------- cannot be constructed because it is `#[non_exhaustive]` LL | pub struct UnitStruct; | ^^^^^^^^^^^^^^^^^^^^^ diff --git a/tests/ui/rfc-2008-non-exhaustive/variant.stderr b/tests/ui/rfc-2008-non-exhaustive/variant.stderr index 551ecb5acf2..4083f57a9cd 100644 --- a/tests/ui/rfc-2008-non-exhaustive/variant.stderr +++ b/tests/ui/rfc-2008-non-exhaustive/variant.stderr @@ -4,16 +4,13 @@ error[E0603]: tuple variant `Tuple` is private LL | let variant_tuple = NonExhaustiveVariants::Tuple(640); | ^^^^^ private tuple variant | - ::: $DIR/auxiliary/variants.rs:5:5 - | -LL | #[non_exhaustive] Tuple(u32), - | ----------------- the tuple variant is `#[non_exhaustive]` - | note: the tuple variant `Tuple` is defined here --> $DIR/auxiliary/variants.rs:5:23 | LL | #[non_exhaustive] Tuple(u32), - | ^^^^^ + | ----------------- ^^^^^ + | | + | cannot be constructed because it is `#[non_exhaustive]` error[E0603]: unit variant `Unit` is private --> $DIR/variant.rs:14:47 @@ -21,16 +18,13 @@ error[E0603]: unit variant `Unit` is private LL | let variant_unit = NonExhaustiveVariants::Unit; | ^^^^ private unit variant | - ::: $DIR/auxiliary/variants.rs:4:5 - | -LL | #[non_exhaustive] Unit, - | ----------------- the unit variant is `#[non_exhaustive]` - | note: the unit variant `Unit` is defined here --> $DIR/auxiliary/variants.rs:4:23 | LL | #[non_exhaustive] Unit, - | ^^^^ + | ----------------- ^^^^ + | | + | cannot be constructed because it is `#[non_exhaustive]` error[E0603]: unit variant `Unit` is private --> $DIR/variant.rs:18:32 @@ -38,16 +32,13 @@ error[E0603]: unit variant `Unit` is private LL | NonExhaustiveVariants::Unit => "", | ^^^^ private unit variant | - ::: $DIR/auxiliary/variants.rs:4:5 - | -LL | #[non_exhaustive] Unit, - | ----------------- the unit variant is `#[non_exhaustive]` - | note: the unit variant `Unit` is defined here --> $DIR/auxiliary/variants.rs:4:23 | LL | #[non_exhaustive] Unit, - | ^^^^ + | ----------------- ^^^^ + | | + | cannot be constructed because it is `#[non_exhaustive]` error[E0603]: tuple variant `Tuple` is private --> $DIR/variant.rs:20:32 @@ -55,16 +46,13 @@ error[E0603]: tuple variant `Tuple` is private LL | NonExhaustiveVariants::Tuple(fe_tpl) => "", | ^^^^^ private tuple variant | - ::: $DIR/auxiliary/variants.rs:5:5 - | -LL | #[non_exhaustive] Tuple(u32), - | ----------------- the tuple variant is `#[non_exhaustive]` - | note: the tuple variant `Tuple` is defined here --> $DIR/auxiliary/variants.rs:5:23 | LL | #[non_exhaustive] Tuple(u32), - | ^^^^^ + | ----------------- ^^^^^ + | | + | cannot be constructed because it is `#[non_exhaustive]` error[E0603]: tuple variant `Tuple` is private --> $DIR/variant.rs:26:35 @@ -72,16 +60,13 @@ error[E0603]: tuple variant `Tuple` is private LL | if let NonExhaustiveVariants::Tuple(fe_tpl) = variant_struct { | ^^^^^ private tuple variant | - ::: $DIR/auxiliary/variants.rs:5:5 - | -LL | #[non_exhaustive] Tuple(u32), - | ----------------- the tuple variant is `#[non_exhaustive]` - | note: the tuple variant `Tuple` is defined here --> $DIR/auxiliary/variants.rs:5:23 | LL | #[non_exhaustive] Tuple(u32), - | ^^^^^ + | ----------------- ^^^^^ + | | + | cannot be constructed because it is `#[non_exhaustive]` error[E0639]: cannot create non-exhaustive variant using struct expression --> $DIR/variant.rs:8:26