From patchwork Tue Oct 17 17:33:50 2017 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: David Malcolm X-Patchwork-Id: 827184 Return-Path: X-Original-To: incoming@patchwork.ozlabs.org Delivered-To: patchwork-incoming@bilbo.ozlabs.org Authentication-Results: ozlabs.org; spf=pass (mailfrom) smtp.mailfrom=gcc.gnu.org (client-ip=209.132.180.131; helo=sourceware.org; envelope-from=gcc-patches-return-464359-incoming=patchwork.ozlabs.org@gcc.gnu.org; receiver=) Authentication-Results: ozlabs.org; dkim=pass (1024-bit key; unprotected) header.d=gcc.gnu.org header.i=@gcc.gnu.org header.b="yQ2gW06Q"; dkim-atps=neutral Received: from sourceware.org (server1.sourceware.org [209.132.180.131]) (using TLSv1.2 with cipher ECDHE-RSA-AES256-GCM-SHA384 (256/256 bits)) (No client certificate requested) by ozlabs.org (Postfix) with ESMTPS id 3yGj2f0kVtz9t2h for ; Wed, 18 Oct 2017 04:33:13 +1100 (AEDT) DomainKey-Signature: a=rsa-sha1; c=nofws; d=gcc.gnu.org; h=list-id :list-unsubscribe:list-archive:list-post:list-help:sender:from :to:cc:subject:date:message-id; q=dns; s=default; b=LHJu9iUkxtY7 3WJf6tSPf1Qvf7/AQ6utcjArvn1kAMbpTRwFGv4vLrSHukpXxXn3YpnCAdHCtCLQ u98hRcuIqhbLagng3qqp7R9mv6iXaDgILx8xupxEBHVInVuzHe/cRxdYRI5/Urmd eUT+Q38lP5OqRiHhVszZsFeIYNz+Ie0= DKIM-Signature: v=1; a=rsa-sha1; c=relaxed; d=gcc.gnu.org; h=list-id :list-unsubscribe:list-archive:list-post:list-help:sender:from :to:cc:subject:date:message-id; s=default; bh=LrfkioQS+QNf3hat1V txgaH5Fvk=; b=yQ2gW06QLduaAbkWnoNeOVxGNZveULF0Gj9N4u0MV+q1byPqSf t4LtKtALYTaRdGvlaf6v4gmDePtYxfrtXE8ZdDKZQv16osD58XC5gmcy82clCf/G hkgDMGWATbAv5icW8ppVXDYV+LT+GjkGfQx72kuh7A8Whsg6jetHxrxgw= Received: (qmail 78518 invoked by alias); 17 Oct 2017 17:33:01 -0000 Mailing-List: contact gcc-patches-help@gcc.gnu.org; run by ezmlm Precedence: bulk List-Id: List-Unsubscribe: List-Archive: List-Post: List-Help: Sender: gcc-patches-owner@gcc.gnu.org Delivered-To: mailing list gcc-patches@gcc.gnu.org Received: (qmail 78493 invoked by uid 89); 17 Oct 2017 17:33:00 -0000 Authentication-Results: sourceware.org; auth=none X-Virus-Found: No X-Spam-SWARE-Status: No, score=-26.9 required=5.0 tests=BAYES_00, GIT_PATCH_0, GIT_PATCH_1, GIT_PATCH_2, GIT_PATCH_3, RP_MATCHES_RCVD, SPF_HELO_PASS autolearn=ham version=3.3.2 spammy= X-HELO: mx1.redhat.com Received: from mx1.redhat.com (HELO mx1.redhat.com) (209.132.183.28) by sourceware.org (qpsmtpd/0.93/v0.84-503-g423c35a) with ESMTP; Tue, 17 Oct 2017 17:32:57 +0000 Received: from smtp.corp.redhat.com (int-mx01.intmail.prod.int.phx2.redhat.com [10.5.11.11]) (using TLSv1.2 with cipher AECDH-AES256-SHA (256/256 bits)) (No client certificate requested) by mx1.redhat.com (Postfix) with ESMTPS id 52D01A00C3 for ; Tue, 17 Oct 2017 17:32:56 +0000 (UTC) DMARC-Filter: OpenDMARC Filter v1.3.2 mx1.redhat.com 52D01A00C3 Authentication-Results: ext-mx02.extmail.prod.ext.phx2.redhat.com; dmarc=none (p=none dis=none) header.from=redhat.com Authentication-Results: ext-mx02.extmail.prod.ext.phx2.redhat.com; spf=fail smtp.mailfrom=dmalcolm@redhat.com Received: from c64.redhat.com (ovpn-112-12.phx2.redhat.com [10.3.112.12]) by smtp.corp.redhat.com (Postfix) with ESMTP id 3D3CF7C686; Tue, 17 Oct 2017 17:32:54 +0000 (UTC) From: David Malcolm To: gcc-patches@gcc.gnu.org Cc: David Malcolm Subject: [PATCH] C/C++: more stdlib header hints (PR c/81404) Date: Tue, 17 Oct 2017 13:33:50 -0400 Message-Id: <1508261630-13799-1-git-send-email-dmalcolm@redhat.com> X-IsSubscribed: yes This patch depends on: * "[PATCH] c-family: add name_hint/deferred_diagnostic (v2)" * https://gcc.gnu.org/ml/gcc-patches/2017-10/msg01021.html (waiting review) * [PATCH 3/3] C: hints for missing stdlib includes for macros and types * https://gcc.gnu.org/ml/gcc-patches/2017-07/msg00125.html (approved, pending the prereq above) It 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 ''; did you forget to '#include '? t.c:1:1: +#include 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 ''; did you forget to '#include '? t.cc:1:1: +#include 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). Successfully bootstrapped & regrtested on x86_64-pc-linux-gnu. OK for trunk once the prereqs are in place? gcc/ChangeLog: * Makefile.in (C_COMMON_OBJS): Add c-family/known-headers.o. gcc/c-family/ChangeLog: * known-headers.cc: New file, with suggest_missing_header taken from c/c-decl.c. * known-headers.h: Likewise. gcc/c/ChangeLog: PR c/81404 * c-decl.c: Include "c-family/known-headers.h". (get_c_name_hint): Reimplement in terms of the API in known-headers.h. Add some knowledge about , , and . (class suggest_missing_header): Move to known-header.h. gcc/cp/ChangeLog: * name-lookup.c: Include "c-family/known-headers.h". (get_std_name_hint): Reimplement in terms of the API in known-headers.h. (get_stdlib_name_hint): New function. (lookup_name_fuzzy): Call get_stdlib_name_hint. gcc/testsuite/ChangeLog: PR c/81404 PR c++/80567 * g++.dg/spellcheck-stdlib.C: New test case. * gcc.dg/spellcheck-stdlib.c (test_INT_MAX): New. --- gcc/Makefile.in | 2 +- gcc/c-family/known-headers.cc | 68 ++++++++++++++++++++++++ gcc/c-family/known-headers.h | 63 ++++++++++++++++++++++ gcc/c/c-decl.c | 84 ++++++++++++++---------------- gcc/cp/name-lookup.c | 89 +++++++++++++++++++++++++++----- gcc/testsuite/g++.dg/spellcheck-stdlib.C | 84 ++++++++++++++++++++++++++++++ gcc/testsuite/gcc.dg/spellcheck-stdlib.c | 9 ++++ 7 files changed, 341 insertions(+), 58 deletions(-) create mode 100644 gcc/c-family/known-headers.cc create mode 100644 gcc/c-family/known-headers.h create mode 100644 gcc/testsuite/g++.dg/spellcheck-stdlib.C 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 +. */ + +#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 +. */ + +#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", ""}, + /* . */ + {"CHAR_BIT", ""}, + {"CHAR_MAX", ""}, + {"CHAR_MIN", ""}, + {"INT_MAX", ""}, + {"INT_MIN", ""}, + {"LLONG_MAX", ""}, + {"LLONG_MIN", ""}, + {"LONG_MAX", ""}, + {"LONG_MIN", ""}, + {"MB_LEN_MAX", ""}, + {"SCHAR_MAX", ""}, + {"SCHAR_MIN", ""}, + {"SHRT_MAX", ""}, + {"SHRT_MIN", ""}, + {"UCHAR_MAX", ""}, + {"UINT_MAX", ""}, + {"ULLONG_MAX", ""}, + {"ULONG_MAX", ""}, + {"USHRT_MAX", ""}, + /* . */ {"va_list", ""}, @@ -4017,49 +4034,26 @@ get_c_name_hint (const char *name) {"fpos_t", ""}, {"stderr", ""}, {"stdin", ""}, - {"stdout", ""} + {"stdout", ""}, + + /* . */ + {"PTRDIFF_MAX", ""}, + {"PTRDIFF_MIN", ""}, + {"SIG_ATOMIC_MAX", ""}, + {"SIG_ATOMIC_MIN", ""}, + {"SIZE_MAX", ""}, + + /* . */ + {"WCHAR_MAX", ""}, + {"WCHAR_MIN", ""}, + {"WINT_MAX", ""}, + {"WINT_MIN", ""} }; 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", ""}, // C++11 /* . */ @@ -5456,12 +5452,8 @@ get_std_name_hint (const char *name) {"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[] = { + /* . */ + {"errno", ""}, + + /* . */ + {"CHAR_BIT", ""}, + {"CHAR_MAX", ""}, + {"CHAR_MIN", ""}, + {"INT_MAX", ""}, + {"INT_MIN", ""}, + {"LLONG_MAX", ""}, + {"LLONG_MIN", ""}, + {"LONG_MAX", ""}, + {"LONG_MIN", ""}, + {"MB_LEN_MAX", ""}, + {"SCHAR_MAX", ""}, + {"SCHAR_MIN", ""}, + {"SHRT_MAX", ""}, + {"SHRT_MIN", ""}, + {"UCHAR_MAX", ""}, + {"UINT_MAX", ""}, + {"ULLONG_MAX", ""}, + {"ULONG_MAX", ""}, + {"USHRT_MAX", ""}, + + /* . */ + {"va_list", ""}, + + /* . */ + {"NULL", ""}, + {"nullptr_t", ""}, + {"offsetof", ""}, + {"ptrdiff_t", ""}, + {"size_t", ""}, + + /* . */ + {"BUFSIZ", ""}, + {"EOF", ""}, + {"FILE", ""}, + {"FILENAME_MAX", ""}, + {"fpos_t", ""}, + {"stderr", ""}, + {"stdin", ""}, + {"stdout", ""}, + + /* . */ + {"PTRDIFF_MAX", ""}, + {"PTRDIFF_MIN", ""}, + {"SIG_ATOMIC_MAX", ""}, + {"SIG_ATOMIC_MIN", ""}, + {"SIZE_MAX", ""}, + }; + 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 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 . */ + +void *ptr = NULL; // { dg-error "'NULL' was not declared" } +// { dg-message "'NULL' is defined in header ''; did you forget to '#include '?" "" { target *-*-* } .-1 } + +ptrdiff_t pd; // { dg-error "'ptrdiff_t' does not name a type" } +// { dg-message "'ptrdiff_t' is defined in header ''; did you forget to '#include '?" "" { target *-*-* } .-1 } + +size_t sz; // { dg-error "'size_t' does not name a type" } +// { dg-message "'size_t' is defined in header ''; did you forget to '#include '?" "" { target *-*-* } .-1 } + +/* Missing . */ + +void test_cstdio (void) +{ + FILE *f; // { dg-error "'FILE' was not declared in this scope" } + // { dg-message "'FILE' is defined in header ''; did you forget to '#include '?" "" { 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 ''; did you forget to '#include '?" "" { target *-*-* } .-1 } + + char buf2[FILENAME_MAX]; // { dg-error "'FILENAME_MAX' was not declared" } + // { dg-message "'FILENAME_MAX' is defined in header ''; did you forget to '#include '?" "" { target *-*-* } .-1 } + + stderr; // { dg-error "'stderr' was not declared" } + // { dg-message "'stderr' is defined in header ''; did you forget to '#include '?" "" { target *-*-* } .-1 } + + stdin; // { dg-error "'stdin' was not declared" } + // { dg-message "'stdin' is defined in header ''; did you forget to '#include '?" "" { target *-*-* } .-1 } + + stdout; // { dg-error "'stdout' was not declared" } + // { dg-message "'stdout' is defined in header ''; did you forget to '#include '?" "" { target *-*-* } .-1 } + + EOF; // { dg-error "'EOF' was not declared" } + // { dg-message "'EOF' is defined in header ''; did you forget to '#include '?" "" { target *-*-* } .-1 } +} + +/* Missing . */ + +int test_cerrno (void) +{ + return errno; // { dg-error "'errno' was not declared" } + // { dg-message "'errno' is defined in header ''; did you forget to '#include '?" "" { target *-*-* } .-1 } +} + +/* Missing . */ + +void test_cstdarg (void) +{ + va_list ap; // { dg-error "'va_list'" } + // { dg-message "'va_list' is defined in header ''; did you forget to '#include '?" "" { target *-*-* } .-1 } +} + +/* Missing . */ +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 ''; did you forget to '#include '?" "" { 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 ''; did you forget to '#include '?" "" { target *-*-* } .-1 } */ } + +/* Missing . */ +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 ''; did you forget to '#include '?" "" { target *-*-* } INT_MAX_line } */ +}