Skip to content

Commit

Permalink
Rollup merge of rust-lang#85068 - luqmana:78708-xcrate-diag, r=estebank
Browse files Browse the repository at this point in the history
Fix diagnostic for cross crate private tuple struct constructors

Fixes rust-lang#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 rust-lang#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.
  • Loading branch information
GuillaumeGomez committed May 13, 2021
2 parents 17b60b8 + 89300cd commit 3db335b
Show file tree
Hide file tree
Showing 7 changed files with 83 additions and 14 deletions.
13 changes: 12 additions & 1 deletion compiler/rustc_metadata/src/rmeta/decoder.rs
Original file line number Diff line number Diff line change
Expand Up @@ -27,7 +27,7 @@ use rustc_middle::middle::exported_symbols::{ExportedSymbol, SymbolExportLevel};
use rustc_middle::mir::interpret::{AllocDecodingSession, AllocDecodingState};
use rustc_middle::mir::{self, Body, Promoted};
use rustc_middle::ty::codec::TyDecoder;
use rustc_middle::ty::{self, Ty, TyCtxt};
use rustc_middle::ty::{self, Ty, TyCtxt, Visibility};
use rustc_serialize::{opaque, Decodable, Decoder};
use rustc_session::Session;
use rustc_span::hygiene::ExpnDataDecodeMode;
Expand Down Expand Up @@ -1312,6 +1312,17 @@ impl<'a, 'tcx> CrateMetadataRef<'a> {
.collect()
}

fn get_struct_field_visibilities(&self, id: DefIndex) -> Vec<Visibility> {
self.root
.tables
.children
.get(self, id)
.unwrap_or_else(Lazy::empty)
.decode(self)
.map(|field_index| self.get_visibility(field_index))
.collect()
}

fn get_inherent_implementations_for_type(
&self,
tcx: TyCtxt<'tcx>,
Expand Down
18 changes: 16 additions & 2 deletions compiler/rustc_metadata/src/rmeta/decoder/cstore_impl.rs
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,7 @@ use rustc_ast::expand::allocator::AllocatorKind;
use rustc_data_structures::stable_map::FxHashMap;
use rustc_data_structures::svh::Svh;
use rustc_hir as hir;
use rustc_hir::def::DefKind;
use rustc_hir::def::{CtorKind, DefKind};
use rustc_hir::def_id::{CrateNum, DefId, DefIdMap, CRATE_DEF_INDEX, LOCAL_CRATE};
use rustc_hir::definitions::{DefKey, DefPath, DefPathHash};
use rustc_middle::hir::exports::Export;
Expand All @@ -17,7 +17,7 @@ use rustc_middle::middle::cstore::{CrateSource, CrateStore, EncodedMetadata};
use rustc_middle::middle::exported_symbols::ExportedSymbol;
use rustc_middle::middle::stability::DeprecationEntry;
use rustc_middle::ty::query::Providers;
use rustc_middle::ty::{self, TyCtxt};
use rustc_middle::ty::{self, TyCtxt, Visibility};
use rustc_session::utils::NativeLibKind;
use rustc_session::{CrateDisambiguator, Session};
use rustc_span::source_map::{Span, Spanned};
Expand Down Expand Up @@ -392,6 +392,20 @@ impl CStore {
self.get_crate_data(def.krate).get_struct_field_names(def.index, sess)
}

pub fn struct_field_visibilities_untracked(&self, def: DefId) -> Vec<Visibility> {
self.get_crate_data(def.krate).get_struct_field_visibilities(def.index)
}

pub fn ctor_def_id_and_kind_untracked(&self, def: DefId) -> Option<(DefId, CtorKind)> {
self.get_crate_data(def.krate).get_ctor_def_id(def.index).map(|ctor_def_id| {
(ctor_def_id, self.get_crate_data(def.krate).get_ctor_kind(def.index))
})
}

pub fn visibility_untracked(&self, def: DefId) -> Visibility {
self.get_crate_data(def.krate).get_visibility(def.index)
}

pub fn item_children_untracked(
&self,
def_id: DefId,
Expand Down
21 changes: 14 additions & 7 deletions compiler/rustc_resolve/src/build_reduced_graph.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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);
}
Expand All @@ -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![]));
}
}
_ => {}
}
}
Expand Down
12 changes: 12 additions & 0 deletions src/test/ui/issues/auxiliary/issue-75907.rs
Original file line number Diff line number Diff line change
Expand Up @@ -3,3 +3,15 @@ pub struct Bar(pub u8, u8, u8);
pub fn make_bar() -> Bar {
Bar(1, 12, 10)
}

mod inner {
pub struct Foo(u8, pub u8, u8);

impl Foo {
pub fn new() -> Foo {
Foo(1, 12, 10)
}
}
}

pub use inner::Foo;
5 changes: 4 additions & 1 deletion src/test/ui/issues/issue-75907_b.rs
Original file line number Diff line number Diff line change
Expand Up @@ -3,9 +3,12 @@

extern crate issue_75907 as a;

use a::{make_bar, Bar};
use a::{make_bar, Bar, Foo};

fn main() {
let Bar(x, y, z) = make_bar();
//~^ ERROR cannot match against a tuple struct which contains private fields

let Foo(x, y, z) = Foo::new();
//~^ ERROR cannot match against a tuple struct which contains private fields
}
26 changes: 24 additions & 2 deletions src/test/ui/issues/issue-75907_b.stderr
Original file line number Diff line number Diff line change
Expand Up @@ -2,8 +2,30 @@ 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();
| ^^^ constructor is not visible here due to private fields
| ^^^
|
note: constructor is not visible here due to private fields
--> $DIR/issue-75907_b.rs:9:16
|
LL | let Bar(x, y, z) = make_bar();
| ^ ^ private field
| |
| private field

error[E0532]: cannot match against a tuple struct which contains private fields
--> $DIR/issue-75907_b.rs:12:9
|
LL | let Foo(x, y, z) = Foo::new();
| ^^^
|
note: constructor is not visible here due to private fields
--> $DIR/issue-75907_b.rs:12:13
|
LL | let Foo(x, y, z) = Foo::new();
| ^ ^ private field
| |
| private field

error: aborting due to previous error
error: aborting due to 2 previous errors

For more information about this error, try `rustc --explain E0532`.
2 changes: 1 addition & 1 deletion src/test/ui/rfc-2008-non-exhaustive/struct.stderr
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@ error[E0423]: cannot initialize a tuple struct which contains private fields
--> $DIR/struct.rs:20:14
|
LL | let ts = TupleStruct(640, 480);
| ^^^^^^^^^^^ constructor is not visible here due to private fields
| ^^^^^^^^^^^

error[E0423]: expected value, found struct `UnitStruct`
--> $DIR/struct.rs:29:14
Expand Down

0 comments on commit 3db335b

Please sign in to comment.