diff --git a/src/librustc_lint/builtin.rs b/src/librustc_lint/builtin.rs
index 13ec27aa1ab..bb2a5cab7d9 100644
--- a/src/librustc_lint/builtin.rs
+++ b/src/librustc_lint/builtin.rs
@@ -21,6 +21,8 @@
 //! If you define a new `LateLintPass`, you will also need to add it to the
 //! `late_lint_methods!` invocation in `lib.rs`.
 
+use std::fmt::Write;
+
 use rustc::hir::def::{Res, DefKind};
 use rustc::hir::def_id::{DefId, LOCAL_CRATE};
 use rustc::ty::{self, Ty, TyCtxt, layout::VariantIdx};
@@ -1877,41 +1879,57 @@ impl<'a, 'tcx> LateLintPass<'a, 'tcx> for InvalidValue {
         const ZEROED_PATH: &[Symbol] = &[sym::core, sym::mem, sym::zeroed];
         const UININIT_PATH: &[Symbol] = &[sym::core, sym::mem, sym::uninitialized];
 
-        /// Return `false` only if we are sure this type does *not*
+        /// Information about why a type cannot be initialized this way.
+        /// Contains an error message and optionally a span to point at.
+        type InitError = (String, Option<Span>);
+
+        /// Return `Some` only if we are sure this type does *not*
         /// allow zero initialization.
-        fn ty_maybe_allows_zero_init<'tcx>(tcx: TyCtxt<'tcx>, ty: Ty<'tcx>) -> bool {
+        fn ty_find_init_error<'tcx>(tcx: TyCtxt<'tcx>, ty: Ty<'tcx>) -> Option<InitError> {
             use rustc::ty::TyKind::*;
             match ty.sty {
                 // Primitive types that don't like 0 as a value.
-                Ref(..) | FnPtr(..) | Never => false,
-                Adt(..) if ty.is_box() => false,
+                Ref(..) => Some((format!("References must be non-null"), None)),
+                Adt(..) if ty.is_box() => Some((format!("`Box` must be non-null"), None)),
+                FnPtr(..) => Some((format!("Function pointers must be non-null"), None)),
+                Never => Some((format!("The never type (`!`) has no valid value"), None)),
                 // Recurse for some compound types.
                 Adt(adt_def, substs) if !adt_def.is_union() => {
                     match adt_def.variants.len() {
-                        0 => false, // Uninhabited enum!
+                        0 => Some((format!("0-variant enums have no valid value"), None)),
                         1 => {
                             // Struct, or enum with exactly one variant.
                             // Proceed recursively, check all fields.
                             let variant = &adt_def.variants[VariantIdx::from_u32(0)];
-                            variant.fields.iter().all(|field| {
-                                ty_maybe_allows_zero_init(
+                            variant.fields.iter().find_map(|field| {
+                                ty_find_init_error(
                                     tcx,
                                     field.ty(tcx, substs),
-                                )
+                                ).map(|(mut msg, span)| if span.is_none() {
+                                    // Point to this field, should be helpful for figuring
+                                    // out where the source of the error is.
+                                    let span = tcx.def_span(field.did);
+                                    write!(&mut msg, " (in this {} field)", adt_def.descr())
+                                        .unwrap();
+                                    (msg, Some(span))
+                                } else {
+                                    // Just forward.
+                                    (msg, span)
+                                })
                             })
                         }
-                        _ => true, // Conservative fallback for multi-variant enum.
+                        _ => None, // Conservative fallback for multi-variant enum.
                     }
                 }
                 Tuple(..) => {
                     // Proceed recursively, check all fields.
-                    ty.tuple_fields().all(|field| ty_maybe_allows_zero_init(tcx, field))
+                    ty.tuple_fields().find_map(|field| ty_find_init_error(tcx, field))
                 }
                 // FIXME: Would be nice to also warn for `NonNull`/`NonZero*`.
                 // FIXME: *Only for `mem::uninitialized`*, we could also warn for `bool`,
                 //        `char`, and any multivariant enum.
                 // Conservative fallback.
-                _ => true,
+                _ => None,
             }
         }
 
@@ -1925,9 +1943,8 @@ impl<'a, 'tcx> LateLintPass<'a, 'tcx> for InvalidValue {
                         // using zeroed or uninitialized memory.
                         // We are extremely conservative with what we warn about.
                         let conjured_ty = cx.tables.expr_ty(expr);
-
-                        if !ty_maybe_allows_zero_init(cx.tcx, conjured_ty) {
-                            cx.struct_span_lint(
+                        if let Some((msg, span)) = ty_find_init_error(cx.tcx, conjured_ty) {
+                            let mut err = cx.struct_span_lint(
                                 INVALID_VALUE,
                                 expr.span,
                                 &format!(
@@ -1939,11 +1956,16 @@ impl<'a, 'tcx> LateLintPass<'a, 'tcx> for InvalidValue {
                                         "being left uninitialized"
                                     }
                                 ),
-                            )
-                            .note("this means that this code causes undefined behavior \
-                                when executed")
-                            .help("use `MaybeUninit` instead")
-                            .emit();
+                            );
+                            err.span_label(expr.span,
+                                "this code causes undefined behavior when executed");
+                            err.span_label(expr.span, "help: use `MaybeUninit<T>` instead");
+                            if let Some(span) = span {
+                                err.span_note(span, &msg);
+                            } else {
+                                err.note(&msg);
+                            }
+                            err.emit();
                         }
                     }
                 }
diff --git a/src/test/ui/lint/uninitialized-zeroed.rs b/src/test/ui/lint/uninitialized-zeroed.rs
index 8f9ca8717bd..d816479bbbb 100644
--- a/src/test/ui/lint/uninitialized-zeroed.rs
+++ b/src/test/ui/lint/uninitialized-zeroed.rs
@@ -11,8 +11,10 @@ use std::mem::{self, MaybeUninit};
 enum Void {}
 
 struct Ref(&'static i32);
+struct RefPair((&'static i32, i32));
 
 struct Wrap<T> { wrapped: T }
+enum WrapEnum<T> { Wrapped(T) }
 
 #[allow(unused)]
 fn generic<T: 'static>() {
@@ -48,6 +50,12 @@ fn main() {
         let _val: Wrap<fn()> = mem::zeroed(); //~ ERROR: does not permit zero-initialization
         let _val: Wrap<fn()> = mem::uninitialized(); //~ ERROR: does not permit being left uninitialized
 
+        let _val: WrapEnum<fn()> = mem::zeroed(); //~ ERROR: does not permit zero-initialization
+        let _val: WrapEnum<fn()> = mem::uninitialized(); //~ ERROR: does not permit being left uninitialized
+
+        let _val: Wrap<(RefPair, i32)> = mem::zeroed(); //~ ERROR: does not permit zero-initialization
+        let _val: Wrap<(RefPair, i32)> = mem::uninitialized(); //~ ERROR: does not permit being left uninitialized
+
         // Some types that should work just fine.
         let _val: Option<&'static i32> = mem::zeroed();
         let _val: Option<fn()> = mem::zeroed();
diff --git a/src/test/ui/lint/uninitialized-zeroed.stderr b/src/test/ui/lint/uninitialized-zeroed.stderr
index af54b16bd0b..1b15fc21525 100644
--- a/src/test/ui/lint/uninitialized-zeroed.stderr
+++ b/src/test/ui/lint/uninitialized-zeroed.stderr
@@ -1,169 +1,289 @@
 error: the type `&'static T` does not permit zero-initialization
-  --> $DIR/uninitialized-zeroed.rs:20:32
+  --> $DIR/uninitialized-zeroed.rs:22:32
    |
 LL |         let _val: &'static T = mem::zeroed();
    |                                ^^^^^^^^^^^^^
+   |                                |
+   |                                this code causes undefined behavior when executed
+   |                                help: use `MaybeUninit<T>` instead
    |
 note: lint level defined here
   --> $DIR/uninitialized-zeroed.rs:7:9
    |
 LL | #![deny(invalid_value)]
    |         ^^^^^^^^^^^^^
-   = note: this means that this code causes undefined behavior when executed
-   = help: use `MaybeUninit` instead
+   = note: References must be non-null
 
 error: the type `&'static T` does not permit being left uninitialized
-  --> $DIR/uninitialized-zeroed.rs:21:32
+  --> $DIR/uninitialized-zeroed.rs:23:32
    |
 LL |         let _val: &'static T = mem::uninitialized();
    |                                ^^^^^^^^^^^^^^^^^^^^
+   |                                |
+   |                                this code causes undefined behavior when executed
+   |                                help: use `MaybeUninit<T>` instead
    |
-   = note: this means that this code causes undefined behavior when executed
-   = help: use `MaybeUninit` instead
+   = note: References must be non-null
 
 error: the type `Wrap<&'static T>` does not permit zero-initialization
-  --> $DIR/uninitialized-zeroed.rs:23:38
+  --> $DIR/uninitialized-zeroed.rs:25:38
    |
 LL |         let _val: Wrap<&'static T> = mem::zeroed();
    |                                      ^^^^^^^^^^^^^
+   |                                      |
+   |                                      this code causes undefined behavior when executed
+   |                                      help: use `MaybeUninit<T>` instead
    |
-   = note: this means that this code causes undefined behavior when executed
-   = help: use `MaybeUninit` instead
+note: References must be non-null (in this struct field)
+  --> $DIR/uninitialized-zeroed.rs:16:18
+   |
+LL | struct Wrap<T> { wrapped: T }
+   |                  ^^^^^^^^^^
 
 error: the type `Wrap<&'static T>` does not permit being left uninitialized
-  --> $DIR/uninitialized-zeroed.rs:24:38
+  --> $DIR/uninitialized-zeroed.rs:26:38
    |
 LL |         let _val: Wrap<&'static T> = mem::uninitialized();
    |                                      ^^^^^^^^^^^^^^^^^^^^
+   |                                      |
+   |                                      this code causes undefined behavior when executed
+   |                                      help: use `MaybeUninit<T>` instead
    |
-   = note: this means that this code causes undefined behavior when executed
-   = help: use `MaybeUninit` instead
+note: References must be non-null (in this struct field)
+  --> $DIR/uninitialized-zeroed.rs:16:18
+   |
+LL | struct Wrap<T> { wrapped: T }
+   |                  ^^^^^^^^^^
 
 error: the type `!` does not permit zero-initialization
-  --> $DIR/uninitialized-zeroed.rs:30:23
+  --> $DIR/uninitialized-zeroed.rs:32:23
    |
 LL |         let _val: ! = mem::zeroed();
    |                       ^^^^^^^^^^^^^
+   |                       |
+   |                       this code causes undefined behavior when executed
+   |                       help: use `MaybeUninit<T>` instead
    |
-   = note: this means that this code causes undefined behavior when executed
-   = help: use `MaybeUninit` instead
+   = note: The never type (`!`) has no valid value
 
 error: the type `!` does not permit being left uninitialized
-  --> $DIR/uninitialized-zeroed.rs:31:23
+  --> $DIR/uninitialized-zeroed.rs:33:23
    |
 LL |         let _val: ! = mem::uninitialized();
    |                       ^^^^^^^^^^^^^^^^^^^^
+   |                       |
+   |                       this code causes undefined behavior when executed
+   |                       help: use `MaybeUninit<T>` instead
    |
-   = note: this means that this code causes undefined behavior when executed
-   = help: use `MaybeUninit` instead
+   = note: The never type (`!`) has no valid value
 
 error: the type `(i32, !)` does not permit zero-initialization
-  --> $DIR/uninitialized-zeroed.rs:33:30
+  --> $DIR/uninitialized-zeroed.rs:35:30
    |
 LL |         let _val: (i32, !) = mem::zeroed();
    |                              ^^^^^^^^^^^^^
+   |                              |
+   |                              this code causes undefined behavior when executed
+   |                              help: use `MaybeUninit<T>` instead
    |
-   = note: this means that this code causes undefined behavior when executed
-   = help: use `MaybeUninit` instead
+   = note: The never type (`!`) has no valid value
 
 error: the type `(i32, !)` does not permit being left uninitialized
-  --> $DIR/uninitialized-zeroed.rs:34:30
+  --> $DIR/uninitialized-zeroed.rs:36:30
    |
 LL |         let _val: (i32, !) = mem::uninitialized();
    |                              ^^^^^^^^^^^^^^^^^^^^
+   |                              |
+   |                              this code causes undefined behavior when executed
+   |                              help: use `MaybeUninit<T>` instead
    |
-   = note: this means that this code causes undefined behavior when executed
-   = help: use `MaybeUninit` instead
+   = note: The never type (`!`) has no valid value
 
 error: the type `Void` does not permit zero-initialization
-  --> $DIR/uninitialized-zeroed.rs:36:26
+  --> $DIR/uninitialized-zeroed.rs:38:26
    |
 LL |         let _val: Void = mem::zeroed();
    |                          ^^^^^^^^^^^^^
+   |                          |
+   |                          this code causes undefined behavior when executed
+   |                          help: use `MaybeUninit<T>` instead
    |
-   = note: this means that this code causes undefined behavior when executed
-   = help: use `MaybeUninit` instead
+   = note: 0-variant enums have no valid value
 
 error: the type `Void` does not permit being left uninitialized
-  --> $DIR/uninitialized-zeroed.rs:37:26
+  --> $DIR/uninitialized-zeroed.rs:39:26
    |
 LL |         let _val: Void = mem::uninitialized();
    |                          ^^^^^^^^^^^^^^^^^^^^
+   |                          |
+   |                          this code causes undefined behavior when executed
+   |                          help: use `MaybeUninit<T>` instead
    |
-   = note: this means that this code causes undefined behavior when executed
-   = help: use `MaybeUninit` instead
+   = note: 0-variant enums have no valid value
 
 error: the type `&'static i32` does not permit zero-initialization
-  --> $DIR/uninitialized-zeroed.rs:39:34
+  --> $DIR/uninitialized-zeroed.rs:41:34
    |
 LL |         let _val: &'static i32 = mem::zeroed();
    |                                  ^^^^^^^^^^^^^
+   |                                  |
+   |                                  this code causes undefined behavior when executed
+   |                                  help: use `MaybeUninit<T>` instead
    |
-   = note: this means that this code causes undefined behavior when executed
-   = help: use `MaybeUninit` instead
+   = note: References must be non-null
 
 error: the type `&'static i32` does not permit being left uninitialized
-  --> $DIR/uninitialized-zeroed.rs:40:34
+  --> $DIR/uninitialized-zeroed.rs:42:34
    |
 LL |         let _val: &'static i32 = mem::uninitialized();
    |                                  ^^^^^^^^^^^^^^^^^^^^
+   |                                  |
+   |                                  this code causes undefined behavior when executed
+   |                                  help: use `MaybeUninit<T>` instead
    |
-   = note: this means that this code causes undefined behavior when executed
-   = help: use `MaybeUninit` instead
+   = note: References must be non-null
 
 error: the type `Ref` does not permit zero-initialization
-  --> $DIR/uninitialized-zeroed.rs:42:25
+  --> $DIR/uninitialized-zeroed.rs:44:25
    |
 LL |         let _val: Ref = mem::zeroed();
    |                         ^^^^^^^^^^^^^
+   |                         |
+   |                         this code causes undefined behavior when executed
+   |                         help: use `MaybeUninit<T>` instead
    |
-   = note: this means that this code causes undefined behavior when executed
-   = help: use `MaybeUninit` instead
+note: References must be non-null (in this struct field)
+  --> $DIR/uninitialized-zeroed.rs:13:12
+   |
+LL | struct Ref(&'static i32);
+   |            ^^^^^^^^^^^^
 
 error: the type `Ref` does not permit being left uninitialized
-  --> $DIR/uninitialized-zeroed.rs:43:25
+  --> $DIR/uninitialized-zeroed.rs:45:25
    |
 LL |         let _val: Ref = mem::uninitialized();
    |                         ^^^^^^^^^^^^^^^^^^^^
+   |                         |
+   |                         this code causes undefined behavior when executed
+   |                         help: use `MaybeUninit<T>` instead
    |
-   = note: this means that this code causes undefined behavior when executed
-   = help: use `MaybeUninit` instead
+note: References must be non-null (in this struct field)
+  --> $DIR/uninitialized-zeroed.rs:13:12
+   |
+LL | struct Ref(&'static i32);
+   |            ^^^^^^^^^^^^
 
 error: the type `fn()` does not permit zero-initialization
-  --> $DIR/uninitialized-zeroed.rs:45:26
+  --> $DIR/uninitialized-zeroed.rs:47:26
    |
 LL |         let _val: fn() = mem::zeroed();
    |                          ^^^^^^^^^^^^^
+   |                          |
+   |                          this code causes undefined behavior when executed
+   |                          help: use `MaybeUninit<T>` instead
    |
-   = note: this means that this code causes undefined behavior when executed
-   = help: use `MaybeUninit` instead
+   = note: Function pointers must be non-null
 
 error: the type `fn()` does not permit being left uninitialized
-  --> $DIR/uninitialized-zeroed.rs:46:26
+  --> $DIR/uninitialized-zeroed.rs:48:26
    |
 LL |         let _val: fn() = mem::uninitialized();
    |                          ^^^^^^^^^^^^^^^^^^^^
+   |                          |
+   |                          this code causes undefined behavior when executed
+   |                          help: use `MaybeUninit<T>` instead
    |
-   = note: this means that this code causes undefined behavior when executed
-   = help: use `MaybeUninit` instead
+   = note: Function pointers must be non-null
 
 error: the type `Wrap<fn()>` does not permit zero-initialization
-  --> $DIR/uninitialized-zeroed.rs:48:32
+  --> $DIR/uninitialized-zeroed.rs:50:32
    |
 LL |         let _val: Wrap<fn()> = mem::zeroed();
    |                                ^^^^^^^^^^^^^
+   |                                |
+   |                                this code causes undefined behavior when executed
+   |                                help: use `MaybeUninit<T>` instead
    |
-   = note: this means that this code causes undefined behavior when executed
-   = help: use `MaybeUninit` instead
+note: Function pointers must be non-null (in this struct field)
+  --> $DIR/uninitialized-zeroed.rs:16:18
+   |
+LL | struct Wrap<T> { wrapped: T }
+   |                  ^^^^^^^^^^
 
 error: the type `Wrap<fn()>` does not permit being left uninitialized
-  --> $DIR/uninitialized-zeroed.rs:49:32
+  --> $DIR/uninitialized-zeroed.rs:51:32
    |
 LL |         let _val: Wrap<fn()> = mem::uninitialized();
    |                                ^^^^^^^^^^^^^^^^^^^^
+   |                                |
+   |                                this code causes undefined behavior when executed
+   |                                help: use `MaybeUninit<T>` instead
    |
-   = note: this means that this code causes undefined behavior when executed
-   = help: use `MaybeUninit` instead
+note: Function pointers must be non-null (in this struct field)
+  --> $DIR/uninitialized-zeroed.rs:16:18
+   |
+LL | struct Wrap<T> { wrapped: T }
+   |                  ^^^^^^^^^^
 
-error: aborting due to 18 previous errors
+error: the type `WrapEnum<fn()>` does not permit zero-initialization
+  --> $DIR/uninitialized-zeroed.rs:53:36
+   |
+LL |         let _val: WrapEnum<fn()> = mem::zeroed();
+   |                                    ^^^^^^^^^^^^^
+   |                                    |
+   |                                    this code causes undefined behavior when executed
+   |                                    help: use `MaybeUninit<T>` instead
+   |
+note: Function pointers must be non-null (in this enum field)
+  --> $DIR/uninitialized-zeroed.rs:17:28
+   |
+LL | enum WrapEnum<T> { Wrapped(T) }
+   |                            ^
+
+error: the type `WrapEnum<fn()>` does not permit being left uninitialized
+  --> $DIR/uninitialized-zeroed.rs:54:36
+   |
+LL |         let _val: WrapEnum<fn()> = mem::uninitialized();
+   |                                    ^^^^^^^^^^^^^^^^^^^^
+   |                                    |
+   |                                    this code causes undefined behavior when executed
+   |                                    help: use `MaybeUninit<T>` instead
+   |
+note: Function pointers must be non-null (in this enum field)
+  --> $DIR/uninitialized-zeroed.rs:17:28
+   |
+LL | enum WrapEnum<T> { Wrapped(T) }
+   |                            ^
+
+error: the type `Wrap<(RefPair, i32)>` does not permit zero-initialization
+  --> $DIR/uninitialized-zeroed.rs:56:42
+   |
+LL |         let _val: Wrap<(RefPair, i32)> = mem::zeroed();
+   |                                          ^^^^^^^^^^^^^
+   |                                          |
+   |                                          this code causes undefined behavior when executed
+   |                                          help: use `MaybeUninit<T>` instead
+   |
+note: References must be non-null (in this struct field)
+  --> $DIR/uninitialized-zeroed.rs:14:16
+   |
+LL | struct RefPair((&'static i32, i32));
+   |                ^^^^^^^^^^^^^^^^^^^
+
+error: the type `Wrap<(RefPair, i32)>` does not permit being left uninitialized
+  --> $DIR/uninitialized-zeroed.rs:57:42
+   |
+LL |         let _val: Wrap<(RefPair, i32)> = mem::uninitialized();
+   |                                          ^^^^^^^^^^^^^^^^^^^^
+   |                                          |
+   |                                          this code causes undefined behavior when executed
+   |                                          help: use `MaybeUninit<T>` instead
+   |
+note: References must be non-null (in this struct field)
+  --> $DIR/uninitialized-zeroed.rs:14:16
+   |
+LL | struct RefPair((&'static i32, i32));
+   |                ^^^^^^^^^^^^^^^^^^^
+
+error: aborting due to 22 previous errors