Skip to content

Commit c7d81ea

Browse files
Port #[non_exhaustive] to the new attribute parsing infrastructure
1 parent ef8dffb commit c7d81ea

File tree

17 files changed

+89
-50
lines changed

17 files changed

+89
-50
lines changed

compiler/rustc_attr_data_structures/src/attributes.rs

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -281,6 +281,9 @@ pub enum AttributeKind {
281281
/// Represents `#[no_mangle]`
282282
NoMangle(Span),
283283

284+
/// Represents `#[non_exhaustive]`
285+
NonExhaustive(Span),
286+
284287
/// Represents `#[optimize(size|speed)]`
285288
Optimize(OptimizeAttr, Span),
286289

compiler/rustc_attr_data_structures/src/encode_cross_crate.rs

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -26,6 +26,7 @@ impl AttributeKind {
2626
Inline(..) => No,
2727
LinkSection { .. } => No,
2828
MacroTransparency(..) => Yes,
29+
NonExhaustive(..) => Yes,
2930
Repr(..) => No,
3031
Stability { .. } => Yes,
3132
Cold(..) => No,

compiler/rustc_attr_parsing/src/attributes/mod.rs

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -35,6 +35,7 @@ pub(crate) mod link_attrs;
3535
pub(crate) mod lint_helpers;
3636
pub(crate) mod loop_match;
3737
pub(crate) mod must_use;
38+
pub(crate) mod non_exhaustive;
3839
pub(crate) mod repr;
3940
pub(crate) mod rustc_internal;
4041
pub(crate) mod semantics;
Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,13 @@
1+
use rustc_attr_data_structures::AttributeKind;
2+
use rustc_span::{Span, Symbol, sym};
3+
4+
use crate::attributes::{NoArgsAttributeParser, OnDuplicate};
5+
use crate::context::Stage;
6+
7+
pub(crate) struct NonExhaustiveParser;
8+
9+
impl<S: Stage> NoArgsAttributeParser<S> for NonExhaustiveParser {
10+
const PATH: &[Symbol] = &[sym::non_exhaustive];
11+
const ON_DUPLICATE: OnDuplicate<S> = OnDuplicate::Warn;
12+
const CREATE: fn(Span) -> AttributeKind = AttributeKind::NonExhaustive;
13+
}

compiler/rustc_attr_parsing/src/context.rs

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -26,6 +26,7 @@ use crate::attributes::link_attrs::{LinkNameParser, LinkSectionParser};
2626
use crate::attributes::lint_helpers::{AsPtrParser, PubTransparentParser};
2727
use crate::attributes::loop_match::{ConstContinueParser, LoopMatchParser};
2828
use crate::attributes::must_use::MustUseParser;
29+
use crate::attributes::non_exhaustive::NonExhaustiveParser;
2930
use crate::attributes::repr::{AlignParser, ReprParser};
3031
use crate::attributes::rustc_internal::{
3132
RustcLayoutScalarValidRangeEnd, RustcLayoutScalarValidRangeStart,
@@ -141,6 +142,7 @@ attribute_parsers!(
141142
Single<WithoutArgs<LoopMatchParser>>,
142143
Single<WithoutArgs<MayDangleParser>>,
143144
Single<WithoutArgs<NoMangleParser>>,
145+
Single<WithoutArgs<NonExhaustiveParser>>,
144146
Single<WithoutArgs<PubTransparentParser>>,
145147
Single<WithoutArgs<TrackCallerParser>>,
146148
// tidy-alphabetical-end

compiler/rustc_hir_analysis/src/collect.rs

Lines changed: 5 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -778,9 +778,11 @@ fn lower_variant<'tcx>(
778778
fields,
779779
parent_did.to_def_id(),
780780
recovered,
781-
adt_kind == AdtKind::Struct && tcx.has_attr(parent_did, sym::non_exhaustive)
782-
|| variant_did
783-
.is_some_and(|variant_did| tcx.has_attr(variant_did, sym::non_exhaustive)),
781+
adt_kind == AdtKind::Struct
782+
&& find_attr!(tcx.get_all_attrs(parent_did), AttributeKind::NonExhaustive(..))
783+
|| variant_did.is_some_and(|variant_did| {
784+
find_attr!(tcx.get_all_attrs(variant_did), AttributeKind::NonExhaustive(..))
785+
}),
784786
)
785787
}
786788

compiler/rustc_middle/src/ty/adt.rs

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,7 @@ use std::ops::Range;
44
use std::str;
55

66
use rustc_abi::{FIRST_VARIANT, ReprOptions, VariantIdx};
7+
use rustc_attr_data_structures::{AttributeKind, find_attr};
78
use rustc_data_structures::fingerprint::Fingerprint;
89
use rustc_data_structures::fx::FxHashMap;
910
use rustc_data_structures::intern::Interned;
@@ -278,7 +279,9 @@ impl AdtDefData {
278279
debug!("AdtDef::new({:?}, {:?}, {:?}, {:?})", did, kind, variants, repr);
279280
let mut flags = AdtFlags::NO_ADT_FLAGS;
280281

281-
if kind == AdtKind::Enum && tcx.has_attr(did, sym::non_exhaustive) {
282+
if kind == AdtKind::Enum
283+
&& find_attr!(tcx.get_all_attrs(did), AttributeKind::NonExhaustive(..))
284+
{
282285
debug!("found non-exhaustive variant list for {:?}", did);
283286
flags = flags | AdtFlags::IS_VARIANT_LIST_NON_EXHAUSTIVE;
284287
}

compiler/rustc_parse/src/validate_attr.rs

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -300,6 +300,7 @@ fn emit_malformed_attribute(
300300
| sym::cold
301301
| sym::naked
302302
| sym::no_mangle
303+
| sym::non_exhaustive
303304
| sym::must_use
304305
| sym::track_caller
305306
| sym::link_name

compiler/rustc_passes/src/check_attr.rs

Lines changed: 8 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -188,6 +188,9 @@ impl<'tcx> CheckAttrVisitor<'tcx> {
188188
Attribute::Parsed(AttributeKind::TrackCaller(attr_span)) => {
189189
self.check_track_caller(hir_id, *attr_span, attrs, span, target)
190190
}
191+
Attribute::Parsed(AttributeKind::NonExhaustive(attr_span)) => {
192+
self.check_non_exhaustive(hir_id, *attr_span, span, target, item)
193+
}
191194
Attribute::Parsed(
192195
AttributeKind::RustcLayoutScalarValidRangeStart(_num, attr_span)
193196
| AttributeKind::RustcLayoutScalarValidRangeEnd(_num, attr_span),
@@ -228,7 +231,6 @@ impl<'tcx> CheckAttrVisitor<'tcx> {
228231
[sym::no_sanitize, ..] => {
229232
self.check_no_sanitize(attr, span, target)
230233
}
231-
[sym::non_exhaustive, ..] => self.check_non_exhaustive(hir_id, attr, span, target, item),
232234
[sym::marker, ..] => self.check_marker(hir_id, attr, span, target),
233235
[sym::target_feature, ..] => {
234236
self.check_target_feature(hir_id, attr, span, target, attrs)
@@ -755,7 +757,7 @@ impl<'tcx> CheckAttrVisitor<'tcx> {
755757
fn check_non_exhaustive(
756758
&self,
757759
hir_id: HirId,
758-
attr: &Attribute,
760+
attr_span: Span,
759761
span: Span,
760762
target: Target,
761763
item: Option<ItemLike<'_>>,
@@ -770,7 +772,7 @@ impl<'tcx> CheckAttrVisitor<'tcx> {
770772
&& fields.iter().any(|f| f.default.is_some())
771773
{
772774
self.dcx().emit_err(errors::NonExhaustiveWithDefaultFieldValues {
773-
attr_span: attr.span(),
775+
attr_span,
774776
defn_span: span,
775777
});
776778
}
@@ -781,13 +783,11 @@ impl<'tcx> CheckAttrVisitor<'tcx> {
781783
// erroneously allowed it and some crates used it accidentally, to be compatible
782784
// with crates depending on them, we can't throw an error here.
783785
Target::Field | Target::Arm | Target::MacroDef => {
784-
self.inline_attr_str_error_with_macro_def(hir_id, attr.span(), "non_exhaustive");
786+
self.inline_attr_str_error_with_macro_def(hir_id, attr_span, "non_exhaustive");
785787
}
786788
_ => {
787-
self.dcx().emit_err(errors::NonExhaustiveWrongLocation {
788-
attr_span: attr.span(),
789-
defn_span: span,
790-
});
789+
self.dcx()
790+
.emit_err(errors::NonExhaustiveWrongLocation { attr_span, defn_span: span });
791791
}
792792
}
793793
}

compiler/rustc_resolve/src/diagnostics.rs

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -5,7 +5,7 @@ use rustc_ast::{
55
self as ast, CRATE_NODE_ID, Crate, ItemKind, MetaItemInner, MetaItemKind, ModKind, NodeId, Path,
66
};
77
use rustc_ast_pretty::pprust;
8-
use rustc_attr_data_structures::{self as attr, Stability};
8+
use rustc_attr_data_structures::{self as attr, AttributeKind, Stability, find_attr};
99
use rustc_data_structures::fx::{FxHashMap, FxHashSet};
1010
use rustc_data_structures::unord::{UnordMap, UnordSet};
1111
use rustc_errors::codes::*;
@@ -1998,9 +1998,9 @@ impl<'ra, 'tcx> Resolver<'ra, 'tcx> {
19981998
// Otherwise, point out if the struct has any private fields.
19991999
if let Some(def_id) = res.opt_def_id()
20002000
&& !def_id.is_local()
2001-
&& let Some(attr) = self.tcx.get_attr(def_id, sym::non_exhaustive)
2001+
&& let Some(attr_span) = find_attr!(self.tcx.get_all_attrs(def_id), AttributeKind::NonExhaustive(span) => *span)
20022002
{
2003-
non_exhaustive = Some(attr.span());
2003+
non_exhaustive = Some(attr_span);
20042004
} else if let Some(span) = ctor_fields_span {
20052005
let label = errors::ConstructorPrivateIfAnyFieldPrivate { span };
20062006
err.subdiagnostic(label);

src/librustdoc/clean/types.rs

Lines changed: 4 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -7,7 +7,7 @@ use arrayvec::ArrayVec;
77
use itertools::Either;
88
use rustc_abi::{ExternAbi, VariantIdx};
99
use rustc_attr_data_structures::{
10-
AttributeKind, ConstStability, Deprecation, Stability, StableSince,
10+
AttributeKind, ConstStability, Deprecation, Stability, StableSince, find_attr,
1111
};
1212
use rustc_data_structures::fx::{FxHashSet, FxIndexMap, FxIndexSet};
1313
use rustc_hir::def::{CtorKind, DefKind, Res};
@@ -621,7 +621,7 @@ impl Item {
621621
}
622622

623623
pub(crate) fn is_non_exhaustive(&self) -> bool {
624-
self.attrs.other_attrs.iter().any(|a| a.has_name(sym::non_exhaustive))
624+
find_attr!(&self.attrs.other_attrs, AttributeKind::NonExhaustive(..))
625625
}
626626

627627
/// Returns a documentation-level item type from the item.
@@ -763,6 +763,8 @@ impl Item {
763763
} else if let hir::Attribute::Parsed(AttributeKind::ExportName { name, .. }) = attr
764764
{
765765
Some(format!("#[export_name = \"{name}\"]"))
766+
} else if let hir::Attribute::Parsed(AttributeKind::NonExhaustive(..)) = attr {
767+
Some("#[non_exhaustive]".to_string())
766768
} else if is_json {
767769
match attr {
768770
// rustdoc-json stores this in `Item::deprecation`, so we

src/tools/clippy/clippy_lints/src/exhaustive_items.rs

Lines changed: 4 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -4,7 +4,9 @@ use rustc_errors::Applicability;
44
use rustc_hir::{Item, ItemKind};
55
use rustc_lint::{LateContext, LateLintPass};
66
use rustc_session::declare_lint_pass;
7-
use rustc_span::sym;
7+
use rustc_attr_data_structures::AttributeKind;
8+
use rustc_attr_data_structures::find_attr;
9+
810

911
declare_clippy_lint! {
1012
/// ### What it does
@@ -85,7 +87,7 @@ impl LateLintPass<'_> for ExhaustiveItems {
8587
};
8688
if cx.effective_visibilities.is_exported(item.owner_id.def_id)
8789
&& let attrs = cx.tcx.hir_attrs(item.hir_id())
88-
&& !attrs.iter().any(|a| a.has_name(sym::non_exhaustive))
90+
&& !find_attr!(attrs, AttributeKind::NonExhaustive(..))
8991
&& fields.iter().all(|f| cx.tcx.visibility(f.def_id).is_public())
9092
{
9193
span_lint_and_then(cx, lint, item.span, msg, |diag| {

src/tools/clippy/clippy_lints/src/manual_non_exhaustive.rs

Lines changed: 7 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -4,15 +4,16 @@ use clippy_utils::is_doc_hidden;
44
use clippy_utils::msrvs::{self, Msrv};
55
use clippy_utils::source::snippet_indent;
66
use itertools::Itertools;
7-
use rustc_ast::attr;
87
use rustc_data_structures::fx::FxHashSet;
98
use rustc_errors::Applicability;
109
use rustc_hir::def::{CtorKind, CtorOf, DefKind, Res};
1110
use rustc_hir::{Expr, ExprKind, Item, ItemKind, QPath, TyKind, VariantData};
1211
use rustc_lint::{LateContext, LateLintPass};
1312
use rustc_session::impl_lint_pass;
1413
use rustc_span::def_id::LocalDefId;
15-
use rustc_span::{Span, sym};
14+
use rustc_span::Span;
15+
use rustc_attr_data_structures::find_attr;
16+
use rustc_attr_data_structures::AttributeKind;
1617

1718
declare_clippy_lint! {
1819
/// ### What it does
@@ -93,7 +94,7 @@ impl<'tcx> LateLintPass<'tcx> for ManualNonExhaustive {
9394
.then_some((v.def_id, v.span))
9495
});
9596
if let Ok((id, span)) = iter.exactly_one()
96-
&& !attr::contains_name(cx.tcx.hir_attrs(item.hir_id()), sym::non_exhaustive)
97+
&& !find_attr!(cx.tcx.hir_attrs(item.hir_id()), AttributeKind::NonExhaustive(..))
9798
{
9899
self.potential_enums.push((item.owner_id.def_id, id, item.span, span));
99100
}
@@ -113,10 +114,10 @@ impl<'tcx> LateLintPass<'tcx> for ManualNonExhaustive {
113114
item.span,
114115
"this seems like a manual implementation of the non-exhaustive pattern",
115116
|diag| {
116-
if let Some(non_exhaustive) =
117-
attr::find_by_name(cx.tcx.hir_attrs(item.hir_id()), sym::non_exhaustive)
117+
if let Some(non_exhaustive_span) =
118+
find_attr!(cx.tcx.hir_attrs(item.hir_id()), AttributeKind::NonExhaustive(span) => *span)
118119
{
119-
diag.span_note(non_exhaustive.span(), "the struct is already non-exhaustive");
120+
diag.span_note(non_exhaustive_span, "the struct is already non-exhaustive");
120121
} else {
121122
let indent = snippet_indent(cx, item.span).unwrap_or_default();
122123
diag.span_suggestion_verbose(

src/tools/clippy/clippy_utils/src/attrs.rs

Lines changed: 5 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -7,9 +7,10 @@ use rustc_middle::ty::{AdtDef, TyCtxt};
77
use rustc_session::Session;
88
use rustc_span::{Span, Symbol};
99
use std::str::FromStr;
10-
10+
use rustc_attr_data_structures::find_attr;
1111
use crate::source::SpanRangeExt;
1212
use crate::{sym, tokenize_with_text};
13+
use rustc_attr_data_structures::AttributeKind;
1314

1415
/// Deprecation status of attributes known by Clippy.
1516
pub enum DeprecationStatus {
@@ -165,13 +166,13 @@ pub fn is_doc_hidden(attrs: &[impl AttributeExt]) -> bool {
165166

166167
pub fn has_non_exhaustive_attr(tcx: TyCtxt<'_>, adt: AdtDef<'_>) -> bool {
167168
adt.is_variant_list_non_exhaustive()
168-
|| tcx.has_attr(adt.did(), sym::non_exhaustive)
169+
|| find_attr!(tcx.get_all_attrs(adt.did()), AttributeKind::NonExhaustive(..))
169170
|| adt.variants().iter().any(|variant_def| {
170-
variant_def.is_field_list_non_exhaustive() || tcx.has_attr(variant_def.def_id, sym::non_exhaustive)
171+
variant_def.is_field_list_non_exhaustive() || find_attr!(tcx.get_all_attrs(variant_def.def_id), AttributeKind::NonExhaustive(..))
171172
})
172173
|| adt
173174
.all_fields()
174-
.any(|field_def| tcx.has_attr(field_def.did, sym::non_exhaustive))
175+
.any(|field_def| find_attr!(tcx.get_all_attrs(field_def.did), AttributeKind::NonExhaustive(..)))
175176
}
176177

177178
/// Checks if the given span contains a `#[cfg(..)]` attribute

tests/ui/attributes/malformed-attrs.stderr

Lines changed: 9 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -218,12 +218,6 @@ error: malformed `automatically_derived` attribute input
218218
LL | #[automatically_derived = 18]
219219
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: must be of the form: `#[automatically_derived]`
220220

221-
error: malformed `non_exhaustive` attribute input
222-
--> $DIR/malformed-attrs.rs:195:1
223-
|
224-
LL | #[non_exhaustive = 1]
225-
| ^^^^^^^^^^^^^^^^^^^^^ help: must be of the form: `#[non_exhaustive]`
226-
227221
error: malformed `thread_local` attribute input
228222
--> $DIR/malformed-attrs.rs:201:1
229223
|
@@ -546,6 +540,15 @@ LL | #[rustc_layout_scalar_valid_range_end]
546540
| expected this to be a list
547541
| help: must be of the form: `#[rustc_layout_scalar_valid_range_end(end)]`
548542

543+
error[E0565]: malformed `non_exhaustive` attribute input
544+
--> $DIR/malformed-attrs.rs:195:1
545+
|
546+
LL | #[non_exhaustive = 1]
547+
| ^^^^^^^^^^^^^^^^^---^
548+
| | |
549+
| | didn't expect any arguments here
550+
| help: must be of the form: `#[non_exhaustive]`
551+
549552
warning: `#[diagnostic::do_not_recommend]` does not expect any arguments
550553
--> $DIR/malformed-attrs.rs:147:1
551554
|

tests/ui/lint/unused/unused-attr-duplicate.stderr

Lines changed: 12 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -65,18 +65,6 @@ LL | #[should_panic]
6565
| ^^^^^^^^^^^^^^^
6666
= warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release!
6767

68-
error: unused attribute
69-
--> $DIR/unused-attr-duplicate.rs:66:1
70-
|
71-
LL | #[non_exhaustive]
72-
| ^^^^^^^^^^^^^^^^^ help: remove this attribute
73-
|
74-
note: attribute also specified here
75-
--> $DIR/unused-attr-duplicate.rs:65:1
76-
|
77-
LL | #[non_exhaustive]
78-
| ^^^^^^^^^^^^^^^^^
79-
8068
error: unused attribute
8169
--> $DIR/unused-attr-duplicate.rs:70:1
8270
|
@@ -202,6 +190,18 @@ LL | #[must_use]
202190
| ^^^^^^^^^^^
203191
= warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release!
204192

193+
error: unused attribute
194+
--> $DIR/unused-attr-duplicate.rs:66:1
195+
|
196+
LL | #[non_exhaustive]
197+
| ^^^^^^^^^^^^^^^^^ help: remove this attribute
198+
|
199+
note: attribute also specified here
200+
--> $DIR/unused-attr-duplicate.rs:65:1
201+
|
202+
LL | #[non_exhaustive]
203+
| ^^^^^^^^^^^^^^^^^
204+
205205
error: unused attribute
206206
--> $DIR/unused-attr-duplicate.rs:74:1
207207
|

tests/ui/rfcs/rfc-2008-non-exhaustive/invalid-attribute.stderr

Lines changed: 7 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,8 +1,11 @@
1-
error: malformed `non_exhaustive` attribute input
1+
error[E0565]: malformed `non_exhaustive` attribute input
22
--> $DIR/invalid-attribute.rs:1:1
33
|
44
LL | #[non_exhaustive(anything)]
5-
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: must be of the form: `#[non_exhaustive]`
5+
| ^^^^^^^^^^^^^^^^----------^
6+
| | |
7+
| | didn't expect any arguments here
8+
| help: must be of the form: `#[non_exhaustive]`
69

710
error[E0701]: attribute should be applied to a struct or enum
811
--> $DIR/invalid-attribute.rs:5:1
@@ -27,4 +30,5 @@ LL | | }
2730

2831
error: aborting due to 3 previous errors
2932

30-
For more information about this error, try `rustc --explain E0701`.
33+
Some errors have detailed explanations: E0565, E0701.
34+
For more information about an error, try `rustc --explain E0565`.

0 commit comments

Comments
 (0)