Skip to content

Commit

Permalink
Rollup merge of #134539 - estebank:restrict-non_exhaustive, r=jieyouxu
Browse files Browse the repository at this point in the history
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.
  • Loading branch information
matthiaskrgr authored Dec 21, 2024
2 parents 3201fe9 + b3cc9b9 commit fea6c4e
Show file tree
Hide file tree
Showing 5 changed files with 78 additions and 3 deletions.
4 changes: 4 additions & 0 deletions compiler/rustc_passes/messages.ftl
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand Down
27 changes: 24 additions & 3 deletions compiler/rustc_passes/src/check_attr.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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)
Expand Down Expand Up @@ -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
Expand Down
9 changes: 9 additions & 0 deletions compiler/rustc_passes/src/errors.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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 {
Expand Down
18 changes: 18 additions & 0 deletions tests/ui/structs/default-field-values-non_exhaustive.rs
Original file line number Diff line number Diff line change
@@ -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 changes: 23 additions & 0 deletions tests/ui/structs/default-field-values-non_exhaustive.stderr
Original file line number Diff line number Diff line change
@@ -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

0 comments on commit fea6c4e

Please sign in to comment.