about summary refs log tree commit diff
path: root/compiler/rustc_resolve/src
diff options
context:
space:
mode:
authorGuillaume Gomez <guillaume1.gomez@gmail.com>2021-05-13 15:54:10 +0200
committerGitHub <noreply@github.com>2021-05-13 15:54:10 +0200
commit3db335b934d31cf3bdaaa248ca34aa25ef67f366 (patch)
tree8b174dffaf31aceca6b2128c6b418606d8d3c0bc /compiler/rustc_resolve/src
parent17b60b8738735d8d64d03601d1dad4001d1e5733 (diff)
parent89300cdebc4f888f64b142a2393623c502cfe3fe (diff)
downloadrust-3db335b934d31cf3bdaaa248ca34aa25ef67f366.tar.gz
rust-3db335b934d31cf3bdaaa248ca34aa25ef67f366.zip
Rollup merge of #85068 - luqmana:78708-xcrate-diag, r=estebank
Fix diagnostic for cross crate private tuple struct constructors

Fixes #78708.

There was already some limited support for certain cross-crate scenarios but that didn't handle a tuple struct rexported from an inner module for example (e.g. the NonZero* types as seen in #85049).

```Rust
➜  cat bug.rs
fn main() {
    let _x = std::num::NonZeroU32(12);
    let n = std::num::NonZeroU32::new(1).unwrap();
    match n {
        std::num::NonZeroU32(i) => {},
    }
}
```

**Before:**
<details>

```Rust
➜  rustc +nightly bug.rs
error[E0423]: expected function, tuple struct or tuple variant, found struct `std::num::NonZeroU32`
   --> bug.rs:2:14
    |
2   |       let _x = std::num::NonZeroU32(12);
    |                ^^^^^^^^^^^^^^^^^^^^^^^^ help: use struct literal syntax instead: `std::num::NonZeroU32 { 0: val }`
    |
   ::: /home/luqman/.rustup/toolchains/nightly-x86_64-unknown-linux-gnu/lib/rustlib/src/rust/library/core/src/num/nonzero.rs:148:1
[snip]
error[E0532]: expected tuple struct or tuple variant, found struct `std::num::NonZeroU32`
   --> bug.rs:5:9
    |
5   |           std::num::NonZeroU32(i) => {},
    |           ^^^^^^^^^^^^^^^^^^^^^^^ help: use struct pattern syntax instead: `std::num::NonZeroU32 { 0 }`
    |
   ::: /home/luqman/.rustup/toolchains/nightly-x86_64-unknown-linux-gnu/lib/rustlib/src/rust/library/core/src/num/nonzero.rs:148:1
[snip]

error: aborting due to 2 previous errors

Some errors have detailed explanations: E0423, E0532.
For more information about an error, try `rustc --explain E0423`.
```
</details>

**After:**
<details>

```Rust
➜  /rust/build/x86_64-unknown-linux-gnu/stage1/bin/rustc bug.rs
error[E0423]: cannot initialize a tuple struct which contains private fields
   --> bug.rs:2:14
    |
2   |     let _x = std::num::NonZeroU32(12);
    |              ^^^^^^^^^^^^^^^^^^^^
    |
note: constructor is not visible here due to private fields
   --> /rust/library/core/src/num/nonzero.rs:148:1
[snip]
error[E0532]: cannot match against a tuple struct which contains private fields
 --> bug.rs:5:9
  |
5 |         std::num::NonZeroU32(i) => {},
  |         ^^^^^^^^^^^^^^^^^^^^
  |
note: constructor is not visible here due to private fields
 --> bug.rs:5:30
  |
5 |         std::num::NonZeroU32(i) => {},
  |                              ^ private field

error: aborting due to 2 previous errors

Some errors have detailed explanations: E0423, E0532.
For more information about an error, try `rustc --explain E0423`.
```
</details>

One question is if we should only collect the needed info for the cross-crate case after encountering an error instead of always doing it. Perf run perhaps to gauge the impact.
Diffstat (limited to 'compiler/rustc_resolve/src')
-rw-r--r--compiler/rustc_resolve/src/build_reduced_graph.rs21
1 files changed, 14 insertions, 7 deletions
diff --git a/compiler/rustc_resolve/src/build_reduced_graph.rs b/compiler/rustc_resolve/src/build_reduced_graph.rs
index b5c95cfcb29..e10314a11fc 100644
--- a/compiler/rustc_resolve/src/build_reduced_graph.rs
+++ b/compiler/rustc_resolve/src/build_reduced_graph.rs
@@ -995,7 +995,20 @@ impl<'a, 'b> BuildReducedGraphVisitor<'a, 'b> {
         // Record some extra data for better diagnostics.
         let cstore = self.r.cstore();
         match res {
-            Res::Def(DefKind::Struct | DefKind::Union, def_id) => {
+            Res::Def(DefKind::Struct, def_id) => {
+                let field_names = cstore.struct_field_names_untracked(def_id, self.r.session);
+                let ctor = cstore.ctor_def_id_and_kind_untracked(def_id);
+                if let Some((ctor_def_id, ctor_kind)) = ctor {
+                    let ctor_res = Res::Def(DefKind::Ctor(CtorOf::Struct, ctor_kind), ctor_def_id);
+                    let ctor_vis = cstore.visibility_untracked(ctor_def_id);
+                    let field_visibilities = cstore.struct_field_visibilities_untracked(def_id);
+                    self.r
+                        .struct_constructors
+                        .insert(def_id, (ctor_res, ctor_vis, field_visibilities));
+                }
+                self.insert_field_names(def_id, field_names);
+            }
+            Res::Def(DefKind::Union, def_id) => {
                 let field_names = cstore.struct_field_names_untracked(def_id, self.r.session);
                 self.insert_field_names(def_id, field_names);
             }
@@ -1007,12 +1020,6 @@ impl<'a, 'b> BuildReducedGraphVisitor<'a, 'b> {
                     self.r.has_self.insert(def_id);
                 }
             }
-            Res::Def(DefKind::Ctor(CtorOf::Struct, ..), def_id) => {
-                let parent = cstore.def_key(def_id).parent;
-                if let Some(struct_def_id) = parent.map(|index| DefId { index, ..def_id }) {
-                    self.r.struct_constructors.insert(struct_def_id, (res, vis, vec![]));
-                }
-            }
             _ => {}
         }
     }