about summary refs log tree commit diff
diff options
context:
space:
mode:
authorbors <bors@rust-lang.org>2020-12-13 08:40:07 +0000
committerbors <bors@rust-lang.org>2020-12-13 08:40:07 +0000
commitd149b6579fb118ea75b16cb7a6afa62695d88992 (patch)
treeab9f532faa43571c4c195df281f8211d20e45db4
parent12813159a985d87a98578e05cc39200e4e8c2102 (diff)
parent5ce3f4c16636b261a8ce9ddfbbb30896338b9e37 (diff)
downloadrust-d149b6579fb118ea75b16cb7a6afa62695d88992.tar.gz
rust-d149b6579fb118ea75b16cb7a6afa62695d88992.zip
Auto merge of #79956 - camelid:variant-field-vis, r=petrochenkov
Resolve enum field visibility correctly

Fixes #79593. :tada:

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.
-rw-r--r--compiler/rustc_resolve/src/build_reduced_graph.rs11
-rw-r--r--compiler/rustc_resolve/src/lib.rs1
-rw-r--r--compiler/rustc_typeck/src/check/expr.rs4
-rw-r--r--src/test/ui/issues/issue-79593.rs29
-rw-r--r--src/test/ui/issues/issue-79593.stderr33
5 files changed, 75 insertions, 3 deletions
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 @@ impl<'a, 'b> BuildReducedGraphVisitor<'a, 'b> {
                 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 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
             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 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
     ///
     /// 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`.