From 5ce3f4c16636b261a8ce9ddfbbb30896338b9e37 Mon Sep 17 00:00:00 2001 From: Camelid Date: Fri, 11 Dec 2020 19:52:51 -0800 Subject: [PATCH] Resolve enum field visibility correctly Previously, this code treated enum fields' visibility as if they were struct fields. However, that's not correct because the visibility of a struct field with `ast::VisibilityKind::Inherited` is private to the module it's defined in, whereas the visibility of an *enum* field with `ast::VisibilityKind::Inherited` is the visibility of the enum it belongs to. --- .../rustc_resolve/src/build_reduced_graph.rs | 11 ++++++- compiler/rustc_resolve/src/lib.rs | 1 + compiler/rustc_typeck/src/check/expr.rs | 4 +-- src/test/ui/issues/issue-79593.rs | 29 ++++++++++++++++ src/test/ui/issues/issue-79593.stderr | 33 +++++++++++++++++++ 5 files changed, 75 insertions(+), 3 deletions(-) create mode 100644 src/test/ui/issues/issue-79593.rs create mode 100644 src/test/ui/issues/issue-79593.stderr diff --git a/compiler/rustc_resolve/src/build_reduced_graph.rs b/compiler/rustc_resolve/src/build_reduced_graph.rs index 6d7e4ebc253..06e9969697d 100644 --- a/compiler/rustc_resolve/src/build_reduced_graph.rs +++ b/compiler/rustc_resolve/src/build_reduced_graph.rs @@ -258,7 +258,16 @@ fn resolve_visibility_speculative<'ast>( Ok(ty::Visibility::Restricted(DefId::local(CRATE_DEF_INDEX))) } ast::VisibilityKind::Inherited => { - Ok(ty::Visibility::Restricted(parent_scope.module.normal_ancestor_id)) + if matches!(self.parent_scope.module.kind, ModuleKind::Def(DefKind::Enum, _, _)) { + // Any inherited visibility resolved directly inside an enum + // (e.g. variants or fields) inherits from the visibility of the enum. + let parent_enum = self.parent_scope.module.def_id().unwrap().expect_local(); + Ok(self.r.visibilities[&parent_enum]) + } else { + // If it's not in an enum, its visibility is restricted to the `mod` item + // that it's defined in. + Ok(ty::Visibility::Restricted(self.parent_scope.module.normal_ancestor_id)) + } } ast::VisibilityKind::Restricted { ref path, id, .. } => { // For visibilities we are not ready to provide correct implementation of "uniform diff --git a/compiler/rustc_resolve/src/lib.rs b/compiler/rustc_resolve/src/lib.rs index e8a06265ada..f764fbc3f8d 100644 --- a/compiler/rustc_resolve/src/lib.rs +++ b/compiler/rustc_resolve/src/lib.rs @@ -403,6 +403,7 @@ enum PathResult<'a> { }, } +#[derive(Debug)] enum ModuleKind { /// An anonymous module; e.g., just a block. /// diff --git a/compiler/rustc_typeck/src/check/expr.rs b/compiler/rustc_typeck/src/check/expr.rs index b8a2a4779d9..ec0e039b5d2 100644 --- a/compiler/rustc_typeck/src/check/expr.rs +++ b/compiler/rustc_typeck/src/check/expr.rs @@ -1248,7 +1248,7 @@ fn check_expr_struct_fields( if no_accessible_remaining_fields { self.report_no_accessible_fields(adt_ty, span); } else { - self.report_missing_field(adt_ty, span, remaining_fields); + self.report_missing_fields(adt_ty, span, remaining_fields); } } @@ -1279,7 +1279,7 @@ fn check_struct_fields_on_error( /// /// error: aborting due to previous error /// ``` - fn report_missing_field( + fn report_missing_fields( &self, adt_ty: Ty<'tcx>, span: Span, diff --git a/src/test/ui/issues/issue-79593.rs b/src/test/ui/issues/issue-79593.rs new file mode 100644 index 00000000000..fb54b36940d --- /dev/null +++ b/src/test/ui/issues/issue-79593.rs @@ -0,0 +1,29 @@ +mod foo { + pub struct Pub { private: () } + + pub enum Enum { + Variant { x: (), y: () }, + Other + } + + fn correct() { + Pub {}; + //~^ ERROR missing field `private` in initializer of `Pub` + Enum::Variant { x: () }; + //~^ ERROR missing field `y` in initializer of `Enum` + } +} + +fn correct() { + foo::Pub {}; + //~^ ERROR cannot construct `Pub` with struct literal syntax due to inaccessible fields +} + +fn wrong() { + foo::Enum::Variant { x: () }; + //~^ ERROR missing field `y` in initializer of `Enum` + foo::Enum::Variant { }; + //~^ ERROR missing fields `x`, `y` in initializer of `Enum` +} + +fn main() {} diff --git a/src/test/ui/issues/issue-79593.stderr b/src/test/ui/issues/issue-79593.stderr new file mode 100644 index 00000000000..33dbd85032e --- /dev/null +++ b/src/test/ui/issues/issue-79593.stderr @@ -0,0 +1,33 @@ +error[E0063]: missing field `private` in initializer of `Pub` + --> $DIR/issue-79593.rs:10:9 + | +LL | Pub {}; + | ^^^ missing `private` + +error[E0063]: missing field `y` in initializer of `Enum` + --> $DIR/issue-79593.rs:12:9 + | +LL | Enum::Variant { x: () }; + | ^^^^^^^^^^^^^ missing `y` + +error: cannot construct `Pub` with struct literal syntax due to inaccessible fields + --> $DIR/issue-79593.rs:18:5 + | +LL | foo::Pub {}; + | ^^^^^^^^ + +error[E0063]: missing field `y` in initializer of `Enum` + --> $DIR/issue-79593.rs:23:5 + | +LL | foo::Enum::Variant { x: () }; + | ^^^^^^^^^^^^^^^^^^ missing `y` + +error[E0063]: missing fields `x`, `y` in initializer of `Enum` + --> $DIR/issue-79593.rs:25:5 + | +LL | foo::Enum::Variant { }; + | ^^^^^^^^^^^^^^^^^^ missing `x`, `y` + +error: aborting due to 5 previous errors + +For more information about this error, try `rustc --explain E0063`.