about summary refs log tree commit diff
diff options
context:
space:
mode:
authorJacob Pratt <jacob@jhpratt.dev>2021-06-29 20:22:52 -0400
committerJacob Pratt <jacob@jhpratt.dev>2021-07-27 15:47:47 -0400
commitc70147fd66e08962ab06adf12eb6a41bc1ea7f08 (patch)
tree3efabfe7f35fb460fdee7dbf4ec35c8d4b5305d3
parentfd853c00e255559255885aadff9e93a1760c8728 (diff)
downloadrust-c70147fd66e08962ab06adf12eb6a41bc1ea7f08.tar.gz
rust-c70147fd66e08962ab06adf12eb6a41bc1ea7f08.zip
Permit deriving default on enums with `#[default]`
-rw-r--r--compiler/rustc_builtin_macros/src/deriving/default.rs197
-rw-r--r--compiler/rustc_feature/src/active.rs3
-rw-r--r--compiler/rustc_span/src/symbol.rs1
-rw-r--r--library/core/src/default.rs3
-rw-r--r--src/test/ui/deriving/deriving-default-enum.rs19
-rw-r--r--src/test/ui/deriving/deriving-with-helper.rs5
-rw-r--r--src/test/ui/error-codes/E0665.rs8
-rw-r--r--src/test/ui/error-codes/E0665.stderr11
-rw-r--r--src/test/ui/feature-gates/feature-gate-derive_default_enum.rs7
-rw-r--r--src/test/ui/feature-gates/feature-gate-derive_default_enum.stderr13
-rw-r--r--src/test/ui/macros/macros-nonfatal-errors.rs57
-rw-r--r--src/test/ui/macros/macros-nonfatal-errors.stderr119
-rw-r--r--src/test/ui/resolve/issue-2356.rs2
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 {}
   }
 }