diff --git a/gcc/Makefile.in b/gcc/Makefile.in
index 2809619..9855919 100644
--- a/gcc/Makefile.in
+++ b/gcc/Makefile.in
@@ -1190,7 +1190,7 @@ C_COMMON_OBJS = c-family/c-common.o c-family/c-cppbuiltin.o c-family/c-dump.o \
   c-family/c-semantics.o c-family/c-ada-spec.o \
   c-family/c-cilkplus.o \
   c-family/array-notation-common.o c-family/cilk.o c-family/c-ubsan.o \
-  c-family/c-attribs.o c-family/c-warn.o
+  c-family/c-attribs.o c-family/c-warn.o c-family/known-headers.o
 
 # Language-independent object files.
 # We put the *-match.o and insn-*.o files first so that a parallel make
diff --git a/gcc/c-family/known-headers.cc b/gcc/c-family/known-headers.cc
new file mode 100644
index 0000000..008788e
--- /dev/null
+++ b/gcc/c-family/known-headers.cc
@@ -0,0 +1,68 @@
+/* Support for suggestions about missing #include directives.
+   Copyright (C) 2017 Free Software Foundation, Inc.
+
+This file is part of GCC.
+
+GCC is free software; you can redistribute it and/or modify it under
+the terms of the GNU General Public License as published by the Free
+Software Foundation; either version 3, or (at your option) any later
+version.
+
+GCC is distributed in the hope that it will be useful, but WITHOUT ANY
+WARRANTY; without even the implied warranty of MERCHANTABILITY or
+FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+for more details.
+
+You should have received a copy of the GNU General Public License
+along with GCC; see the file COPYING3.  If not see
+<http://www.gnu.org/licenses/>.  */
+
+#include "config.h"
+#include "system.h"
+#include "coretypes.h"
+#include "c-family/c-common.h"
+#include "c-family/known-headers.h"
+#include "gcc-rich-location.h"
+
+/* Given NAME, attempt to locate a header that would declare it,
+   or return NULL if we don't know of such a header.  */
+
+const char *
+known_headers::get_header_for_name (const char *name) const
+{
+  gcc_assert (name);
+
+  for (size_t i = 0; i < m_num_hints; i++)
+    if (0 == strcmp (name, m_hints[i].name))
+	return m_hints[i].header;
+
+  return NULL;
+}
+
+/* Implementation of class suggest_missing_header.  */
+
+/* suggest_missing_header's ctor.  */
+
+suggest_missing_header::suggest_missing_header (location_t loc,
+						const char *name,
+						const char *header_hint)
+: deferred_diagnostic (loc), m_name_str (name), m_header_hint (header_hint)
+{
+  gcc_assert (name);
+  gcc_assert (header_hint);
+}
+
+/* suggest_missing_header's dtor.  */
+
+suggest_missing_header::~suggest_missing_header ()
+{
+  if (is_suppressed_p ())
+    return;
+
+  gcc_rich_location richloc (get_location ());
+  maybe_add_include_fixit (&richloc, m_header_hint);
+  inform_at_rich_loc (&richloc,
+		      "%qs is defined in header %qs;"
+		      " did you forget to %<#include %s%>?",
+		      m_name_str, m_header_hint, m_header_hint);
+}
diff --git a/gcc/c-family/known-headers.h b/gcc/c-family/known-headers.h
new file mode 100644
index 0000000..11057c8
--- /dev/null
+++ b/gcc/c-family/known-headers.h
@@ -0,0 +1,63 @@
+/* Support for suggestions about missing #include directives.
+   Copyright (C) 2017 Free Software Foundation, Inc.
+
+This file is part of GCC.
+
+GCC is free software; you can redistribute it and/or modify it under
+the terms of the GNU General Public License as published by the Free
+Software Foundation; either version 3, or (at your option) any later
+version.
+
+GCC is distributed in the hope that it will be useful, but WITHOUT ANY
+WARRANTY; without even the implied warranty of MERCHANTABILITY or
+FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+for more details.
+
+You should have received a copy of the GNU General Public License
+along with GCC; see the file COPYING3.  If not see
+<http://www.gnu.org/licenses/>.  */
+
+#ifndef GCC_KNOWN_HEADERS_H
+#define GCC_KNOWN_HEADERS_H
+
+/* A struct for associating names in a standard library (perhaps in
+   some namespace) with the header that should be included to locate them.  */
+
+struct header_hint
+{
+  const char *name;
+  const char *header;
+};
+
+/* A class for looking up unknown names, to attempt to locate the header
+   that should have been #include-d to declare it.  */
+
+class known_headers
+{
+ public:
+  known_headers (const header_hint *hints, size_t num_hints)
+  : m_hints (hints), m_num_hints (num_hints) {}
+
+  const char *get_header_for_name (const char *name) const;
+
+ private:
+  const header_hint *const m_hints;
+  const size_t m_num_hints;
+};
+
+/* Subclass of deferred_diagnostic for suggesting to the user
+   that they have missed a #include.  */
+
+class suggest_missing_header : public deferred_diagnostic
+{
+ public:
+  suggest_missing_header (location_t loc, const char *name,
+			  const char *header_hint);
+  ~suggest_missing_header ();
+
+ private:
+  const char *m_name_str;
+  const char *m_header_hint;
+};
+
+#endif /* GCC_KNOWN_HEADERS_H */
diff --git a/gcc/c/c-decl.c b/gcc/c/c-decl.c
index ce4cb3e..fe55365 100644
--- a/gcc/c/c-decl.c
+++ b/gcc/c/c-decl.c
@@ -54,6 +54,7 @@ along with GCC; see the file COPYING3.  If not see
 #include "spellcheck-tree.h"
 #include "gcc-rich-location.h"
 #include "asan.h"
+#include "c-family/known-headers.h"
 
 /* In grokdeclarator, distinguish syntactic contexts of declarators.  */
 enum decl_context
@@ -3991,15 +3992,31 @@ lookup_name_in_scope (tree name, struct c_scope *scope)
 static const char *
 get_c_name_hint (const char *name)
 {
-  struct std_name_hint
-  {
-    const char *name;
-    const char *header;
-  };
-  static const std_name_hint hints[] = {
+  static const header_hint hints[] = {
     /* <errno.h>.  */
     {"errno", "<errno.h>"},
 
+    /* <limits.h>.  */
+    {"CHAR_BIT", "<limits.h>"},
+    {"CHAR_MAX", "<limits.h>"},
+    {"CHAR_MIN", "<limits.h>"},
+    {"INT_MAX", "<limits.h>"},
+    {"INT_MIN", "<limits.h>"},
+    {"LLONG_MAX", "<limits.h>"},
+    {"LLONG_MIN", "<limits.h>"},
+    {"LONG_MAX", "<limits.h>"},
+    {"LONG_MIN", "<limits.h>"},
+    {"MB_LEN_MAX", "<limits.h>"},
+    {"SCHAR_MAX", "<limits.h>"},
+    {"SCHAR_MIN", "<limits.h>"},
+    {"SHRT_MAX", "<limits.h>"},
+    {"SHRT_MIN", "<limits.h>"},
+    {"UCHAR_MAX", "<limits.h>"},
+    {"UINT_MAX", "<limits.h>"},
+    {"ULLONG_MAX", "<limits.h>"},
+    {"ULONG_MAX", "<limits.h>"},
+    {"USHRT_MAX", "<limits.h>"},
+
     /* <stdarg.h>.  */
     {"va_list", "<stdarg.h>"},
 
@@ -4017,49 +4034,26 @@ get_c_name_hint (const char *name)
     {"fpos_t", "<stdio.h>"},
     {"stderr", "<stdio.h>"},
     {"stdin", "<stdio.h>"},
-    {"stdout", "<stdio.h>"}
+    {"stdout", "<stdio.h>"},
+
+    /* <stdint.h>.  */
+    {"PTRDIFF_MAX", "<stdint.h>"},
+    {"PTRDIFF_MIN", "<stdint.h>"},
+    {"SIG_ATOMIC_MAX", "<stdint.h>"},
+    {"SIG_ATOMIC_MIN", "<stdint.h>"},
+    {"SIZE_MAX", "<stdint.h>"},
+
+    /* <wchar.h>.  */
+    {"WCHAR_MAX", "<wchar.h>"},
+    {"WCHAR_MIN", "<wchar.h>"},
+    {"WINT_MAX", "<wchar.h>"},
+    {"WINT_MIN", "<wchar.h>"}
   };
   const size_t num_hints = sizeof (hints) / sizeof (hints[0]);
-  for (size_t i = 0; i < num_hints; i++)
-    {
-      if (0 == strcmp (name, hints[i].name))
-	return hints[i].header;
-    }
-  return NULL;
+  known_headers kh (hints, num_hints);
+  return kh.get_header_for_name (name);
 }
 
-/* Subclass of deferred_diagnostic for suggesting to the user
-   that they have missed a #include.  */
-
-class suggest_missing_header : public deferred_diagnostic
-{
- public:
-  suggest_missing_header (location_t loc, const char *name,
-			  const char *header_hint)
-  : deferred_diagnostic (loc), m_name_str (name), m_header_hint (header_hint)
-  {
-    gcc_assert (name);
-    gcc_assert (header_hint);
-  }
-
-  ~suggest_missing_header ()
-  {
-    if (is_suppressed_p ())
-      return;
-
-    gcc_rich_location richloc (get_location ());
-    maybe_add_include_fixit (&richloc, m_header_hint);
-    inform_at_rich_loc (&richloc,
-			"%qs is defined in header %qs;"
-			" did you forget to %<#include %s%>?",
-			m_name_str, m_header_hint, m_header_hint);
-  }
-
- private:
-  const char *m_name_str;
-  const char *m_header_hint;
-};
-
 /* Look for the closest match for NAME within the currently valid
    scopes.
 
diff --git a/gcc/cp/name-lookup.c b/gcc/cp/name-lookup.c
index dec93ad..b86ee4f 100644
--- a/gcc/cp/name-lookup.c
+++ b/gcc/cp/name-lookup.c
@@ -32,6 +32,7 @@ along with GCC; see the file COPYING3.  If not see
 #include "gcc-rich-location.h"
 #include "spellcheck-tree.h"
 #include "parser.h"
+#include "c-family/known-headers.h"
 
 static cxx_binding *cxx_binding_make (tree value, tree type);
 static cp_binding_level *innermost_nonclass_level (void);
@@ -5392,12 +5393,7 @@ suggest_alternatives_for (location_t location, tree name,
 static const char *
 get_std_name_hint (const char *name)
 {
-  struct std_name_hint
-  {
-    const char *name;
-    const char *header;
-  };
-  static const std_name_hint hints[] = {
+  static const header_hint hints[] = {
     /* <array>.  */
     {"array", "<array>"}, // C++11
     /* <deque>.  */
@@ -5456,12 +5452,8 @@ get_std_name_hint (const char *name)
     {"vector", "<vector>"},
   };
   const size_t num_hints = sizeof (hints) / sizeof (hints[0]);
-  for (size_t i = 0; i < num_hints; i++)
-    {
-      if (0 == strcmp (name, hints[i].name))
-	return hints[i].header;
-    }
-  return NULL;
+  known_headers kh (hints, num_hints);
+  return kh.get_header_for_name (name);
 }
 
 /* If SCOPE is the "std" namespace, then suggest pertinent header
@@ -5660,6 +5652,70 @@ class macro_use_before_def : public deferred_diagnostic
   cpp_hashnode *m_macro;
 };
 
+/* Subroutine of lookup_name_fuzzy for handling unrecognized names
+   for some of the names within the C++ standard library.
+   Given non-NULL NAME, return the header name defining it within the C++
+   standard library (with '<' and '>'), or NULL.  */
+
+static const char *
+get_stdlib_name_hint (const char *name)
+{
+  static const header_hint hints[] = {
+    /* <cerrno>.  */
+    {"errno", "<cerrno>"},
+
+    /* <climits>.  */
+    {"CHAR_BIT", "<climits>"},
+    {"CHAR_MAX", "<climits>"},
+    {"CHAR_MIN", "<climits>"},
+    {"INT_MAX", "<climits>"},
+    {"INT_MIN", "<climits>"},
+    {"LLONG_MAX", "<climits>"},
+    {"LLONG_MIN", "<climits>"},
+    {"LONG_MAX", "<climits>"},
+    {"LONG_MIN", "<climits>"},
+    {"MB_LEN_MAX", "<climits>"},
+    {"SCHAR_MAX", "<climits>"},
+    {"SCHAR_MIN", "<climits>"},
+    {"SHRT_MAX", "<climits>"},
+    {"SHRT_MIN", "<climits>"},
+    {"UCHAR_MAX", "<climits>"},
+    {"UINT_MAX", "<climits>"},
+    {"ULLONG_MAX", "<climits>"},
+    {"ULONG_MAX", "<climits>"},
+    {"USHRT_MAX", "<climits>"},
+
+    /* <cstdarg>.  */
+    {"va_list", "<cstdarg>"},
+
+    /* <cstddef>.  */
+    {"NULL", "<cstddef>"},
+    {"nullptr_t", "<cstddef>"},
+    {"offsetof", "<cstddef>"},
+    {"ptrdiff_t", "<cstddef>"},
+    {"size_t", "<cstddef>"},
+
+    /* <cstdio>.  */
+    {"BUFSIZ", "<cstdio>"},
+    {"EOF", "<cstdio>"},
+    {"FILE", "<cstdio>"},
+    {"FILENAME_MAX", "<cstdio>"},
+    {"fpos_t", "<cstdio>"},
+    {"stderr", "<cstdio>"},
+    {"stdin", "<cstdio>"},
+    {"stdout", "<cstdio>"},
+
+    /* <cstdint>.  */
+    {"PTRDIFF_MAX", "<cstdint>"},
+    {"PTRDIFF_MIN", "<cstdint>"},
+    {"SIG_ATOMIC_MAX", "<cstdint>"},
+    {"SIG_ATOMIC_MIN", "<cstdint>"},
+    {"SIZE_MAX", "<cstdint>"},
+  };
+  const size_t num_hints = sizeof (hints) / sizeof (hints[0]);
+  known_headers kh (hints, num_hints);
+  return kh.get_header_for_name (name);
+}
 
 /* Search for near-matches for NAME within the current bindings, and within
    macro names, returning the best match as a const char *, or NULL if
@@ -5672,6 +5728,15 @@ lookup_name_fuzzy (tree name, enum lookup_name_fuzzy_kind kind, location_t loc)
 {
   gcc_assert (TREE_CODE (name) == IDENTIFIER_NODE);
 
+  /* First, try some well-known names in the C++ standard library, in case
+     the user forgot a #include.  */
+  const char *header_hint = get_stdlib_name_hint (IDENTIFIER_POINTER (name));
+  if (header_hint)
+    return name_hint (NULL,
+		      new suggest_missing_header (loc,
+						  IDENTIFIER_POINTER (name),
+						  header_hint));
+
   best_match <tree, const char *> bm (name);
 
   cp_binding_level *lvl;
diff --git a/gcc/testsuite/g++.dg/spellcheck-stdlib.C b/gcc/testsuite/g++.dg/spellcheck-stdlib.C
new file mode 100644
index 0000000..6e6ab1d
--- /dev/null
+++ b/gcc/testsuite/g++.dg/spellcheck-stdlib.C
@@ -0,0 +1,84 @@
+/* Missing <cstddef>.  */
+
+void *ptr = NULL; // { dg-error "'NULL' was not declared" }
+// { dg-message "'NULL' is defined in header '<cstddef>'; did you forget to '#include <cstddef>'?" "" { target *-*-* } .-1 }
+
+ptrdiff_t pd; // { dg-error "'ptrdiff_t' does not name a type" }
+// { dg-message "'ptrdiff_t' is defined in header '<cstddef>'; did you forget to '#include <cstddef>'?" "" { target *-*-* } .-1 }
+
+size_t sz; // { dg-error "'size_t' does not name a type" }
+// { dg-message "'size_t' is defined in header '<cstddef>'; did you forget to '#include <cstddef>'?" "" { target *-*-* } .-1 }
+
+/* Missing <cstdio>.  */
+
+void test_cstdio (void)
+{
+  FILE *f; // { dg-error "'FILE' was not declared in this scope" }
+  // { dg-message "'FILE' is defined in header '<cstdio>'; did you forget to '#include <cstdio>'?" "" { target *-*-* } .-1 }
+  // { dg-error "'f' was not declared in this scope" "" { target *-*-* } .-2 }
+  // { dg-bogus "suggested alternative: 'if'" "PR c++/80567" { xfail *-*-* } .-3 }
+
+  char buf[BUFSIZ]; // { dg-error "'BUFSIZ' was not declared" }
+  // { dg-message "'BUFSIZ' is defined in header '<cstdio>'; did you forget to '#include <cstdio>'?" "" { target *-*-* } .-1 }
+
+  char buf2[FILENAME_MAX]; // { dg-error "'FILENAME_MAX' was not declared" }
+  // { dg-message "'FILENAME_MAX' is defined in header '<cstdio>'; did you forget to '#include <cstdio>'?" "" { target *-*-* } .-1 }
+
+  stderr; // { dg-error "'stderr' was not declared" }
+  // { dg-message "'stderr' is defined in header '<cstdio>'; did you forget to '#include <cstdio>'?" "" { target *-*-* } .-1 }
+
+  stdin; // { dg-error "'stdin' was not declared" }
+  // { dg-message "'stdin' is defined in header '<cstdio>'; did you forget to '#include <cstdio>'?" "" { target *-*-* } .-1 }
+
+  stdout; // { dg-error "'stdout' was not declared" }
+  // { dg-message "'stdout' is defined in header '<cstdio>'; did you forget to '#include <cstdio>'?" "" { target *-*-* } .-1 }
+
+  EOF; // { dg-error "'EOF' was not declared" }
+  // { dg-message "'EOF' is defined in header '<cstdio>'; did you forget to '#include <cstdio>'?" "" { target *-*-* } .-1 }
+}
+
+/* Missing <cerrno>.  */
+
+int test_cerrno (void)
+{
+  return errno; // { dg-error "'errno' was not declared" }
+  // { dg-message "'errno' is defined in header '<cerrno>'; did you forget to '#include <cerrno>'?" "" { target *-*-* } .-1 }
+}
+
+/* Missing <cstdarg>.  */
+
+void test_cstdarg (void)
+{
+  va_list ap; // { dg-error "'va_list'" }
+  // { dg-message "'va_list' is defined in header '<cstdarg>'; did you forget to '#include <cstdarg>'?" "" { target *-*-* } .-1 }
+}
+
+/* Missing <climits>.  */
+int test_INT_MAX (void)
+{
+  return INT_MAX; // { dg-line INT_MAX_line }
+  // { dg-error "'INT_MAX' was not declared" "" { target *-*-* } INT_MAX_line }
+  // { dg-bogus "__INT_MAX__" "" { target *-*-* } INT_MAX_line }
+  // { dg-message "'INT_MAX' is defined in header '<climits>'; did you forget to '#include <climits>'?" "" { target *-*-* } INT_MAX_line }
+}
+
+/* Verify that we don't offer suggestions to stdlib globals names when
+   there's an explicit namespace.  */
+
+namespace some_ns {}
+
+int not_within_namespace (void)
+{
+  return some_ns::stdout; // { dg-error "'stdout' is not a member of 'some_ns'" }
+  // { dg-bogus "is defined in header" "" { target *-*-* } .-1 }
+}
+
+/* Similarly for when there's an explicit class scope.  */
+
+class some_class {};
+
+int not_within_class (void)
+{
+  return some_class::stdout; // { dg-error "'stdout' is not a member of 'some_class'" }
+  // { dg-bogus "is defined in header" "" { target *-*-* } .-1 }
+}
diff --git a/gcc/testsuite/gcc.dg/spellcheck-stdlib.c b/gcc/testsuite/gcc.dg/spellcheck-stdlib.c
index 85a21c3..7474c9a 100644
--- a/gcc/testsuite/gcc.dg/spellcheck-stdlib.c
+++ b/gcc/testsuite/gcc.dg/spellcheck-stdlib.c
@@ -53,3 +53,12 @@ void test_stdarg_h (void)
   va_list ap; /* { dg-error "unknown type name 'va_list'" } */
   /* { dg-message "'va_list' is defined in header '<stdarg.h>'; did you forget to '#include <stdarg.h>'?" "" { target *-*-* } .-1 } */
 }
+
+/* Missing <limits.h>.  */
+int test_INT_MAX (void)
+{
+  return INT_MAX; /* { dg-line INT_MAX_line } */
+  /* { dg-error "'INT_MAX' undeclared" "" { target *-*-* } INT_MAX_line } */
+  /* { dg-bogus "__INT_MAX__" "" { target *-*-* } INT_MAX_line } */
+  /* { dg-message "'INT_MAX' is defined in header '<limits.h>'; did you forget to '#include <limits.h>'?" "" { target *-*-* } INT_MAX_line } */
+}
