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}
|
`#[no_sanitize({$attr_str})]` should be applied to {$accepted_kind}
|
||||||
.label = not {$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 =
|
passes_non_exported_macro_invalid_attrs =
|
||||||
attribute should be applied to function or closure
|
attribute should be applied to function or closure
|
||||||
.label = not a 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::coverage, ..] => self.check_coverage(attr, span, target),
|
||||||
[sym::optimize, ..] => self.check_optimize(hir_id, attr, span, target),
|
[sym::optimize, ..] => self.check_optimize(hir_id, attr, span, target),
|
||||||
[sym::no_sanitize, ..] => self.check_no_sanitize(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::marker, ..] => self.check_marker(hir_id, attr, span, target),
|
||||||
[sym::target_feature, ..] => {
|
[sym::target_feature, ..] => {
|
||||||
self.check_target_feature(hir_id, attr, span, target, attrs)
|
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.
|
/// 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 {
|
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
|
// FIXME(#80564): We permit struct fields, match arms and macro defs to have an
|
||||||
// `#[non_exhaustive]` attribute with just a lint, because we previously
|
// `#[non_exhaustive]` attribute with just a lint, because we previously
|
||||||
// erroneously allowed it and some crates used it accidentally, to be compatible
|
// erroneously allowed it and some crates used it accidentally, to be compatible
|
||||||
|
|
|
@ -119,6 +119,15 @@ pub(crate) struct NonExhaustiveWrongLocation {
|
||||||
pub defn_span: Span,
|
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)]
|
#[derive(Diagnostic)]
|
||||||
#[diag(passes_should_be_applied_to_trait)]
|
#[diag(passes_should_be_applied_to_trait)]
|
||||||
pub(crate) struct AttrShouldBeAppliedToTrait {
|
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