diff options
| author | Jacob Pratt <jacob@jhpratt.dev> | 2021-06-29 20:22:52 -0400 |
|---|---|---|
| committer | Jacob Pratt <jacob@jhpratt.dev> | 2021-07-27 15:47:47 -0400 |
| commit | c70147fd66e08962ab06adf12eb6a41bc1ea7f08 (patch) | |
| tree | 3efabfe7f35fb460fdee7dbf4ec35c8d4b5305d3 | |
| parent | fd853c00e255559255885aadff9e93a1760c8728 (diff) | |
| download | rust-c70147fd66e08962ab06adf12eb6a41bc1ea7f08.tar.gz rust-c70147fd66e08962ab06adf12eb6a41bc1ea7f08.zip | |
Permit deriving default on enums with `#[default]`
| -rw-r--r-- | compiler/rustc_builtin_macros/src/deriving/default.rs | 197 | ||||
| -rw-r--r-- | compiler/rustc_feature/src/active.rs | 3 | ||||
| -rw-r--r-- | compiler/rustc_span/src/symbol.rs | 1 | ||||
| -rw-r--r-- | library/core/src/default.rs | 3 | ||||
| -rw-r--r-- | src/test/ui/deriving/deriving-default-enum.rs | 19 | ||||
| -rw-r--r-- | src/test/ui/deriving/deriving-with-helper.rs | 5 | ||||
| -rw-r--r-- | src/test/ui/error-codes/E0665.rs | 8 | ||||
| -rw-r--r-- | src/test/ui/error-codes/E0665.stderr | 11 | ||||
| -rw-r--r-- | src/test/ui/feature-gates/feature-gate-derive_default_enum.rs | 7 | ||||
| -rw-r--r-- | src/test/ui/feature-gates/feature-gate-derive_default_enum.stderr | 13 | ||||
| -rw-r--r-- | src/test/ui/macros/macros-nonfatal-errors.rs | 57 | ||||
| -rw-r--r-- | src/test/ui/macros/macros-nonfatal-errors.stderr | 119 | ||||
| -rw-r--r-- | src/test/ui/resolve/issue-2356.rs | 2 |
13 files changed, 371 insertions, 74 deletions
diff --git a/compiler/rustc_builtin_macros/src/deriving/default.rs b/compiler/rustc_builtin_macros/src/deriving/default.rs index 980be3a0050..7c1dc5e5365 100644 --- a/compiler/rustc_builtin_macros/src/deriving/default.rs +++ b/compiler/rustc_builtin_macros/src/deriving/default.rs @@ -2,11 +2,15 @@ use crate::deriving::generic::ty::*; use crate::deriving::generic::*; use rustc_ast::ptr::P; +use rustc_ast::EnumDef; +use rustc_ast::VariantData; use rustc_ast::{Expr, MetaItem}; -use rustc_errors::struct_span_err; +use rustc_errors::Applicability; use rustc_expand::base::{Annotatable, DummyResult, ExtCtxt}; +use rustc_span::symbol::Ident; use rustc_span::symbol::{kw, sym}; use rustc_span::Span; +use smallvec::SmallVec; pub fn expand_deriving_default( cx: &mut ExtCtxt<'_>, @@ -34,8 +38,25 @@ pub fn expand_deriving_default( attributes: attrs, is_unsafe: false, unify_fieldless_variants: false, - combine_substructure: combine_substructure(Box::new(|a, b, c| { - default_substructure(a, b, c) + combine_substructure: combine_substructure(Box::new(|cx, trait_span, substr| { + match substr.fields { + StaticStruct(_, fields) => { + default_struct_substructure(cx, trait_span, substr, fields) + } + StaticEnum(enum_def, _) => { + if !cx.sess.features_untracked().derive_default_enum { + rustc_session::parse::feature_err( + cx.parse_sess(), + sym::derive_default_enum, + span, + "deriving `Default` on enums is experimental", + ) + .emit(); + } + default_enum_substructure(cx, trait_span, enum_def) + } + _ => cx.span_bug(trait_span, "method in `derive(Default)`"), + } })), }], associated_types: Vec::new(), @@ -43,44 +64,158 @@ pub fn expand_deriving_default( trait_def.expand(cx, mitem, item, push) } -fn default_substructure( +fn default_struct_substructure( cx: &mut ExtCtxt<'_>, trait_span: Span, substr: &Substructure<'_>, + summary: &StaticFields, ) -> P<Expr> { // Note that `kw::Default` is "default" and `sym::Default` is "Default"! let default_ident = cx.std_path(&[kw::Default, sym::Default, kw::Default]); let default_call = |span| cx.expr_call_global(span, default_ident.clone(), Vec::new()); - match *substr.fields { - StaticStruct(_, ref summary) => match *summary { - Unnamed(ref fields, is_tuple) => { - if !is_tuple { - cx.expr_ident(trait_span, substr.type_ident) - } else { - let exprs = fields.iter().map(|sp| default_call(*sp)).collect(); - cx.expr_call_ident(trait_span, substr.type_ident, exprs) - } - } - Named(ref fields) => { - let default_fields = fields - .iter() - .map(|&(ident, span)| cx.field_imm(span, ident, default_call(span))) - .collect(); - cx.expr_struct_ident(trait_span, substr.type_ident, default_fields) + match summary { + Unnamed(ref fields, is_tuple) => { + if !is_tuple { + cx.expr_ident(trait_span, substr.type_ident) + } else { + let exprs = fields.iter().map(|sp| default_call(*sp)).collect(); + cx.expr_call_ident(trait_span, substr.type_ident, exprs) } - }, - StaticEnum(..) => { - struct_span_err!( - &cx.sess.parse_sess.span_diagnostic, - trait_span, - E0665, - "`Default` cannot be derived for enums, only structs" - ) + } + Named(ref fields) => { + let default_fields = fields + .iter() + .map(|&(ident, span)| cx.field_imm(span, ident, default_call(span))) + .collect(); + cx.expr_struct_ident(trait_span, substr.type_ident, default_fields) + } + } +} + +fn default_enum_substructure( + cx: &mut ExtCtxt<'_>, + trait_span: Span, + enum_def: &EnumDef, +) -> P<Expr> { + let default_variant = match extract_default_variant(cx, enum_def, trait_span) { + Ok(value) => value, + Err(()) => return DummyResult::raw_expr(trait_span, true), + }; + + // At this point, we know that there is exactly one variant with a `#[default]` attribute. The + // attribute hasn't yet been validated. + + if let Err(()) = validate_default_attribute(cx, default_variant) { + return DummyResult::raw_expr(trait_span, true); + } + + // We now know there is exactly one unit variant with exactly one `#[default]` attribute. + + cx.expr_path(cx.path( + default_variant.span, + vec![Ident::new(kw::SelfUpper, default_variant.span), default_variant.ident], + )) +} + +fn extract_default_variant<'a>( + cx: &mut ExtCtxt<'_>, + enum_def: &'a EnumDef, + trait_span: Span, +) -> Result<&'a rustc_ast::Variant, ()> { + let default_variants: SmallVec<[_; 1]> = enum_def + .variants + .iter() + .filter(|variant| cx.sess.contains_name(&variant.attrs, kw::Default)) + .collect(); + + let variant = match default_variants.as_slice() { + [variant] => variant, + [] => { + cx.struct_span_err(trait_span, "no default declared") + .help("make a unit variant default by placing `#[default]` above it") + .emit(); + + return Err(()); + } + [first, rest @ ..] => { + cx.struct_span_err(trait_span, "multiple declared defaults") + .span_label(first.span, "first default") + .span_labels(rest.iter().map(|variant| variant.span), "additional default") + .note("only one variant can be default") + .emit(); + + return Err(()); + } + }; + + if !matches!(variant.data, VariantData::Unit(..)) { + cx.struct_span_err(variant.ident.span, "`#[default]` may only be used on unit variants") + .help("consider a manual implementation of `Default`") + .emit(); + + return Err(()); + } + + if let Some(non_exhaustive_attr) = cx.sess.find_by_name(&variant.attrs, sym::non_exhaustive) { + cx.struct_span_err(variant.ident.span, "default variant must be exhaustive") + .span_label(non_exhaustive_attr.span, "declared `#[non_exhaustive]` here") + .help("consider a manual implementation of `Default`") .emit(); - // let compilation continue - DummyResult::raw_expr(trait_span, true) + + return Err(()); + } + + Ok(variant) +} + +fn validate_default_attribute( + cx: &mut ExtCtxt<'_>, + default_variant: &rustc_ast::Variant, +) -> Result<(), ()> { + let attrs: SmallVec<[_; 1]> = + cx.sess.filter_by_name(&default_variant.attrs, kw::Default).collect(); + + let attr = match attrs.as_slice() { + [attr] => attr, + [] => cx.bug( + "this method must only be called with a variant that has a `#[default]` attribute", + ), + [first, rest @ ..] => { + // FIXME(jhpratt) Do we want to perform this check? It doesn't exist + // for `#[inline]`, `#[non_exhaustive]`, and presumably others. + + let suggestion_text = + if rest.len() == 1 { "try removing this" } else { "try removing these" }; + + cx.struct_span_err(default_variant.ident.span, "multiple `#[default]` attributes") + .note("only one `#[default]` attribute is needed") + .span_label(first.span, "`#[default]` used here") + .span_label(rest[0].span, "`#[default]` used again here") + .span_help(rest.iter().map(|attr| attr.span).collect::<Vec<_>>(), suggestion_text) + // This would otherwise display the empty replacement, hence the otherwise + // repetitive `.span_help` call above. + .tool_only_multipart_suggestion( + suggestion_text, + rest.iter().map(|attr| (attr.span, String::new())).collect(), + Applicability::MachineApplicable, + ) + .emit(); + + return Err(()); } - _ => cx.span_bug(trait_span, "method in `derive(Default)`"), + }; + if !attr.is_word() { + cx.struct_span_err(attr.span, "`#[default]` attribute does not accept a value") + .span_suggestion_hidden( + attr.span, + "try using `#[default]`", + "#[default]".into(), + Applicability::MaybeIncorrect, + ) + .emit(); + + return Err(()); } + Ok(()) } diff --git a/compiler/rustc_feature/src/active.rs b/compiler/rustc_feature/src/active.rs index 803e4a2e59d..41351c1f938 100644 --- a/compiler/rustc_feature/src/active.rs +++ b/compiler/rustc_feature/src/active.rs @@ -683,6 +683,9 @@ declare_features! ( /// Infer generic args for both consts and types. (active, generic_arg_infer, "1.55.0", Some(85077), None), + /// Allows `#[derive(Default)]` and `#[default]` on enums. + (active, derive_default_enum, "1.56.0", Some(86985), None), + // ------------------------------------------------------------------------- // feature-group-end: actual feature gates // ------------------------------------------------------------------------- diff --git a/compiler/rustc_span/src/symbol.rs b/compiler/rustc_span/src/symbol.rs index 536ebdef426..5fc773e431c 100644 --- a/compiler/rustc_span/src/symbol.rs +++ b/compiler/rustc_span/src/symbol.rs @@ -489,6 +489,7 @@ symbols! { deref_mut, deref_target, derive, + derive_default_enum, destructuring_assignment, diagnostic, direct, diff --git a/library/core/src/default.rs b/library/core/src/default.rs index fd7159d35fa..0fe88222805 100644 --- a/library/core/src/default.rs +++ b/library/core/src/default.rs @@ -161,7 +161,8 @@ pub fn default<T: Default>() -> T { } /// Derive macro generating an impl of the trait `Default`. -#[rustc_builtin_macro] +#[cfg_attr(not(bootstrap), rustc_builtin_macro(Default, attributes(default)))] +#[cfg_attr(bootstrap, rustc_builtin_macro)] #[stable(feature = "builtin_macro_prelude", since = "1.38.0")] #[allow_internal_unstable(core_intrinsics)] pub macro Default($item:item) { diff --git a/src/test/ui/deriving/deriving-default-enum.rs b/src/test/ui/deriving/deriving-default-enum.rs new file mode 100644 index 00000000000..931ff1a5847 --- /dev/null +++ b/src/test/ui/deriving/deriving-default-enum.rs @@ -0,0 +1,19 @@ +// run-pass + +#![feature(derive_default_enum)] + +// nb: does not impl Default +#[derive(Debug, PartialEq)] +struct NotDefault; + +#[derive(Debug, Default, PartialEq)] +enum Foo { + #[default] + Alpha, + #[allow(dead_code)] + Beta(NotDefault), +} + +fn main() { + assert_eq!(Foo::default(), Foo::Alpha); +} diff --git a/src/test/ui/deriving/deriving-with-helper.rs b/src/test/ui/deriving/deriving-with-helper.rs index ea74a15624c..d8f0b27a2e5 100644 --- a/src/test/ui/deriving/deriving-with-helper.rs +++ b/src/test/ui/deriving/deriving-with-helper.rs @@ -5,6 +5,7 @@ #![feature(lang_items)] #![feature(no_core)] #![feature(rustc_attrs)] +#![feature(derive_default_enum)] #![no_core] @@ -30,7 +31,7 @@ mod default { trait Sized {} #[derive(Default)] -struct S { +enum S { #[default] // OK - field: u8, + Foo, } diff --git a/src/test/ui/error-codes/E0665.rs b/src/test/ui/error-codes/E0665.rs deleted file mode 100644 index cfd42bd9aac..00000000000 --- a/src/test/ui/error-codes/E0665.rs +++ /dev/null @@ -1,8 +0,0 @@ -#[derive(Default)] //~ ERROR E0665 -enum Food { - Sweet, - Salty, -} - -fn main() { -} diff --git a/src/test/ui/error-codes/E0665.stderr b/src/test/ui/error-codes/E0665.stderr deleted file mode 100644 index bb8b3906ca6..00000000000 --- a/src/test/ui/error-codes/E0665.stderr +++ /dev/null @@ -1,11 +0,0 @@ -error[E0665]: `Default` cannot be derived for enums, only structs - --> $DIR/E0665.rs:1:10 - | -LL | #[derive(Default)] - | ^^^^^^^ - | - = note: this error originates in the derive macro `Default` (in Nightly builds, run with -Z macro-backtrace for more info) - -error: aborting due to previous error - -For more information about this error, try `rustc --explain E0665`. diff --git a/src/test/ui/feature-gates/feature-gate-derive_default_enum.rs b/src/test/ui/feature-gates/feature-gate-derive_default_enum.rs new file mode 100644 index 00000000000..05a5d4e1422 --- /dev/null +++ b/src/test/ui/feature-gates/feature-gate-derive_default_enum.rs @@ -0,0 +1,7 @@ +#[derive(Default)] //~ ERROR deriving `Default` on enums is experimental +enum Foo { + #[default] + Alpha, +} + +fn main() {} diff --git a/src/test/ui/feature-gates/feature-gate-derive_default_enum.stderr b/src/test/ui/feature-gates/feature-gate-derive_default_enum.stderr new file mode 100644 index 00000000000..58dd4d508a7 --- /dev/null +++ b/src/test/ui/feature-gates/feature-gate-derive_default_enum.stderr @@ -0,0 +1,13 @@ +error[E0658]: deriving `Default` on enums is experimental + --> $DIR/feature-gate-derive_default_enum.rs:1:10 + | +LL | #[derive(Default)] + | ^^^^^^^ + | + = note: see issue #86985 <https://github.com/rust-lang/rust/issues/86985> for more information + = help: add `#![feature(derive_default_enum)]` to the crate attributes to enable + = note: this error originates in the derive macro `Default` (in Nightly builds, run with -Z macro-backtrace for more info) + +error: aborting due to previous error + +For more information about this error, try `rustc --explain E0658`. diff --git a/src/test/ui/macros/macros-nonfatal-errors.rs b/src/test/ui/macros/macros-nonfatal-errors.rs index 0a496c9dc3d..bb5f4d089bc 100644 --- a/src/test/ui/macros/macros-nonfatal-errors.rs +++ b/src/test/ui/macros/macros-nonfatal-errors.rs @@ -5,9 +5,62 @@ #![feature(asm, llvm_asm)] #![feature(trace_macros, concat_idents)] +#![feature(derive_default_enum)] -#[derive(Default)] //~ ERROR -enum OrDeriveThis {} +#[derive(Default)] //~ ERROR no default declared +enum NoDeclaredDefault { + Foo, + Bar, +} + +#[derive(Default)] //~ ERROR multiple declared defaults +enum MultipleDefaults { + #[default] + Foo, + #[default] + Bar, + #[default] + Baz, +} + +#[derive(Default)] +enum ExtraDeriveTokens { + #[default = 1] //~ ERROR `#[default]` attribute does not accept a value + Foo, +} + +#[derive(Default)] +enum TwoDefaultAttrs { + #[default] + #[default] + Foo, //~ERROR multiple `#[default]` attributes + Bar, +} + +#[derive(Default)] +enum ManyDefaultAttrs { + #[default] + #[default] + #[default] + #[default] + Foo, //~ERROR multiple `#[default]` attributes + Bar, +} + +#[derive(Default)] +enum DefaultHasFields { + #[default] + Foo {}, //~ ERROR `#[default]` may only be used on unit variants + Bar, +} + +#[derive(Default)] +enum NonExhaustiveDefault { + #[default] + #[non_exhaustive] + Foo, //~ ERROR default variant must be exhaustive + Bar, +} fn main() { asm!(invalid); //~ ERROR diff --git a/src/test/ui/macros/macros-nonfatal-errors.stderr b/src/test/ui/macros/macros-nonfatal-errors.stderr index 14058f86639..4bb5e9b8169 100644 --- a/src/test/ui/macros/macros-nonfatal-errors.stderr +++ b/src/test/ui/macros/macros-nonfatal-errors.stderr @@ -1,49 +1,133 @@ -error[E0665]: `Default` cannot be derived for enums, only structs - --> $DIR/macros-nonfatal-errors.rs:9:10 +error: no default declared + --> $DIR/macros-nonfatal-errors.rs:10:10 | LL | #[derive(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) +error: multiple declared defaults + --> $DIR/macros-nonfatal-errors.rs:16:10 + | +LL | #[derive(Default)] + | ^^^^^^^ +... +LL | Foo, + | --- first default +LL | #[default] +LL | Bar, + | --- additional default +LL | #[default] +LL | Baz, + | --- additional default + | + = note: only one variant can be default + = 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:28:5 + | +LL | #[default = 1] + | ^^^^^^^^^^^^^^ + | + = help: try using `#[default]` + +error: multiple `#[default]` attributes + --> $DIR/macros-nonfatal-errors.rs:36:5 + | +LL | #[default] + | ---------- `#[default]` used here +LL | #[default] + | ---------- `#[default]` used again here +LL | Foo, + | ^^^ + | + = note: only one `#[default]` attribute is needed +help: try removing this + --> $DIR/macros-nonfatal-errors.rs:35:5 + | +LL | #[default] + | ^^^^^^^^^^ + +error: multiple `#[default]` attributes + --> $DIR/macros-nonfatal-errors.rs:46:5 + | +LL | #[default] + | ---------- `#[default]` used here +LL | #[default] + | ---------- `#[default]` used again here +... +LL | Foo, + | ^^^ + | + = note: only one `#[default]` attribute is needed +help: try removing these + --> $DIR/macros-nonfatal-errors.rs:43:5 + | +LL | #[default] + | ^^^^^^^^^^ +LL | #[default] + | ^^^^^^^^^^ +LL | #[default] + | ^^^^^^^^^^ + +error: `#[default]` may only be used on unit variants + --> $DIR/macros-nonfatal-errors.rs:53:5 + | +LL | Foo {}, + | ^^^ + | + = help: consider a manual implementation of `Default` + +error: default variant must be exhaustive + --> $DIR/macros-nonfatal-errors.rs:61:5 + | +LL | #[non_exhaustive] + | ----------------- declared `#[non_exhaustive]` here +LL | Foo, + | ^^^ + | + = help: consider a manual implementation of `Default` + error: asm template must be a string literal - --> $DIR/macros-nonfatal-errors.rs:13:10 + --> $DIR/macros-nonfatal-errors.rs:66:10 | LL | asm!(invalid); | ^^^^^^^ error: inline assembly must be a string literal - --> $DIR/macros-nonfatal-errors.rs:14:15 + --> $DIR/macros-nonfatal-errors.rs:67:15 | LL | llvm_asm!(invalid); | ^^^^^^^ error: concat_idents! requires ident args. - --> $DIR/macros-nonfatal-errors.rs:16:5 + --> $DIR/macros-nonfatal-errors.rs:69:5 | LL | concat_idents!("not", "idents"); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ error: argument must be a string literal - --> $DIR/macros-nonfatal-errors.rs:18:17 + --> $DIR/macros-nonfatal-errors.rs:71:17 | LL | option_env!(invalid); | ^^^^^^^ error: expected string literal - --> $DIR/macros-nonfatal-errors.rs:19:10 + --> $DIR/macros-nonfatal-errors.rs:72:10 | LL | env!(invalid); | ^^^^^^^ error: expected string literal - --> $DIR/macros-nonfatal-errors.rs:20:10 + --> $DIR/macros-nonfatal-errors.rs:73:10 | LL | env!(foo, abr, baz); | ^^^ error: environment variable `RUST_HOPEFULLY_THIS_DOESNT_EXIST` not defined - --> $DIR/macros-nonfatal-errors.rs:21:5 + --> $DIR/macros-nonfatal-errors.rs:74:5 | LL | env!("RUST_HOPEFULLY_THIS_DOESNT_EXIST"); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ @@ -51,7 +135,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:23:13 + --> $DIR/macros-nonfatal-errors.rs:76:13 | LL | format!(invalid); | ^^^^^^^ @@ -62,19 +146,19 @@ LL | format!("{}", invalid); | ^^^^^ error: argument must be a string literal - --> $DIR/macros-nonfatal-errors.rs:25:14 + --> $DIR/macros-nonfatal-errors.rs:78:14 | LL | include!(invalid); | ^^^^^^^ error: argument must be a string literal - --> $DIR/macros-nonfatal-errors.rs:27:18 + --> $DIR/macros-nonfatal-errors.rs:80: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 (os error 2) - --> $DIR/macros-nonfatal-errors.rs:28:5 + --> $DIR/macros-nonfatal-errors.rs:81:5 | LL | include_str!("i'd be quite surprised if a file with this name existed"); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ @@ -82,13 +166,13 @@ 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:29:20 + --> $DIR/macros-nonfatal-errors.rs:82: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 (os error 2) - --> $DIR/macros-nonfatal-errors.rs:30:5 + --> $DIR/macros-nonfatal-errors.rs:83:5 | LL | include_bytes!("i'd be quite surprised if a file with this name existed"); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ @@ -96,11 +180,10 @@ 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:32:5 + --> $DIR/macros-nonfatal-errors.rs:85:5 | LL | trace_macros!(invalid); | ^^^^^^^^^^^^^^^^^^^^^^^ -error: aborting due to 15 previous errors +error: aborting due to 21 previous errors -For more information about this error, try `rustc --explain E0665`. diff --git a/src/test/ui/resolve/issue-2356.rs b/src/test/ui/resolve/issue-2356.rs index f7b2dd13dcb..fe9bf4d443e 100644 --- a/src/test/ui/resolve/issue-2356.rs +++ b/src/test/ui/resolve/issue-2356.rs @@ -29,7 +29,7 @@ impl Clone for Cat { impl Default for Cat { fn default() -> Self { default(); - //~^ ERROR cannot find function `default` + //~^ ERROR cannot find function `default` in this scope [E0425] loop {} } } |
