Skip to content
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.

Commit c41be9e

Browse files
committedSep 5, 2024·
Auto merge of #13345 - Alexendoo:manual-non-exhaustive-visibility, r=y21
Only lint `manual_non_exhaustive` for exported types For types that are not exported the attribute doesn't make a difference, but the manual pattern can still be used to achieve module level non exhaustiveness Fixes #10301 Fixes #12106 changelog: none
2 parents a95afe2 + f7f5505 commit c41be9e

File tree

6 files changed

+166
-179
lines changed

6 files changed

+166
-179
lines changed
 

‎clippy_lints/src/lib.rs

Lines changed: 1 addition & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -634,8 +634,7 @@ pub fn register_lints(store: &mut rustc_lint::LintStore, conf: &'static Conf) {
634634
let format_args = format_args_storage.clone();
635635
store.register_late_pass(move |_| Box::new(methods::Methods::new(conf, format_args.clone())));
636636
store.register_late_pass(move |_| Box::new(matches::Matches::new(conf)));
637-
store.register_early_pass(move || Box::new(manual_non_exhaustive::ManualNonExhaustiveStruct::new(conf)));
638-
store.register_late_pass(move |_| Box::new(manual_non_exhaustive::ManualNonExhaustiveEnum::new(conf)));
637+
store.register_late_pass(move |_| Box::new(manual_non_exhaustive::ManualNonExhaustive::new(conf)));
639638
store.register_late_pass(move |_| Box::new(manual_strip::ManualStrip::new(conf)));
640639
store.register_early_pass(move || Box::new(redundant_static_lifetimes::RedundantStaticLifetimes::new(conf)));
641640
store.register_early_pass(move || Box::new(redundant_field_names::RedundantFieldNames::new(conf)));

‎clippy_lints/src/manual_non_exhaustive.rs

Lines changed: 73 additions & 109 deletions
Original file line numberDiff line numberDiff line change
@@ -2,16 +2,16 @@ use clippy_config::msrvs::{self, Msrv};
22
use clippy_config::Conf;
33
use clippy_utils::diagnostics::{span_lint_and_then, span_lint_hir_and_then};
44
use clippy_utils::is_doc_hidden;
5-
use clippy_utils::source::SpanRangeExt;
6-
use rustc_ast::ast::{self, VisibilityKind};
5+
use clippy_utils::source::snippet_indent;
6+
use itertools::Itertools;
77
use rustc_ast::attr;
88
use rustc_data_structures::fx::FxHashSet;
99
use rustc_errors::Applicability;
1010
use rustc_hir::def::{CtorKind, CtorOf, DefKind, Res};
11-
use rustc_hir::{self as hir, Expr, ExprKind, QPath};
12-
use rustc_lint::{EarlyContext, EarlyLintPass, LateContext, LateLintPass, LintContext};
11+
use rustc_hir::{Expr, ExprKind, Item, ItemKind, QPath, TyKind, VariantData};
12+
use rustc_lint::{LateContext, LateLintPass};
1313
use rustc_session::impl_lint_pass;
14-
use rustc_span::def_id::{DefId, LocalDefId};
14+
use rustc_span::def_id::LocalDefId;
1515
use rustc_span::{sym, Span};
1616

1717
declare_clippy_lint! {
@@ -62,29 +62,13 @@ declare_clippy_lint! {
6262
"manual implementations of the non-exhaustive pattern can be simplified using #[non_exhaustive]"
6363
}
6464

65-
#[expect(clippy::module_name_repetitions)]
66-
pub struct ManualNonExhaustiveStruct {
65+
pub struct ManualNonExhaustive {
6766
msrv: Msrv,
68-
}
69-
70-
impl ManualNonExhaustiveStruct {
71-
pub fn new(conf: &'static Conf) -> Self {
72-
Self {
73-
msrv: conf.msrv.clone(),
74-
}
75-
}
76-
}
77-
78-
impl_lint_pass!(ManualNonExhaustiveStruct => [MANUAL_NON_EXHAUSTIVE]);
79-
80-
#[expect(clippy::module_name_repetitions)]
81-
pub struct ManualNonExhaustiveEnum {
82-
msrv: Msrv,
83-
constructed_enum_variants: FxHashSet<(DefId, DefId)>,
67+
constructed_enum_variants: FxHashSet<LocalDefId>,
8468
potential_enums: Vec<(LocalDefId, LocalDefId, Span, Span)>,
8569
}
8670

87-
impl ManualNonExhaustiveEnum {
71+
impl ManualNonExhaustive {
8872
pub fn new(conf: &'static Conf) -> Self {
8973
Self {
9074
msrv: conf.msrv.clone(),
@@ -94,96 +78,78 @@ impl ManualNonExhaustiveEnum {
9478
}
9579
}
9680

97-
impl_lint_pass!(ManualNonExhaustiveEnum => [MANUAL_NON_EXHAUSTIVE]);
98-
99-
impl EarlyLintPass for ManualNonExhaustiveStruct {
100-
fn check_item(&mut self, cx: &EarlyContext<'_>, item: &ast::Item) {
101-
if let ast::ItemKind::Struct(variant_data, _) = &item.kind
102-
&& let (fields, delimiter) = match variant_data {
103-
ast::VariantData::Struct { fields, .. } => (&**fields, '{'),
104-
ast::VariantData::Tuple(fields, _) => (&**fields, '('),
105-
ast::VariantData::Unit(_) => return,
106-
}
107-
&& fields.len() > 1
108-
&& self.msrv.meets(msrvs::NON_EXHAUSTIVE)
109-
{
110-
let mut iter = fields.iter().filter_map(|f| match f.vis.kind {
111-
VisibilityKind::Public => None,
112-
VisibilityKind::Inherited => Some(Ok(f)),
113-
VisibilityKind::Restricted { .. } => Some(Err(())),
114-
});
115-
if let Some(Ok(field)) = iter.next()
116-
&& iter.next().is_none()
117-
&& field.ty.kind.is_unit()
118-
{
119-
span_lint_and_then(
120-
cx,
121-
MANUAL_NON_EXHAUSTIVE,
122-
item.span,
123-
"this seems like a manual implementation of the non-exhaustive pattern",
124-
|diag| {
125-
if !item.attrs.iter().any(|attr| attr.has_name(sym::non_exhaustive))
126-
&& let header_span = cx.sess().source_map().span_until_char(item.span, delimiter)
127-
&& let Some(snippet) = header_span.get_source_text(cx)
128-
{
129-
diag.span_suggestion(
130-
header_span,
131-
"add the attribute",
132-
format!("#[non_exhaustive] {snippet}"),
133-
Applicability::Unspecified,
134-
);
135-
}
136-
diag.span_help(field.span, "remove this field");
137-
},
138-
);
139-
}
140-
}
141-
}
81+
impl_lint_pass!(ManualNonExhaustive => [MANUAL_NON_EXHAUSTIVE]);
14282

143-
extract_msrv_attr!(EarlyContext);
144-
}
145-
146-
impl<'tcx> LateLintPass<'tcx> for ManualNonExhaustiveEnum {
147-
fn check_item(&mut self, cx: &LateContext<'tcx>, item: &'tcx hir::Item<'_>) {
148-
if !self.msrv.meets(msrvs::NON_EXHAUSTIVE) {
83+
impl<'tcx> LateLintPass<'tcx> for ManualNonExhaustive {
84+
fn check_item(&mut self, cx: &LateContext<'tcx>, item: &'tcx Item<'_>) {
85+
if !self.msrv.meets(msrvs::NON_EXHAUSTIVE) || !cx.effective_visibilities.is_exported(item.owner_id.def_id) {
14986
return;
15087
}
15188

152-
if let hir::ItemKind::Enum(def, _) = &item.kind
153-
&& def.variants.len() > 1
154-
{
155-
let mut iter = def.variants.iter().filter_map(|v| {
156-
(matches!(v.data, hir::VariantData::Unit(_, _))
157-
&& is_doc_hidden(cx.tcx.hir().attrs(v.hir_id))
158-
&& !attr::contains_name(cx.tcx.hir().attrs(item.hir_id()), sym::non_exhaustive))
159-
.then_some((v.def_id, v.span))
160-
});
161-
if let Some((id, span)) = iter.next()
162-
&& iter.next().is_none()
163-
{
164-
self.potential_enums.push((item.owner_id.def_id, id, item.span, span));
165-
}
89+
match item.kind {
90+
ItemKind::Enum(def, _) if def.variants.len() > 1 => {
91+
let iter = def.variants.iter().filter_map(|v| {
92+
(matches!(v.data, VariantData::Unit(_, _)) && is_doc_hidden(cx.tcx.hir().attrs(v.hir_id)))
93+
.then_some((v.def_id, v.span))
94+
});
95+
if let Ok((id, span)) = iter.exactly_one()
96+
&& !attr::contains_name(cx.tcx.hir().attrs(item.hir_id()), sym::non_exhaustive)
97+
{
98+
self.potential_enums.push((item.owner_id.def_id, id, item.span, span));
99+
}
100+
},
101+
ItemKind::Struct(variant_data, _) => {
102+
let fields = variant_data.fields();
103+
let private_fields = fields
104+
.iter()
105+
.filter(|field| !cx.effective_visibilities.is_exported(field.def_id));
106+
if fields.len() > 1
107+
&& let Ok(field) = private_fields.exactly_one()
108+
&& let TyKind::Tup([]) = field.ty.kind
109+
{
110+
span_lint_and_then(
111+
cx,
112+
MANUAL_NON_EXHAUSTIVE,
113+
item.span,
114+
"this seems like a manual implementation of the non-exhaustive pattern",
115+
|diag| {
116+
if let Some(non_exhaustive) =
117+
attr::find_by_name(cx.tcx.hir().attrs(item.hir_id()), sym::non_exhaustive)
118+
{
119+
diag.span_note(non_exhaustive.span, "the struct is already non-exhaustive");
120+
} else {
121+
let indent = snippet_indent(cx, item.span).unwrap_or_default();
122+
diag.span_suggestion_verbose(
123+
item.span.shrink_to_lo(),
124+
"use the `#[non_exhaustive]` attribute instead",
125+
format!("#[non_exhaustive]\n{indent}"),
126+
Applicability::MaybeIncorrect,
127+
);
128+
}
129+
diag.span_help(field.span, "remove this field");
130+
},
131+
);
132+
}
133+
},
134+
_ => {},
166135
}
167136
}
168137

169138
fn check_expr(&mut self, cx: &LateContext<'tcx>, e: &'tcx Expr<'_>) {
170139
if let ExprKind::Path(QPath::Resolved(None, p)) = &e.kind
171-
&& let Res::Def(DefKind::Ctor(CtorOf::Variant, CtorKind::Const), id) = p.res
140+
&& let Res::Def(DefKind::Ctor(CtorOf::Variant, CtorKind::Const), ctor_id) = p.res
141+
&& let Some(local_ctor) = ctor_id.as_local()
172142
{
173-
let variant_id = cx.tcx.parent(id);
174-
let enum_id = cx.tcx.parent(variant_id);
175-
176-
self.constructed_enum_variants.insert((enum_id, variant_id));
143+
let variant_id = cx.tcx.local_parent(local_ctor);
144+
self.constructed_enum_variants.insert(variant_id);
177145
}
178146
}
179147

180148
fn check_crate_post(&mut self, cx: &LateContext<'tcx>) {
181-
for &(enum_id, _, enum_span, variant_span) in
182-
self.potential_enums.iter().filter(|&&(enum_id, variant_id, _, _)| {
183-
!self
184-
.constructed_enum_variants
185-
.contains(&(enum_id.to_def_id(), variant_id.to_def_id()))
186-
})
149+
for &(enum_id, _, enum_span, variant_span) in self
150+
.potential_enums
151+
.iter()
152+
.filter(|(_, variant_id, _, _)| !self.constructed_enum_variants.contains(variant_id))
187153
{
188154
let hir_id = cx.tcx.local_def_id_to_hir_id(enum_id);
189155
span_lint_hir_and_then(
@@ -193,15 +159,13 @@ impl<'tcx> LateLintPass<'tcx> for ManualNonExhaustiveEnum {
193159
enum_span,
194160
"this seems like a manual implementation of the non-exhaustive pattern",
195161
|diag| {
196-
let header_span = cx.sess().source_map().span_until_char(enum_span, '{');
197-
if let Some(snippet) = header_span.get_source_text(cx) {
198-
diag.span_suggestion(
199-
header_span,
200-
"add the attribute",
201-
format!("#[non_exhaustive] {snippet}"),
202-
Applicability::Unspecified,
203-
);
204-
}
162+
let indent = snippet_indent(cx, enum_span).unwrap_or_default();
163+
diag.span_suggestion_verbose(
164+
enum_span.shrink_to_lo(),
165+
"use the `#[non_exhaustive]` attribute instead",
166+
format!("#[non_exhaustive]\n{indent}"),
167+
Applicability::MaybeIncorrect,
168+
);
205169
diag.span_help(variant_span, "remove this variant");
206170
},
207171
);
Lines changed: 11 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -1,8 +1,8 @@
11
#![warn(clippy::manual_non_exhaustive)]
22
#![allow(unused)]
33
//@no-rustfix
4-
enum E {
5-
//~^ ERROR: this seems like a manual implementation of the non-exhaustive pattern
4+
pub enum E {
5+
//~^ manual_non_exhaustive
66
A,
77
B,
88
#[doc(hidden)]
@@ -11,44 +11,44 @@ enum E {
1111

1212
// if the user explicitly marks as nonexhaustive we shouldn't warn them
1313
#[non_exhaustive]
14-
enum Ep {
14+
pub enum Ep {
1515
A,
1616
B,
1717
#[doc(hidden)]
1818
_C,
1919
}
2020

2121
// marker variant does not have doc hidden attribute, should be ignored
22-
enum NoDocHidden {
22+
pub enum NoDocHidden {
2323
A,
2424
B,
2525
_C,
2626
}
2727

2828
// name of variant with doc hidden does not start with underscore
29-
enum NoUnderscore {
29+
pub enum NoUnderscore {
3030
A,
3131
B,
3232
#[doc(hidden)]
3333
C,
3434
}
3535

3636
// variant with doc hidden is not unit, should be ignored
37-
enum NotUnit {
37+
pub enum NotUnit {
3838
A,
3939
B,
4040
#[doc(hidden)]
4141
_C(bool),
4242
}
4343

4444
// variant with doc hidden is the only one, should be ignored
45-
enum OnlyMarker {
45+
pub enum OnlyMarker {
4646
#[doc(hidden)]
4747
_A,
4848
}
4949

5050
// variant with multiple markers, should be ignored
51-
enum MultipleMarkers {
51+
pub enum MultipleMarkers {
5252
A,
5353
#[doc(hidden)]
5454
_B,
@@ -58,13 +58,13 @@ enum MultipleMarkers {
5858

5959
// already non_exhaustive and no markers, should be ignored
6060
#[non_exhaustive]
61-
enum NonExhaustive {
61+
pub enum NonExhaustive {
6262
A,
6363
B,
6464
}
6565

6666
// marked is used, don't lint
67-
enum UsedHidden {
67+
pub enum UsedHidden {
6868
#[doc(hidden)]
6969
_A,
7070
B,
@@ -77,11 +77,9 @@ fn foo(x: &mut UsedHidden) {
7777
}
7878

7979
#[expect(clippy::manual_non_exhaustive)]
80-
enum ExpectLint {
80+
pub enum ExpectLint {
8181
A,
8282
B,
8383
#[doc(hidden)]
8484
_C,
8585
}
86-
87-
fn main() {}

‎tests/ui/manual_non_exhaustive_enum.stderr

Lines changed: 12 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -1,11 +1,7 @@
11
error: this seems like a manual implementation of the non-exhaustive pattern
22
--> tests/ui/manual_non_exhaustive_enum.rs:4:1
33
|
4-
LL | enum E {
5-
| ^-----
6-
| |
7-
| _help: add the attribute: `#[non_exhaustive] enum E`
8-
| |
4+
LL | / pub enum E {
95
LL | |
106
LL | | A,
117
LL | | B,
@@ -21,15 +17,16 @@ LL | _C,
2117
| ^^
2218
= note: `-D clippy::manual-non-exhaustive` implied by `-D warnings`
2319
= help: to override `-D warnings` add `#[allow(clippy::manual_non_exhaustive)]`
20+
help: use the `#[non_exhaustive]` attribute instead
21+
|
22+
LL + #[non_exhaustive]
23+
LL | pub enum E {
24+
|
2425

2526
error: this seems like a manual implementation of the non-exhaustive pattern
2627
--> tests/ui/manual_non_exhaustive_enum.rs:29:1
2728
|
28-
LL | enum NoUnderscore {
29-
| ^----------------
30-
| |
31-
| _help: add the attribute: `#[non_exhaustive] enum NoUnderscore`
32-
| |
29+
LL | / pub enum NoUnderscore {
3330
LL | | A,
3431
LL | | B,
3532
LL | | #[doc(hidden)]
@@ -42,6 +39,11 @@ help: remove this variant
4239
|
4340
LL | C,
4441
| ^
42+
help: use the `#[non_exhaustive]` attribute instead
43+
|
44+
LL + #[non_exhaustive]
45+
LL | pub enum NoUnderscore {
46+
|
4547

4648
error: aborting due to 2 previous errors
4749

Lines changed: 29 additions & 21 deletions
Original file line numberDiff line numberDiff line change
@@ -1,78 +1,86 @@
11
#![warn(clippy::manual_non_exhaustive)]
22
#![allow(unused)]
33
//@no-rustfix
4-
mod structs {
5-
struct S {
6-
//~^ ERROR: this seems like a manual implementation of the non-exhaustive pattern
4+
pub mod structs {
5+
pub struct S {
6+
//~^ manual_non_exhaustive
77
pub a: i32,
88
pub b: i32,
99
_c: (),
1010
}
1111

1212
// user forgot to remove the private field
1313
#[non_exhaustive]
14-
struct Sp {
15-
//~^ ERROR: this seems like a manual implementation of the non-exhaustive pattern
14+
pub struct Sp {
15+
//~^ manual_non_exhaustive
1616
pub a: i32,
1717
pub b: i32,
1818
_c: (),
1919
}
2020

2121
// some other fields are private, should be ignored
22-
struct PrivateFields {
22+
pub struct PrivateFields {
2323
a: i32,
2424
pub b: i32,
2525
_c: (),
2626
}
2727

28-
// private field name does not start with underscore, should be ignored
29-
struct NoUnderscore {
28+
pub struct NoUnderscore {
29+
//~^ manual_non_exhaustive
3030
pub a: i32,
3131
pub b: i32,
3232
c: (),
3333
}
3434

3535
// private field is not unit type, should be ignored
36-
struct NotUnit {
36+
pub struct NotUnit {
3737
pub a: i32,
3838
pub b: i32,
3939
_c: i32,
4040
}
4141

4242
// private field is the only field, should be ignored
43-
struct OnlyMarker {
43+
pub struct OnlyMarker {
4444
_a: (),
4545
}
4646

4747
// already non exhaustive and no private fields, should be ignored
4848
#[non_exhaustive]
49-
struct NonExhaustive {
49+
pub struct NonExhaustive {
5050
pub a: i32,
5151
pub b: i32,
5252
}
5353
}
5454

55-
mod tuple_structs {
56-
struct T(pub i32, pub i32, ());
57-
//~^ ERROR: this seems like a manual implementation of the non-exhaustive pattern
55+
pub mod tuple_structs {
56+
pub struct T(pub i32, pub i32, ());
57+
//~^ manual_non_exhaustive
5858

5959
// user forgot to remove the private field
6060
#[non_exhaustive]
61-
struct Tp(pub i32, pub i32, ());
62-
//~^ ERROR: this seems like a manual implementation of the non-exhaustive pattern
61+
pub struct Tp(pub i32, pub i32, ());
62+
//~^ manual_non_exhaustive
6363

6464
// some other fields are private, should be ignored
65-
struct PrivateFields(pub i32, i32, ());
65+
pub struct PrivateFields(pub i32, i32, ());
6666

6767
// private field is not unit type, should be ignored
68-
struct NotUnit(pub i32, pub i32, i32);
68+
pub struct NotUnit(pub i32, pub i32, i32);
6969

7070
// private field is the only field, should be ignored
71-
struct OnlyMarker(());
71+
pub struct OnlyMarker(());
7272

7373
// already non exhaustive and no private fields, should be ignored
7474
#[non_exhaustive]
75-
struct NonExhaustive(pub i32, pub i32);
75+
pub struct NonExhaustive(pub i32, pub i32);
7676
}
7777

78-
fn main() {}
78+
mod private {
79+
// Don't lint structs that are not actually public as `#[non_exhaustive]` only applies to
80+
// external crates. The manual pattern can still be used to get module local non exhaustiveness
81+
pub struct NotPublic {
82+
pub a: i32,
83+
pub b: i32,
84+
_c: (),
85+
}
86+
}
Lines changed: 40 additions & 24 deletions
Original file line numberDiff line numberDiff line change
@@ -1,11 +1,7 @@
11
error: this seems like a manual implementation of the non-exhaustive pattern
22
--> tests/ui/manual_non_exhaustive_struct.rs:5:5
33
|
4-
LL | struct S {
5-
| ^-------
6-
| |
7-
| _____help: add the attribute: `#[non_exhaustive] struct S`
8-
| |
4+
LL | / pub struct S {
95
LL | |
106
LL | | pub a: i32,
117
LL | | pub b: i32,
@@ -20,32 +16,39 @@ LL | _c: (),
2016
| ^^^^^^
2117
= note: `-D clippy::manual-non-exhaustive` implied by `-D warnings`
2218
= help: to override `-D warnings` add `#[allow(clippy::manual_non_exhaustive)]`
19+
help: use the `#[non_exhaustive]` attribute instead
20+
|
21+
LL ~ #[non_exhaustive]
22+
LL ~ pub struct S {
23+
|
2324

2425
error: this seems like a manual implementation of the non-exhaustive pattern
2526
--> tests/ui/manual_non_exhaustive_struct.rs:14:5
2627
|
27-
LL | / struct Sp {
28+
LL | / pub struct Sp {
2829
LL | |
2930
LL | | pub a: i32,
3031
LL | | pub b: i32,
3132
LL | | _c: (),
3233
LL | | }
3334
| |_____^
3435
|
36+
note: the struct is already non-exhaustive
37+
--> tests/ui/manual_non_exhaustive_struct.rs:13:5
38+
|
39+
LL | #[non_exhaustive]
40+
| ^^^^^^^^^^^^^^^^^
3541
help: remove this field
3642
--> tests/ui/manual_non_exhaustive_struct.rs:18:9
3743
|
3844
LL | _c: (),
3945
| ^^^^^^
4046

4147
error: this seems like a manual implementation of the non-exhaustive pattern
42-
--> tests/ui/manual_non_exhaustive_struct.rs:29:5
48+
--> tests/ui/manual_non_exhaustive_struct.rs:28:5
4349
|
44-
LL | struct NoUnderscore {
45-
| ^------------------
46-
| |
47-
| _____help: add the attribute: `#[non_exhaustive] struct NoUnderscore`
48-
| |
50+
LL | / pub struct NoUnderscore {
51+
LL | |
4952
LL | | pub a: i32,
5053
LL | | pub b: i32,
5154
LL | | c: (),
@@ -57,32 +60,45 @@ help: remove this field
5760
|
5861
LL | c: (),
5962
| ^^^^^
63+
help: use the `#[non_exhaustive]` attribute instead
64+
|
65+
LL ~ #[non_exhaustive]
66+
LL ~ pub struct NoUnderscore {
67+
|
6068

6169
error: this seems like a manual implementation of the non-exhaustive pattern
6270
--> tests/ui/manual_non_exhaustive_struct.rs:56:5
6371
|
64-
LL | struct T(pub i32, pub i32, ());
65-
| --------^^^^^^^^^^^^^^^^^^^^^^^
66-
| |
67-
| help: add the attribute: `#[non_exhaustive] struct T`
72+
LL | pub struct T(pub i32, pub i32, ());
73+
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
6874
|
6975
help: remove this field
70-
--> tests/ui/manual_non_exhaustive_struct.rs:56:32
76+
--> tests/ui/manual_non_exhaustive_struct.rs:56:36
77+
|
78+
LL | pub struct T(pub i32, pub i32, ());
79+
| ^^
80+
help: use the `#[non_exhaustive]` attribute instead
81+
|
82+
LL ~ #[non_exhaustive]
83+
LL ~ pub struct T(pub i32, pub i32, ());
7184
|
72-
LL | struct T(pub i32, pub i32, ());
73-
| ^^
7485

7586
error: this seems like a manual implementation of the non-exhaustive pattern
7687
--> tests/ui/manual_non_exhaustive_struct.rs:61:5
7788
|
78-
LL | struct Tp(pub i32, pub i32, ());
79-
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
89+
LL | pub struct Tp(pub i32, pub i32, ());
90+
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
91+
|
92+
note: the struct is already non-exhaustive
93+
--> tests/ui/manual_non_exhaustive_struct.rs:60:5
8094
|
95+
LL | #[non_exhaustive]
96+
| ^^^^^^^^^^^^^^^^^
8197
help: remove this field
82-
--> tests/ui/manual_non_exhaustive_struct.rs:61:33
98+
--> tests/ui/manual_non_exhaustive_struct.rs:61:37
8399
|
84-
LL | struct Tp(pub i32, pub i32, ());
85-
| ^^
100+
LL | pub struct Tp(pub i32, pub i32, ());
101+
| ^^
86102

87103
error: aborting due to 5 previous errors
88104

0 commit comments

Comments
 (0)
Please sign in to comment.