C/C++: more stdlib header hints (PR c/81404)
authorDavid Malcolm <dmalcolm@redhat.com>
Tue, 21 Nov 2017 00:50:39 +0000 (00:50 +0000)
committerDavid Malcolm <dmalcolm@gcc.gnu.org>
Tue, 21 Nov 2017 00:50:39 +0000 (00:50 +0000)
This patch extends the C frontend's "knowledge" of the C stdlib within
get_c_name_hint to cover some more macros and functions, covering
a case reported in PR c/81404 ("INT_MAX"), so that rather than printing:

  t.c:5:12: error: 'INT_MAX' undeclared here (not in a function); did you mean '__INT_MAX__'?
   int test = INT_MAX;
              ^~~~~~~
              __INT_MAX__

we instead print:

  t.c:5:12: error: 'INT_MAX' undeclared here (not in a function)
   int test = INT_MAX;
              ^~~~~~~
  t.c:5:12: note: 'INT_MAX' is defined in header '<limits.h>'; did you forget to '#include <limits.h>'?
  t.c:1:1:
  +#include <limits.h>

  t.c:5:12:
    int test = INT_MAX;
               ^~~~~~~

It also adds generalizes some of the code for this (and for the "std::"
namespace hints in the C++ frontend), moving it to a new
c-family/known-headers.cc and .h, and introducing a class known_headers.
This currently just works by scanning a hardcoded array of known
name/header associations, but perhaps in the future could be turned
into some kind of symbol database so that the compiler could record API
uses and use that to offer suggestions e.g.

foo.cc: error: 'myapi::foo' was not declared in this scope
foo.cc: note: 'myapi::foo" was declared in header 'myapi/private.h'
(included via 'myapi/public.h') when compiling 'bar.cc'; did you forget to
'#include "myapi/public.h"'?

or somesuch.

In any case, moving this to a class gives an easier way to locate the
hardcoded knowledge about the stdlib.

The patch also adds similar code to the C++ frontend covering
unqualified names in the standard library, so that rather than just
e.g.:

  t.cc:19:13: error: 'NULL' was not declared in this scope
   void *ptr = NULL;
               ^~~~

we can emit:

  t.cc:19:13: error: 'NULL' was not declared in this scope
   void *ptr = NULL;
               ^~~~
  t.cc:19:13: note: 'NULL' is defined in header '<cstddef>'; did you forget
  to '#include <cstddef>'?
  t.cc:1:1:
  +#include <cstddef>

  t.cc:19:13:
   void *ptr = NULL;
               ^~~~

(Also XFAIL for PR c++/80567 added for the C++ testcase; this is a
separate pre-existing bug exposed by the testcase for PR 81404).

gcc/ChangeLog:
PR c/81404
* Makefile.in (C_COMMON_OBJS): Add c-family/known-headers.o.

gcc/c-family/ChangeLog:
PR c/81404
* known-headers.cc: New file, based on material from c/c-decl.c.
(suggest_missing_header): Copied as-is.
(get_stdlib_header_for_name): New, based on get_c_name_hint but
heavily edited to add C++ support.  Add some knowledge about
<limits.h>, <stdint.h>, and <wchar.h>.
* known-headers.h: Likewise.

gcc/c/ChangeLog:
PR c/81404
* c-decl.c: Include "c-family/known-headers.h".
(get_c_name_hint): Rename to get_stdlib_header_for_name and move
to known-headers.cc.
(class suggest_missing_header): Move to known-header.h.
(lookup_name_fuzzy): Call get_c_stdlib_header_for_name rather
than get_c_name_hint.

gcc/cp/ChangeLog:
PR c/81404
* name-lookup.c: Include "c-family/known-headers.h"
(lookup_name_fuzzy): Call get_cp_stdlib_header_for_name and
potentially return a new suggest_missing_header hint.

gcc/testsuite/ChangeLog:
PR c/81404
* g++.dg/spellcheck-stdlib.C: New.
* gcc.dg/spellcheck-stdlib.c (test_INT_MAX): New.

From-SVN: r254980

12 files changed:
gcc/ChangeLog
gcc/Makefile.in
gcc/c-family/ChangeLog
gcc/c-family/known-headers.cc [new file with mode: 0644]
gcc/c-family/known-headers.h [new file with mode: 0644]
gcc/c/ChangeLog
gcc/c/c-decl.c
gcc/cp/ChangeLog
gcc/cp/name-lookup.c
gcc/testsuite/ChangeLog
gcc/testsuite/g++.dg/spellcheck-stdlib.C [new file with mode: 0644]
gcc/testsuite/gcc.dg/spellcheck-stdlib.c

index 0255d8a3744bbde2f1a031b002d8d4627c845076..1f8417911915e792edcbdf04afe50ab9f487c6e5 100644 (file)
@@ -1,3 +1,8 @@
+2017-11-20  David Malcolm  <dmalcolm@redhat.com>
+
+       PR c/81404
+       * Makefile.in (C_COMMON_OBJS): Add c-family/known-headers.o.
+
 2017-11-20  David Malcolm  <dmalcolm@redhat.com>
 
        PR c++/72786
index 38ab4e8102685dbc7686114255f469e01c346a98..f2a897c5962396f51bbfe6b23e3c3861644e3f4c 100644 (file)
@@ -1191,7 +1191,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
index 9d49eb934e4720d6845f1c0d92dac874b6cd4e1d..1e5c3d3e18722383bd52404a063eac283ecaf8b2 100644 (file)
@@ -1,3 +1,13 @@
+2017-11-20  David Malcolm  <dmalcolm@redhat.com>
+
+       PR c/81404
+       * known-headers.cc: New file, based on material from c/c-decl.c.
+       (suggest_missing_header): Copied as-is.
+       (get_stdlib_header_for_name): New, based on get_c_name_hint but
+       heavily edited to add C++ support.  Add some knowledge about
+       <limits.h>, <stdint.h>, and <wchar.h>.
+       * known-headers.h: Likewise.
+
 2017-11-20  David Malcolm  <dmalcolm@redhat.com>
 
        * c-common.h (enum lookup_name_fuzzy_kind): Move to name-hint.h.
diff --git a/gcc/c-family/known-headers.cc b/gcc/c-family/known-headers.cc
new file mode 100644 (file)
index 0000000..d4cd39b
--- /dev/null
@@ -0,0 +1,169 @@
+/* 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"
+#define INCLUDE_UNIQUE_PTR
+#include "system.h"
+#include "coretypes.h"
+#include "c-family/c-common.h"
+#include "c-family/name-hint.h"
+#include "c-family/known-headers.h"
+#include "gcc-rich-location.h"
+
+/* An enum for distinguishing between the C and C++ stdlibs.  */
+
+enum stdlib
+{
+  STDLIB_C,
+  STDLIB_CPLUSPLUS,
+
+  NUM_STDLIBS
+};
+
+/* A struct for associating names in a standard library with the header
+   that should be included to locate them, for each of the C and C++ stdlibs
+   (or NULL, for names that aren't in a header for a particular stdlib).  */
+
+struct stdlib_hint
+{
+  const char *name;
+  const char *header[NUM_STDLIBS];
+};
+
+/* Given non-NULL NAME, return the header name defining it within either
+   the standard library (with '<' and '>'), or NULL.
+   Only handles a subset of the most common names within the stdlibs.  */
+
+static const char *
+get_stdlib_header_for_name (const char *name, enum stdlib lib)
+{
+  gcc_assert (name);
+  gcc_assert (lib < NUM_STDLIBS);
+
+  static const stdlib_hint hints[] = {
+    /* <errno.h> and <cerrno>.  */
+    {"errno", {"<errno.h>", "<cerrno>"} },
+
+    /* <limits.h> and <climits>.  */
+    {"CHAR_BIT", {"<limits.h>", "<climits>"} },
+    {"CHAR_MAX", {"<limits.h>", "<climits>"} },
+    {"CHAR_MIN", {"<limits.h>", "<climits>"} },
+    {"INT_MAX", {"<limits.h>", "<climits>"} },
+    {"INT_MIN", {"<limits.h>", "<climits>"} },
+    {"LLONG_MAX", {"<limits.h>", "<climits>"} },
+    {"LLONG_MIN", {"<limits.h>", "<climits>"} },
+    {"LONG_MAX", {"<limits.h>", "<climits>"} },
+    {"LONG_MIN", {"<limits.h>", "<climits>"} },
+    {"MB_LEN_MAX", {"<limits.h>", "<climits>"} },
+    {"SCHAR_MAX", {"<limits.h>", "<climits>"} },
+    {"SCHAR_MIN", {"<limits.h>", "<climits>"} },
+    {"SHRT_MAX", {"<limits.h>", "<climits>"} },
+    {"SHRT_MIN", {"<limits.h>", "<climits>"} },
+    {"UCHAR_MAX", {"<limits.h>", "<climits>"} },
+    {"UINT_MAX", {"<limits.h>", "<climits>"} },
+    {"ULLONG_MAX", {"<limits.h>", "<climits>"} },
+    {"ULONG_MAX", {"<limits.h>", "<climits>"} },
+    {"USHRT_MAX", {"<limits.h>", "<climits>"} },
+
+    /* <stdarg.h> and <cstdarg>.  */
+    {"va_list", {"<stdarg.h>", "<cstdarg>"} },
+
+    /* <stddef.h> and <cstddef>.  */
+    {"NULL", {"<stddef.h>", "<cstddef>"} },
+    {"nullptr_t", {NULL, "<cstddef>"} },
+    {"offsetof", {"<stddef.h>", "<cstddef>"} },
+    {"ptrdiff_t", {"<stddef.h>", "<cstddef>"} },
+    {"size_t", {"<stddef.h>", "<cstddef>"} },
+    {"wchar_t", {"<stddef.h>", NULL /* a keyword in C++ */} },
+
+    /* <stdio.h>.  */
+    {"BUFSIZ", {"<stdio.h>", "<cstdio>"} },
+    {"EOF", {"<stdio.h>", "<cstdio>"} },
+    {"FILE", {"<stdio.h>", "<cstdio>"} },
+    {"FILENAME_MAX", {"<stdio.h>", "<cstdio>"} },
+    {"fpos_t", {"<stdio.h>", "<cstdio>"} },
+    {"stderr", {"<stdio.h>", "<cstdio>"} },
+    {"stdin", {"<stdio.h>", "<cstdio>"} },
+    {"stdout", {"<stdio.h>", "<cstdio>"} },
+
+    /* <stdint.h>.  */
+    {"PTRDIFF_MAX", {"<stdint.h>", "<cstdint>"} },
+    {"PTRDIFF_MIN", {"<stdint.h>", "<cstdint>"} },
+    {"SIG_ATOMIC_MAX", {"<stdint.h>", "<cstdint>"} },
+    {"SIG_ATOMIC_MIN", {"<stdint.h>", "<cstdint>"} },
+    {"SIZE_MAX", {"<stdint.h>", "<cstdint>"} },
+    {"WINT_MAX", {"<stdint.h>", "<cstdint>"} },
+    {"WINT_MIN", {"<stdint.h>", "<cstdint>"} },
+
+    /* <wchar.h>.  */
+    {"WCHAR_MAX", {"<wchar.h>", "<cwchar>"} },
+    {"WCHAR_MIN", {"<wchar.h>", "<cwchar>"} }
+  };
+  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[lib];
+  return NULL;
+}
+
+/* Given non-NULL NAME, return the header name defining it within the C
+   standard library (with '<' and '>'), or NULL.  */
+
+const char *
+get_c_stdlib_header_for_name (const char *name)
+{
+  return get_stdlib_header_for_name (name, STDLIB_C);
+}
+
+/* Given non-NULL NAME, return the header name defining it within the C++
+   standard library (with '<' and '>'), or NULL.  */
+
+const char *
+get_cp_stdlib_header_for_name (const char *name)
+{
+  return get_stdlib_header_for_name (name, STDLIB_CPLUSPLUS);
+}
+
+/* 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 (&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 (file)
index 0000000..328100f
--- /dev/null
@@ -0,0 +1,41 @@
+/* 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
+
+extern const char *get_c_stdlib_header_for_name (const char *name);
+extern const char *get_cp_stdlib_header_for_name (const char *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);
+  ~suggest_missing_header ();
+
+ private:
+  const char *m_name_str;
+  const char *m_header_hint;
+};
+
+#endif /* GCC_KNOWN_HEADERS_H */
index b60a8e70d48e169ef330000f35b2b022f6cb18b0..95b7718791aacdc7242587a758bfece48ae492d0 100644 (file)
@@ -1,3 +1,13 @@
+2017-11-20  David Malcolm  <dmalcolm@redhat.com>
+
+       PR c/81404
+       * c-decl.c: Include "c-family/known-headers.h".
+       (get_c_name_hint): Rename to get_stdlib_header_for_name and move
+       to known-headers.cc.
+       (class suggest_missing_header): Move to known-header.h.
+       (lookup_name_fuzzy): Call get_c_stdlib_header_for_name rather
+       than get_c_name_hint.
+
 2017-11-20  David Malcolm  <dmalcolm@redhat.com>
 
        * c-decl.c (get_c_name_hint): New function.
index ae45e9a88f87a74f91165387f449dc149180e5a6..e0a4dd1661af815061cd3d68a19eada1945f8367 100644 (file)
@@ -56,6 +56,7 @@ along with GCC; see the file COPYING3.  If not see
 #include "gcc-rich-location.h"
 #include "asan.h"
 #include "c-family/name-hint.h"
+#include "c-family/known-headers.h"
 
 /* In grokdeclarator, distinguish syntactic contexts of declarators.  */
 enum decl_context
@@ -3992,83 +3993,6 @@ lookup_name_in_scope (tree name, struct c_scope *scope)
   return NULL_TREE;
 }
 
-/* Subroutine of lookup_name_fuzzy for handling unrecognized names
-   for some of the most common 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_c_name_hint (const char *name)
-{
-  struct std_name_hint
-  {
-    const char *name;
-    const char *header;
-  };
-  static const std_name_hint hints[] = {
-    /* <errno.h>.  */
-    {"errno", "<errno.h>"},
-
-    /* <stdarg.h>.  */
-    {"va_list", "<stdarg.h>"},
-
-    /* <stddef.h>.  */
-    {"NULL", "<stddef.h>"},
-    {"ptrdiff_t", "<stddef.h>"},
-    {"wchar_t", "<stddef.h>"},
-    {"size_t", "<stddef.h>"},
-
-    /* <stdio.h>.  */
-    {"BUFSIZ", "<stdio.h>"},
-    {"EOF", "<stdio.h>"},
-    {"FILE", "<stdio.h>"},
-    {"FILENAME_MAX", "<stdio.h>"},
-    {"fpos_t", "<stdio.h>"},
-    {"stderr", "<stdio.h>"},
-    {"stdin", "<stdio.h>"},
-    {"stdout", "<stdio.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;
-}
-
-/* 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 (&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.
 
@@ -4094,7 +4018,9 @@ lookup_name_fuzzy (tree name, enum lookup_name_fuzzy_kind kind, location_t loc)
 
   /* First, try some well-known names in the C standard library, in case
      the user forgot a #include.  */
-  const char *header_hint = get_c_name_hint (IDENTIFIER_POINTER (name));
+  const char *header_hint
+    = get_c_stdlib_header_for_name (IDENTIFIER_POINTER (name));
+
   if (header_hint)
     return name_hint (NULL,
                      new suggest_missing_header (loc,
index 908b48ef09bc5ab788c444e1491194cf9c72b2bd..56d466dfb4c58570a8357d0fc16bf5c4e03e2801 100644 (file)
@@ -1,3 +1,10 @@
+2017-11-20  David Malcolm  <dmalcolm@redhat.com>
+
+       PR c/81404
+       * name-lookup.c: Include "c-family/known-headers.h"
+       (lookup_name_fuzzy): Call get_cp_stdlib_header_for_name and
+       potentially return a new suggest_missing_header hint.
+
 2017-11-20  David Malcolm  <dmalcolm@redhat.com>
 
        PR c++/72786
index fc317b175fb0fa09644396c3c9da75850393a1bf..7c363b0f935e35a730159abad6b1720bd147aa09 100644 (file)
@@ -34,6 +34,7 @@ along with GCC; see the file COPYING3.  If not see
 #include "spellcheck-tree.h"
 #include "parser.h"
 #include "c-family/name-hint.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);
@@ -5682,6 +5683,16 @@ 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_cp_stdlib_header_for_name (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;
index d1911dff6c9097218bfbf95ef78476b3c7bdb0d1..8bd2101486a8561d28e260b80fb4e621e519f1c3 100644 (file)
@@ -1,3 +1,9 @@
+2017-11-20  David Malcolm  <dmalcolm@redhat.com>
+
+       PR c/81404
+       * g++.dg/spellcheck-stdlib.C: New.
+       * gcc.dg/spellcheck-stdlib.c (test_INT_MAX): New.
+
 2017-11-20  David Malcolm  <dmalcolm@redhat.com>
 
        * gcc.dg/spellcheck-stdlib.c: New test case.
diff --git a/gcc/testsuite/g++.dg/spellcheck-stdlib.C b/gcc/testsuite/g++.dg/spellcheck-stdlib.C
new file mode 100644 (file)
index 0000000..6e6ab1d
--- /dev/null
@@ -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 }
+}
index 85a21c3840082496f509a6bdb1e694a9e3cf2493..7474c9a5b03adc0e1ff851653a10c7d62d0d5062 100644 (file)
@@ -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 } */
+}