Skip to content

Use E0665 for missing #[default] on enum and update doc #134364

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 2 commits into from
Dec 22, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
6 changes: 3 additions & 3 deletions compiler/rustc_builtin_macros/messages.ftl
Original file line number Diff line number Diff line change
Expand Up @@ -249,9 +249,9 @@ builtin_macros_naked_functions_testing_attribute =
.label = function marked with testing attribute here
.naked_attribute = `#[naked]` is incompatible with testing attributes

builtin_macros_no_default_variant = no default declared
.help = make a unit variant default by placing `#[default]` above it
.suggestion = make `{$ident}` default
builtin_macros_no_default_variant = `#[derive(Default)]` on enum with no `#[default]`
.label = this enum needs a unit variant marked with `#[default]`
.suggestion = make this unit variant default by placing `#[default]` on it

builtin_macros_non_abi = at least one abi must be provided as an argument to `clobber_abi`

Expand Down
13 changes: 9 additions & 4 deletions compiler/rustc_builtin_macros/src/deriving/default.rs
Original file line number Diff line number Diff line change
Expand Up @@ -42,7 +42,9 @@ pub(crate) fn expand_deriving_default(
StaticStruct(_, fields) => {
default_struct_substructure(cx, trait_span, substr, fields)
}
StaticEnum(enum_def, _) => default_enum_substructure(cx, trait_span, enum_def),
StaticEnum(enum_def, _) => {
default_enum_substructure(cx, trait_span, enum_def, item.span())
}
_ => cx.dcx().span_bug(trait_span, "method in `derive(Default)`"),
}
})),
Expand Down Expand Up @@ -96,9 +98,10 @@ fn default_enum_substructure(
cx: &ExtCtxt<'_>,
trait_span: Span,
enum_def: &EnumDef,
item_span: Span,
) -> BlockOrExpr {
let expr = match try {
let default_variant = extract_default_variant(cx, enum_def, trait_span)?;
let default_variant = extract_default_variant(cx, enum_def, trait_span, item_span)?;
validate_default_attribute(cx, default_variant)?;
default_variant
} {
Expand Down Expand Up @@ -146,6 +149,7 @@ fn extract_default_variant<'a>(
cx: &ExtCtxt<'_>,
enum_def: &'a EnumDef,
trait_span: Span,
item_span: Span,
) -> Result<&'a rustc_ast::Variant, ErrorGuaranteed> {
let default_variants: SmallVec<[_; 1]> = enum_def
.variants
Expand All @@ -163,9 +167,10 @@ fn extract_default_variant<'a>(
.filter(|variant| !attr::contains_name(&variant.attrs, sym::non_exhaustive));

let suggs = possible_defaults
.map(|v| errors::NoDefaultVariantSugg { span: v.span, ident: v.ident })
.map(|v| errors::NoDefaultVariantSugg { span: v.span.shrink_to_lo() })
.collect();
let guar = cx.dcx().emit_err(errors::NoDefaultVariant { span: trait_span, suggs });
let guar =
cx.dcx().emit_err(errors::NoDefaultVariant { span: trait_span, item_span, suggs });

return Err(guar);
}
Expand Down
13 changes: 4 additions & 9 deletions compiler/rustc_builtin_macros/src/errors.rs
Original file line number Diff line number Diff line change
Expand Up @@ -369,26 +369,21 @@ pub(crate) struct DerivePathArgsValue {
}

#[derive(Diagnostic)]
#[diag(builtin_macros_no_default_variant)]
#[help]
#[diag(builtin_macros_no_default_variant, code = E0665)]
pub(crate) struct NoDefaultVariant {
#[primary_span]
pub(crate) span: Span,
#[label]
pub(crate) item_span: Span,
#[subdiagnostic]
pub(crate) suggs: Vec<NoDefaultVariantSugg>,
}

#[derive(Subdiagnostic)]
#[suggestion(
builtin_macros_suggestion,
code = "#[default] {ident}",
applicability = "maybe-incorrect",
style = "tool-only"
)]
#[suggestion(builtin_macros_suggestion, code = "#[default] ", applicability = "maybe-incorrect")]
pub(crate) struct NoDefaultVariantSugg {
#[primary_span]
pub(crate) span: Span,
pub(crate) ident: Ident,
}

#[derive(Diagnostic)]
Expand Down
25 changes: 18 additions & 7 deletions compiler/rustc_error_codes/src/error_codes/E0665.md
Copy link
Member

@fmease fmease Dec 16, 2024

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This error code is no longer emitted by the compiler and I don't see the point in updating this entry if it no longer sees the light of day (ignoring the use of old rustc verions & subsequent exposure via the website).

The diagnostic which gets currently emitted on a #[derive(Default)] enum without #[default] doesn't have any error code associated with it. I don't know why it didn't take over E0665. If you make it use E0665 (I think that makes sense), then I'm fine with updating this entry.

Original file line number Diff line number Diff line change
@@ -1,10 +1,9 @@
#### Note: this error code is no longer emitted by the compiler.

The `Default` trait was derived on an enum.
The `Default` trait was derived on an enum without specifying the default
variant.

Erroneous code example:

```compile_fail
```compile_fail,E0665
#[derive(Default)]
enum Food {
Sweet,
Expand All @@ -16,18 +15,30 @@ The `Default` cannot be derived on an enum for the simple reason that the
compiler doesn't know which value to pick by default whereas it can for a
struct as long as all its fields implement the `Default` trait as well.

If you still want to implement `Default` on your enum, you'll have to do it "by
hand":
For the case where the desired default variant has no payload, you can
annotate it with `#[default]` to derive it:

```
#[derive(Default)]
enum Food {
#[default]
Sweet,
Salty,
}
```

In the case where the default variant does have a payload, you will have to
implement `Default` on your enum manually:

```
enum Food {
Sweet(i32),
Salty,
}

impl Default for Food {
fn default() -> Food {
Food::Sweet
Food::Sweet(1)
}
}
```
8 changes: 7 additions & 1 deletion tests/ui/macros/macros-nonfatal-errors.rs
Original file line number Diff line number Diff line change
Expand Up @@ -39,12 +39,18 @@ enum AttrOnInnerExpression {
Baz,
}

#[derive(Default)] //~ ERROR no default declared
#[derive(Default)] //~ ERROR `#[derive(Default)]` on enum with no `#[default]`
enum NoDeclaredDefault {
Foo,
Bar,
}

#[derive(Default)] //~ ERROR `#[derive(Default)]` on enum with no `#[default]`
enum NoDeclaredDefaultWithoutUnitVariant {
Foo(i32),
Bar(i32),
}

#[derive(Default)] //~ ERROR multiple declared defaults
enum MultipleDefaults {
#[default]
Expand Down
82 changes: 54 additions & 28 deletions tests/ui/macros/macros-nonfatal-errors.stderr
Original file line number Diff line number Diff line change
Expand Up @@ -46,18 +46,43 @@ LL | Bar([u8; #[default] 1]),
|
= help: consider a manual implementation of `Default`

error: no default declared
error[E0665]: `#[derive(Default)]` on enum with no `#[default]`
--> $DIR/macros-nonfatal-errors.rs:42:10
|
LL | #[derive(Default)]
| ^^^^^^^
LL | #[derive(Default)]
| ^^^^^^^
LL | / enum NoDeclaredDefault {
LL | | Foo,
LL | | Bar,
LL | | }
| |_- this enum needs a unit variant marked with `#[default]`
|
= help: make a unit variant default by placing `#[default]` above it
= note: this error originates in the derive macro `Default` (in Nightly builds, run with -Z macro-backtrace for more info)
help: make this unit variant default by placing `#[default]` on it
|
LL | #[default] Foo,
| ++++++++++
help: make this unit variant default by placing `#[default]` on it
|
LL | #[default] Bar,
| ++++++++++

error: multiple declared defaults
error[E0665]: `#[derive(Default)]` on enum with no `#[default]`
--> $DIR/macros-nonfatal-errors.rs:48:10
|
LL | #[derive(Default)]
| ^^^^^^^
LL | / enum NoDeclaredDefaultWithoutUnitVariant {
LL | | Foo(i32),
LL | | Bar(i32),
LL | | }
| |_- this enum needs a unit variant marked with `#[default]`
|
= note: this error originates in the derive macro `Default` (in Nightly builds, run with -Z macro-backtrace for more info)

error: multiple declared defaults
--> $DIR/macros-nonfatal-errors.rs:54:10
|
LL | #[derive(Default)]
| ^^^^^^^
...
Expand All @@ -74,15 +99,15 @@ LL | Baz,
= note: this error originates in the derive macro `Default` (in Nightly builds, run with -Z macro-backtrace for more info)

error: `#[default]` attribute does not accept a value
--> $DIR/macros-nonfatal-errors.rs:60:5
--> $DIR/macros-nonfatal-errors.rs:66:5
|
LL | #[default = 1]
| ^^^^^^^^^^^^^^
|
= help: try using `#[default]`

error: multiple `#[default]` attributes
--> $DIR/macros-nonfatal-errors.rs:68:5
--> $DIR/macros-nonfatal-errors.rs:74:5
|
LL | #[default]
| ---------- `#[default]` used here
Expand All @@ -93,13 +118,13 @@ LL | Foo,
|
= note: only one `#[default]` attribute is needed
help: try removing this
--> $DIR/macros-nonfatal-errors.rs:67:5
--> $DIR/macros-nonfatal-errors.rs:73:5
|
LL | #[default]
| ^^^^^^^^^^

error: multiple `#[default]` attributes
--> $DIR/macros-nonfatal-errors.rs:78:5
--> $DIR/macros-nonfatal-errors.rs:84:5
|
LL | #[default]
| ---------- `#[default]` used here
Expand All @@ -111,7 +136,7 @@ LL | Foo,
|
= note: only one `#[default]` attribute is needed
help: try removing these
--> $DIR/macros-nonfatal-errors.rs:75:5
--> $DIR/macros-nonfatal-errors.rs:81:5
|
LL | #[default]
| ^^^^^^^^^^
Expand All @@ -121,15 +146,15 @@ LL | #[default]
| ^^^^^^^^^^

error: the `#[default]` attribute may only be used on unit enum variants
--> $DIR/macros-nonfatal-errors.rs:85:5
--> $DIR/macros-nonfatal-errors.rs:91:5
|
LL | Foo {},
| ^^^
|
= help: consider a manual implementation of `Default`

error: default variant must be exhaustive
--> $DIR/macros-nonfatal-errors.rs:93:5
--> $DIR/macros-nonfatal-errors.rs:99:5
|
LL | #[non_exhaustive]
| ----------------- declared `#[non_exhaustive]` here
Expand All @@ -139,37 +164,37 @@ LL | Foo,
= help: consider a manual implementation of `Default`

error: asm template must be a string literal
--> $DIR/macros-nonfatal-errors.rs:98:10
--> $DIR/macros-nonfatal-errors.rs:104:10
|
LL | asm!(invalid);
| ^^^^^^^

error: `concat_idents!()` requires ident args
--> $DIR/macros-nonfatal-errors.rs:101:5
--> $DIR/macros-nonfatal-errors.rs:107:5
|
LL | concat_idents!("not", "idents");
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^

error: argument must be a string literal
--> $DIR/macros-nonfatal-errors.rs:103:17
--> $DIR/macros-nonfatal-errors.rs:109:17
|
LL | option_env!(invalid);
| ^^^^^^^

error: expected string literal
--> $DIR/macros-nonfatal-errors.rs:104:10
--> $DIR/macros-nonfatal-errors.rs:110:10
|
LL | env!(invalid);
| ^^^^^^^

error: `env!()` takes 1 or 2 arguments
--> $DIR/macros-nonfatal-errors.rs:105:5
--> $DIR/macros-nonfatal-errors.rs:111:5
|
LL | env!(foo, abr, baz);
| ^^^^^^^^^^^^^^^^^^^

error: environment variable `RUST_HOPEFULLY_THIS_DOESNT_EXIST` not defined at compile time
--> $DIR/macros-nonfatal-errors.rs:106:5
--> $DIR/macros-nonfatal-errors.rs:112:5
|
LL | env!("RUST_HOPEFULLY_THIS_DOESNT_EXIST");
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
Expand All @@ -178,7 +203,7 @@ LL | env!("RUST_HOPEFULLY_THIS_DOESNT_EXIST");
= note: this error originates in the macro `env` (in Nightly builds, run with -Z macro-backtrace for more info)

error: format argument must be a string literal
--> $DIR/macros-nonfatal-errors.rs:108:13
--> $DIR/macros-nonfatal-errors.rs:114:13
|
LL | format!(invalid);
| ^^^^^^^
Expand All @@ -189,47 +214,47 @@ LL | format!("{}", invalid);
| +++++

error: argument must be a string literal
--> $DIR/macros-nonfatal-errors.rs:110:14
--> $DIR/macros-nonfatal-errors.rs:116:14
|
LL | include!(invalid);
| ^^^^^^^

error: argument must be a string literal
--> $DIR/macros-nonfatal-errors.rs:112:18
--> $DIR/macros-nonfatal-errors.rs:118:18
|
LL | include_str!(invalid);
| ^^^^^^^

error: couldn't read `$DIR/i'd be quite surprised if a file with this name existed`: $FILE_NOT_FOUND_MSG
--> $DIR/macros-nonfatal-errors.rs:113:5
--> $DIR/macros-nonfatal-errors.rs:119:5
|
LL | include_str!("i'd be quite surprised if a file with this name existed");
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
|
= note: this error originates in the macro `include_str` (in Nightly builds, run with -Z macro-backtrace for more info)

error: argument must be a string literal
--> $DIR/macros-nonfatal-errors.rs:114:20
--> $DIR/macros-nonfatal-errors.rs:120:20
|
LL | include_bytes!(invalid);
| ^^^^^^^

error: couldn't read `$DIR/i'd be quite surprised if a file with this name existed`: $FILE_NOT_FOUND_MSG
--> $DIR/macros-nonfatal-errors.rs:115:5
--> $DIR/macros-nonfatal-errors.rs:121:5
|
LL | include_bytes!("i'd be quite surprised if a file with this name existed");
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
|
= note: this error originates in the macro `include_bytes` (in Nightly builds, run with -Z macro-backtrace for more info)

error: trace_macros! accepts only `true` or `false`
--> $DIR/macros-nonfatal-errors.rs:117:5
--> $DIR/macros-nonfatal-errors.rs:123:5
|
LL | trace_macros!(invalid);
| ^^^^^^^^^^^^^^^^^^^^^^

error: default variant must be exhaustive
--> $DIR/macros-nonfatal-errors.rs:127:9
--> $DIR/macros-nonfatal-errors.rs:133:9
|
LL | #[non_exhaustive]
| ----------------- declared `#[non_exhaustive]` here
Expand All @@ -239,10 +264,11 @@ LL | Foo,
= help: consider a manual implementation of `Default`

error: cannot find macro `llvm_asm` in this scope
--> $DIR/macros-nonfatal-errors.rs:99:5
--> $DIR/macros-nonfatal-errors.rs:105:5
|
LL | llvm_asm!(invalid);
| ^^^^^^^^

error: aborting due to 28 previous errors
error: aborting due to 29 previous errors

For more information about this error, try `rustc --explain E0665`.
Loading