Skip to content

Commit bbbd48f

Browse files
committed
Auto merge of #90358 - DevinR528:omitted-field-fix, r=jackh726
Fix exposing fields marked unstable or doc hidden Closes #89837 Work towards #89554 Filter fields that are marked `doc(hidden)` or are unstable with that feature turned off. This brings structs and enums into alignment behavior-wise when emitting warning/errors about pattern exhaustiveness/reachability. cc `@Nadrieril`
2 parents f103b29 + 492d8d7 commit bbbd48f

21 files changed

+422
-79
lines changed

compiler/rustc_mir_build/src/thir/pattern/deconstruct_pat.rs

+3-3
Original file line numberDiff line numberDiff line change
@@ -692,11 +692,11 @@ impl<'tcx> Constructor<'tcx> {
692692
}
693693

694694
/// Checks if the `Constructor` is a `Constructor::Variant` with a `#[doc(hidden)]`
695-
/// attribute.
695+
/// attribute from a type not local to the current crate.
696696
pub(super) fn is_doc_hidden_variant(&self, pcx: PatCtxt<'_, '_, 'tcx>) -> bool {
697697
if let Constructor::Variant(idx) = self && let ty::Adt(adt, _) = pcx.ty.kind() {
698-
let variant_def_id = adt.variant(*idx).def_id;
699-
return pcx.cx.tcx.is_doc_hidden(variant_def_id);
698+
let variant_def_id = adt.variants()[*idx].def_id;
699+
return pcx.cx.tcx.is_doc_hidden(variant_def_id) && !variant_def_id.is_local();
700700
}
701701
false
702702
}

compiler/rustc_typeck/src/check/pat.rs

+7
Original file line numberDiff line numberDiff line change
@@ -11,6 +11,7 @@ use rustc_hir::pat_util::EnumerateAndAdjustIterator;
1111
use rustc_hir::{HirId, Pat, PatKind};
1212
use rustc_infer::infer;
1313
use rustc_infer::infer::type_variable::{TypeVariableOrigin, TypeVariableOriginKind};
14+
use rustc_middle::middle::stability::EvalResult;
1415
use rustc_middle::ty::{self, Adt, BindingMode, Ty, TypeFoldable};
1516
use rustc_session::lint::builtin::NON_EXHAUSTIVE_OMITTED_PATTERNS;
1617
use rustc_span::hygiene::DesugaringKind;
@@ -1308,6 +1309,12 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
13081309
.copied()
13091310
.filter(|(field, _)| {
13101311
field.vis.is_accessible_from(tcx.parent_module(pat.hir_id).to_def_id(), tcx)
1312+
&& !matches!(
1313+
tcx.eval_stability(field.did, None, DUMMY_SP, None),
1314+
EvalResult::Deny { .. }
1315+
)
1316+
// We only want to report the error if it is hidden and not local
1317+
&& !(tcx.is_doc_hidden(field.did) && !field.did.is_local())
13111318
})
13121319
.collect();
13131320

Original file line numberDiff line numberDiff line change
@@ -1,6 +1,14 @@
1-
pub enum Foo {
1+
pub enum HiddenEnum {
22
A,
33
B,
44
#[doc(hidden)]
55
C,
66
}
7+
8+
#[derive(Default)]
9+
pub struct HiddenStruct {
10+
pub one: u8,
11+
pub two: bool,
12+
#[doc(hidden)]
13+
pub hide: usize,
14+
}

src/test/ui/pattern/usefulness/auxiliary/unstable.rs

+12-1
Original file line numberDiff line numberDiff line change
@@ -2,11 +2,22 @@
22
#![stable(feature = "stable_test_feature", since = "1.0.0")]
33

44
#[stable(feature = "stable_test_feature", since = "1.0.0")]
5-
pub enum Foo {
5+
pub enum UnstableEnum {
66
#[stable(feature = "stable_test_feature", since = "1.0.0")]
77
Stable,
88
#[stable(feature = "stable_test_feature", since = "1.0.0")]
99
Stable2,
1010
#[unstable(feature = "unstable_test_feature", issue = "none")]
1111
Unstable,
1212
}
13+
14+
#[derive(Default)]
15+
#[stable(feature = "stable_test_feature", since = "1.0.0")]
16+
pub struct UnstableStruct {
17+
#[stable(feature = "stable_test_feature", since = "1.0.0")]
18+
pub stable: bool,
19+
#[stable(feature = "stable_test_feature", since = "1.0.0")]
20+
pub stable2: usize,
21+
#[unstable(feature = "unstable_test_feature", issue = "none")]
22+
pub unstable: u8,
23+
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,26 @@
1+
// aux-build:hidden.rs
2+
3+
extern crate hidden;
4+
5+
use hidden::HiddenStruct;
6+
7+
struct InCrate {
8+
a: usize,
9+
b: bool,
10+
#[doc(hidden)]
11+
im_hidden: u8
12+
}
13+
14+
fn main() {
15+
let HiddenStruct { one, two } = HiddenStruct::default();
16+
//~^ pattern requires `..` due to inaccessible fields
17+
18+
let HiddenStruct { one } = HiddenStruct::default();
19+
//~^ pattern does not mention field `two` and inaccessible fields
20+
21+
let HiddenStruct { one, hide } = HiddenStruct::default();
22+
//~^ pattern does not mention field `two`
23+
24+
let InCrate { a, b } = InCrate { a: 0, b: false, im_hidden: 0 };
25+
//~^ pattern does not mention field `im_hidden`
26+
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,59 @@
1+
error: pattern requires `..` due to inaccessible fields
2+
--> $DIR/doc-hidden-fields.rs:15:9
3+
|
4+
LL | let HiddenStruct { one, two } = HiddenStruct::default();
5+
| ^^^^^^^^^^^^^^^^^^^^^^^^^
6+
|
7+
help: ignore the inaccessible and unused fields
8+
|
9+
LL | let HiddenStruct { one, two, .. } = HiddenStruct::default();
10+
| ++++
11+
12+
error[E0027]: pattern does not mention field `two` and inaccessible fields
13+
--> $DIR/doc-hidden-fields.rs:18:9
14+
|
15+
LL | let HiddenStruct { one } = HiddenStruct::default();
16+
| ^^^^^^^^^^^^^^^^^^^^ missing field `two` and inaccessible fields
17+
|
18+
help: include the missing field in the pattern and ignore the inaccessible fields
19+
|
20+
LL | let HiddenStruct { one, two, .. } = HiddenStruct::default();
21+
| ~~~~~~~~~~~
22+
help: if you don't care about this missing field, you can explicitly ignore it
23+
|
24+
LL | let HiddenStruct { one, .. } = HiddenStruct::default();
25+
| ~~~~~~
26+
27+
error[E0027]: pattern does not mention field `two`
28+
--> $DIR/doc-hidden-fields.rs:21:9
29+
|
30+
LL | let HiddenStruct { one, hide } = HiddenStruct::default();
31+
| ^^^^^^^^^^^^^^^^^^^^^^^^^^ missing field `two`
32+
|
33+
help: include the missing field in the pattern
34+
|
35+
LL | let HiddenStruct { one, hide, two } = HiddenStruct::default();
36+
| ~~~~~~~
37+
help: if you don't care about this missing field, you can explicitly ignore it
38+
|
39+
LL | let HiddenStruct { one, hide, .. } = HiddenStruct::default();
40+
| ~~~~~~
41+
42+
error[E0027]: pattern does not mention field `im_hidden`
43+
--> $DIR/doc-hidden-fields.rs:24:9
44+
|
45+
LL | let InCrate { a, b } = InCrate { a: 0, b: false, im_hidden: 0 };
46+
| ^^^^^^^^^^^^^^^^ missing field `im_hidden`
47+
|
48+
help: include the missing field in the pattern
49+
|
50+
LL | let InCrate { a, b, im_hidden } = InCrate { a: 0, b: false, im_hidden: 0 };
51+
| ~~~~~~~~~~~~~
52+
help: if you don't care about this missing field, you can explicitly ignore it
53+
|
54+
LL | let InCrate { a, b, .. } = InCrate { a: 0, b: false, im_hidden: 0 };
55+
| ~~~~~~
56+
57+
error: aborting due to 4 previous errors
58+
59+
For more information about this error, try `rustc --explain E0027`.

src/test/ui/pattern/usefulness/doc-hidden-non-exhaustive.rs

+23-10
Original file line numberDiff line numberDiff line change
@@ -2,29 +2,42 @@
22

33
extern crate hidden;
44

5-
use hidden::Foo;
5+
use hidden::HiddenEnum;
6+
7+
enum InCrate {
8+
A,
9+
B,
10+
#[doc(hidden)]
11+
C,
12+
}
613

714
fn main() {
8-
match Foo::A {
9-
Foo::A => {}
10-
Foo::B => {}
15+
match HiddenEnum::A {
16+
HiddenEnum::A => {}
17+
HiddenEnum::B => {}
1118
}
1219
//~^^^^ non-exhaustive patterns: `_` not covered
1320

14-
match Foo::A {
15-
Foo::A => {}
16-
Foo::C => {}
21+
match HiddenEnum::A {
22+
HiddenEnum::A => {}
23+
HiddenEnum::C => {}
1724
}
1825
//~^^^^ non-exhaustive patterns: `B` not covered
1926

20-
match Foo::A {
21-
Foo::A => {}
27+
match HiddenEnum::A {
28+
HiddenEnum::A => {}
2229
}
2330
//~^^^ non-exhaustive patterns: `B` and `_` not covered
2431

2532
match None {
2633
None => {}
27-
Some(Foo::A) => {}
34+
Some(HiddenEnum::A) => {}
2835
}
2936
//~^^^^ non-exhaustive patterns: `Some(B)` and `Some(_)` not covered
37+
38+
match InCrate::A {
39+
InCrate::A => {}
40+
InCrate::B => {}
41+
}
42+
//~^^^^ non-exhaustive patterns: `C` not covered
3043
}
Original file line numberDiff line numberDiff line change
@@ -1,81 +1,81 @@
11
error[E0004]: non-exhaustive patterns: `_` not covered
2-
--> $DIR/doc-hidden-non-exhaustive.rs:8:11
2+
--> $DIR/doc-hidden-non-exhaustive.rs:15:11
33
|
4-
LL | match Foo::A {
5-
| ^^^^^^ pattern `_` not covered
4+
LL | match HiddenEnum::A {
5+
| ^^^^^^^^^^^^^ pattern `_` not covered
66
|
7-
note: `Foo` defined here
7+
note: `HiddenEnum` defined here
88
--> $DIR/auxiliary/hidden.rs:1:1
99
|
10-
LL | / pub enum Foo {
10+
LL | / pub enum HiddenEnum {
1111
LL | | A,
1212
LL | | B,
1313
LL | | #[doc(hidden)]
1414
LL | | C,
1515
LL | | }
1616
| |_^
17-
= note: the matched value is of type `Foo`
17+
= note: the matched value is of type `HiddenEnum`
1818
help: ensure that all possible cases are being handled by adding a match arm with a wildcard pattern or an explicit pattern as shown
1919
|
20-
LL ~ Foo::B => {}
20+
LL ~ HiddenEnum::B => {}
2121
LL + _ => todo!()
2222
|
2323

2424
error[E0004]: non-exhaustive patterns: `B` not covered
25-
--> $DIR/doc-hidden-non-exhaustive.rs:14:11
25+
--> $DIR/doc-hidden-non-exhaustive.rs:21:11
2626
|
27-
LL | match Foo::A {
28-
| ^^^^^^ pattern `B` not covered
27+
LL | match HiddenEnum::A {
28+
| ^^^^^^^^^^^^^ pattern `B` not covered
2929
|
30-
note: `Foo` defined here
30+
note: `HiddenEnum` defined here
3131
--> $DIR/auxiliary/hidden.rs:3:5
3232
|
33-
LL | / pub enum Foo {
33+
LL | / pub enum HiddenEnum {
3434
LL | | A,
3535
LL | | B,
3636
| | ^ not covered
3737
LL | | #[doc(hidden)]
3838
LL | | C,
3939
LL | | }
4040
| |_-
41-
= note: the matched value is of type `Foo`
41+
= note: the matched value is of type `HiddenEnum`
4242
help: ensure that all possible cases are being handled by adding a match arm with a wildcard pattern or an explicit pattern as shown
4343
|
44-
LL ~ Foo::C => {}
44+
LL ~ HiddenEnum::C => {}
4545
LL + B => todo!()
4646
|
4747

4848
error[E0004]: non-exhaustive patterns: `B` and `_` not covered
49-
--> $DIR/doc-hidden-non-exhaustive.rs:20:11
49+
--> $DIR/doc-hidden-non-exhaustive.rs:27:11
5050
|
51-
LL | match Foo::A {
52-
| ^^^^^^ patterns `B` and `_` not covered
51+
LL | match HiddenEnum::A {
52+
| ^^^^^^^^^^^^^ patterns `B` and `_` not covered
5353
|
54-
note: `Foo` defined here
54+
note: `HiddenEnum` defined here
5555
--> $DIR/auxiliary/hidden.rs:3:5
5656
|
57-
LL | / pub enum Foo {
57+
LL | / pub enum HiddenEnum {
5858
LL | | A,
5959
LL | | B,
6060
| | ^ not covered
6161
LL | | #[doc(hidden)]
6262
LL | | C,
6363
LL | | }
6464
| |_-
65-
= note: the matched value is of type `Foo`
65+
= note: the matched value is of type `HiddenEnum`
6666
help: ensure that all possible cases are being handled by adding a match arm with a wildcard pattern, a match arm with multiple or-patterns as shown, or multiple match arms
6767
|
68-
LL ~ Foo::A => {}
68+
LL ~ HiddenEnum::A => {}
6969
LL + B | _ => todo!()
7070
|
7171

7272
error[E0004]: non-exhaustive patterns: `Some(B)` and `Some(_)` not covered
73-
--> $DIR/doc-hidden-non-exhaustive.rs:25:11
73+
--> $DIR/doc-hidden-non-exhaustive.rs:32:11
7474
|
7575
LL | match None {
7676
| ^^^^ patterns `Some(B)` and `Some(_)` not covered
7777
|
78-
note: `Option<Foo>` defined here
78+
note: `Option<HiddenEnum>` defined here
7979
--> $SRC_DIR/core/src/option.rs:LL:COL
8080
|
8181
LL | / pub enum Option<T> {
@@ -87,13 +87,34 @@ LL | | Some(#[stable(feature = "rust1", since = "1.0.0")] T),
8787
| | ^^^^ not covered
8888
LL | | }
8989
| |_-
90-
= note: the matched value is of type `Option<Foo>`
90+
= note: the matched value is of type `Option<HiddenEnum>`
9191
help: ensure that all possible cases are being handled by adding a match arm with a wildcard pattern, a match arm with multiple or-patterns as shown, or multiple match arms
9292
|
93-
LL ~ Some(Foo::A) => {}
93+
LL ~ Some(HiddenEnum::A) => {}
9494
LL + Some(B) | Some(_) => todo!()
9595
|
9696

97-
error: aborting due to 4 previous errors
97+
error[E0004]: non-exhaustive patterns: `C` not covered
98+
--> $DIR/doc-hidden-non-exhaustive.rs:38:11
99+
|
100+
LL | match InCrate::A {
101+
| ^^^^^^^^^^ pattern `C` not covered
102+
|
103+
note: `InCrate` defined here
104+
--> $DIR/doc-hidden-non-exhaustive.rs:11:5
105+
|
106+
LL | enum InCrate {
107+
| -------
108+
...
109+
LL | C,
110+
| ^ not covered
111+
= note: the matched value is of type `InCrate`
112+
help: ensure that all possible cases are being handled by adding a match arm with a wildcard pattern or an explicit pattern as shown
113+
|
114+
LL ~ InCrate::B => {}
115+
LL + C => todo!()
116+
|
117+
118+
error: aborting due to 5 previous errors
98119

99120
For more information about this error, try `rustc --explain E0004`.
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,16 @@
1+
// aux-build:unstable.rs
2+
3+
extern crate unstable;
4+
5+
use unstable::UnstableStruct;
6+
7+
fn main() {
8+
let UnstableStruct { stable } = UnstableStruct::default();
9+
//~^ pattern does not mention field `stable2` and inaccessible fields
10+
11+
let UnstableStruct { stable, stable2 } = UnstableStruct::default();
12+
//~^ pattern requires `..` due to inaccessible fields
13+
14+
// OK: stable field is matched
15+
let UnstableStruct { stable, stable2, .. } = UnstableStruct::default();
16+
}

0 commit comments

Comments
 (0)