Rollup merge of #134539 - estebank:restrict-non_exhaustive, r=jieyouxu
Restrict `#[non_exaustive]` on structs with default field values Do not allow users to apply `#[non_exaustive]` to a struct when they have also used default field values.
This commit is contained in:
commit
fea6c4eb07
5 changed files with 78 additions and 3 deletions
|
@ -566,6 +566,10 @@ passes_no_sanitize =
|
|||
`#[no_sanitize({$attr_str})]` should be applied to {$accepted_kind}
|
||||
.label = not {$accepted_kind}
|
||||
|
||||
passes_non_exaustive_with_default_field_values =
|
||||
`#[non_exhaustive]` can't be used to annotate items with default field values
|
||||
.label = this struct has default field values
|
||||
|
||||
passes_non_exported_macro_invalid_attrs =
|
||||
attribute should be applied to function or closure
|
||||
.label = not a function or closure
|
||||
|
|
|
@ -124,7 +124,7 @@ impl<'tcx> CheckAttrVisitor<'tcx> {
|
|||
[sym::coverage, ..] => self.check_coverage(attr, span, target),
|
||||
[sym::optimize, ..] => self.check_optimize(hir_id, attr, span, target),
|
||||
[sym::no_sanitize, ..] => self.check_no_sanitize(attr, span, target),
|
||||
[sym::non_exhaustive, ..] => self.check_non_exhaustive(hir_id, attr, span, target),
|
||||
[sym::non_exhaustive, ..] => self.check_non_exhaustive(hir_id, attr, span, target, item),
|
||||
[sym::marker, ..] => self.check_marker(hir_id, attr, span, target),
|
||||
[sym::target_feature, ..] => {
|
||||
self.check_target_feature(hir_id, attr, span, target, attrs)
|
||||
|
@ -685,9 +685,30 @@ impl<'tcx> CheckAttrVisitor<'tcx> {
|
|||
}
|
||||
|
||||
/// Checks if the `#[non_exhaustive]` attribute on an `item` is valid.
|
||||
fn check_non_exhaustive(&self, hir_id: HirId, attr: &Attribute, span: Span, target: Target) {
|
||||
fn check_non_exhaustive(
|
||||
&self,
|
||||
hir_id: HirId,
|
||||
attr: &Attribute,
|
||||
span: Span,
|
||||
target: Target,
|
||||
item: Option<ItemLike<'_>>,
|
||||
) {
|
||||
match target {
|
||||
Target::Struct | Target::Enum | Target::Variant => {}
|
||||
Target::Struct => {
|
||||
if let Some(ItemLike::Item(hir::Item {
|
||||
kind: hir::ItemKind::Struct(hir::VariantData::Struct { fields, .. }, _),
|
||||
..
|
||||
})) = item
|
||||
&& !fields.is_empty()
|
||||
&& fields.iter().any(|f| f.default.is_some())
|
||||
{
|
||||
self.dcx().emit_err(errors::NonExhaustiveWithDefaultFieldValues {
|
||||
attr_span: attr.span,
|
||||
defn_span: span,
|
||||
});
|
||||
}
|
||||
}
|
||||
Target::Enum | Target::Variant => {}
|
||||
// FIXME(#80564): We permit struct fields, match arms and macro defs to have an
|
||||
// `#[non_exhaustive]` attribute with just a lint, because we previously
|
||||
// erroneously allowed it and some crates used it accidentally, to be compatible
|
||||
|
|
|
@ -119,6 +119,15 @@ pub(crate) struct NonExhaustiveWrongLocation {
|
|||
pub defn_span: Span,
|
||||
}
|
||||
|
||||
#[derive(Diagnostic)]
|
||||
#[diag(passes_non_exaustive_with_default_field_values)]
|
||||
pub(crate) struct NonExhaustiveWithDefaultFieldValues {
|
||||
#[primary_span]
|
||||
pub attr_span: Span,
|
||||
#[label]
|
||||
pub defn_span: Span,
|
||||
}
|
||||
|
||||
#[derive(Diagnostic)]
|
||||
#[diag(passes_should_be_applied_to_trait)]
|
||||
pub(crate) struct AttrShouldBeAppliedToTrait {
|
||||
|
|
18
tests/ui/structs/default-field-values-non_exhaustive.rs
Normal file
18
tests/ui/structs/default-field-values-non_exhaustive.rs
Normal file
|
@ -0,0 +1,18 @@
|
|||
#![feature(default_field_values)]
|
||||
|
||||
#[derive(Default)]
|
||||
#[non_exhaustive] //~ ERROR `#[non_exhaustive]` can't be used to annotate items with default field values
|
||||
struct Foo {
|
||||
x: i32 = 42 + 3,
|
||||
}
|
||||
|
||||
#[derive(Default)]
|
||||
enum Bar {
|
||||
#[non_exhaustive]
|
||||
#[default]
|
||||
Baz { //~ ERROR default variant must be exhaustive
|
||||
x: i32 = 42 + 3,
|
||||
}
|
||||
}
|
||||
|
||||
fn main () {}
|
23
tests/ui/structs/default-field-values-non_exhaustive.stderr
Normal file
23
tests/ui/structs/default-field-values-non_exhaustive.stderr
Normal file
|
@ -0,0 +1,23 @@
|
|||
error: default variant must be exhaustive
|
||||
--> $DIR/default-field-values-non_exhaustive.rs:13:5
|
||||
|
|
||||
LL | #[non_exhaustive]
|
||||
| ----------------- declared `#[non_exhaustive]` here
|
||||
LL | #[default]
|
||||
LL | Baz {
|
||||
| ^^^
|
||||
|
|
||||
= help: consider a manual implementation of `Default`
|
||||
|
||||
error: `#[non_exhaustive]` can't be used to annotate items with default field values
|
||||
--> $DIR/default-field-values-non_exhaustive.rs:4:1
|
||||
|
|
||||
LL | #[non_exhaustive]
|
||||
| ^^^^^^^^^^^^^^^^^
|
||||
LL | / struct Foo {
|
||||
LL | | x: i32 = 42 + 3,
|
||||
LL | | }
|
||||
| |_- this struct has default field values
|
||||
|
||||
error: aborting due to 2 previous errors
|
||||
|
Loading…
Add table
Add a link
Reference in a new issue