diff options
author | David Malcolm <dmalcolm@redhat.com> | 2017-04-25 13:54:35 +0000 |
---|---|---|
committer | David Malcolm <dmalcolm@gcc.gnu.org> | 2017-04-25 13:54:35 +0000 |
commit | 5ca28c1d5f5f8c435d534ed6142e8215b0babb65 (patch) | |
tree | 4af24850da8afcbe9bf1a162913989aa86eeac0b /gcc | |
parent | 2ec07fa616d283c60844031818c239f1714d31c9 (diff) | |
download | gcc-5ca28c1d5f5f8c435d534ed6142e8215b0babb65.zip gcc-5ca28c1d5f5f8c435d534ed6142e8215b0babb65.tar.gz gcc-5ca28c1d5f5f8c435d534ed6142e8215b0babb65.tar.bz2 |
C++: hints for missing std:: headers
gcc/cp/ChangeLog:
* name-lookup.c (get_std_name_hint): New function.
(maybe_suggest_missing_header): New function.
(suggest_alternative_in_explicit_scope): Call
maybe_suggest_missing_header.
gcc/testsuite/ChangeLog:
* g++.dg/lookup/missing-std-include.C: New test file.
From-SVN: r247240
Diffstat (limited to 'gcc')
-rw-r--r-- | gcc/cp/ChangeLog | 7 | ||||
-rw-r--r-- | gcc/cp/name-lookup.c | 109 | ||||
-rw-r--r-- | gcc/testsuite/ChangeLog | 4 | ||||
-rw-r--r-- | gcc/testsuite/g++.dg/lookup/missing-std-include.C | 29 |
4 files changed, 149 insertions, 0 deletions
diff --git a/gcc/cp/ChangeLog b/gcc/cp/ChangeLog index b04894d..ff80b33 100644 --- a/gcc/cp/ChangeLog +++ b/gcc/cp/ChangeLog @@ -1,5 +1,12 @@ 2017-04-25 David Malcolm <dmalcolm@redhat.com> + * name-lookup.c (get_std_name_hint): New function. + (maybe_suggest_missing_header): New function. + (suggest_alternative_in_explicit_scope): Call + maybe_suggest_missing_header. + +2017-04-25 David Malcolm <dmalcolm@redhat.com> + PR c++/80177 * name-lookup.c (suggest_alternative_in_explicit_scope): Convert candidate type of bm from tree to const char *. diff --git a/gcc/cp/name-lookup.c b/gcc/cp/name-lookup.c index eda6db2..0c5df93 100644 --- a/gcc/cp/name-lookup.c +++ b/gcc/cp/name-lookup.c @@ -4537,6 +4537,113 @@ suggest_alternatives_for (location_t location, tree name, candidates.release (); } +/* Subroutine of maybe_suggest_missing_header for handling unrecognized names + for some of the most common names within "std::". + Given non-NULL NAME, a name for lookup within "std::", return the header + name defining it within the C++ Standard Library (without '<' and '>'), + or NULL. */ + +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[] = { + /* <array>. */ + {"array", "array"}, // C++11 + /* <deque>. */ + {"deque", "deque"}, + /* <forward_list>. */ + {"forward_list", "forward_list"}, // C++11 + /* <fstream>. */ + {"basic_filebuf", "fstream"}, + {"basic_ifstream", "fstream"}, + {"basic_ofstream", "fstream"}, + {"basic_fstream", "fstream"}, + /* <iostream>. */ + {"cin", "iostream"}, + {"cout", "iostream"}, + {"cerr", "iostream"}, + {"clog", "iostream"}, + {"wcin", "iostream"}, + {"wcout", "iostream"}, + {"wclog", "iostream"}, + /* <list>. */ + {"list", "list"}, + /* <map>. */ + {"map", "map"}, + {"multimap", "map"}, + /* <queue>. */ + {"queue", "queue"}, + {"priority_queue", "queue"}, + /* <ostream>. */ + {"ostream", "ostream"}, + {"wostream", "ostream"}, + {"ends", "ostream"}, + {"flush", "ostream"}, + {"endl", "ostream"}, + /* <set>. */ + {"set", "set"}, + {"multiset", "set"}, + /* <sstream>. */ + {"basic_stringbuf", "sstream"}, + {"basic_istringstream", "sstream"}, + {"basic_ostringstream", "sstream"}, + {"basic_stringstream", "sstream"}, + /* <stack>. */ + {"stack", "stack"}, + /* <string>. */ + {"string", "string"}, + {"wstring", "string"}, + {"u16string", "string"}, + {"u32string", "string"}, + /* <unordered_map>. */ + {"unordered_map", "unordered_map"}, // C++11 + {"unordered_multimap", "unordered_map"}, // C++11 + /* <unordered_set>. */ + {"unordered_set", "unordered_set"}, // C++11 + {"unordered_multiset", "unordered_set"}, // C++11 + /* <vector>. */ + {"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; +} + +/* Subroutine of suggest_alternative_in_explicit_scope, for use when we have no + suggestions to offer. + If SCOPE is the "std" namespace, then suggest pertinent header + files for NAME. */ + +static void +maybe_suggest_missing_header (location_t location, tree name, tree scope) +{ + if (scope == NULL_TREE) + return; + if (TREE_CODE (scope) != NAMESPACE_DECL) + return; + /* We only offer suggestions for the "std" namespace. */ + if (scope != std_node) + return; + gcc_assert (TREE_CODE (name) == IDENTIFIER_NODE); + + const char *name_str = IDENTIFIER_POINTER (name); + const char *header_hint = get_std_name_hint (name_str); + if (header_hint) + inform (location, + "%<std::%s%> is defined in header %<<%s>%>;" + " did you forget to %<#include <%s>%>?", + name_str, header_hint, header_hint); +} + /* Look for alternatives for NAME, an IDENTIFIER_NODE for which name lookup failed within the explicitly provided SCOPE. Suggest the the best meaningful candidates (if any) as a fix-it hint. @@ -4564,6 +4671,8 @@ suggest_alternative_in_explicit_scope (location_t location, tree name, fuzzy_name); return true; } + else + maybe_suggest_missing_header (location, name, scope); return false; } diff --git a/gcc/testsuite/ChangeLog b/gcc/testsuite/ChangeLog index c60d9a2..a8e24e9 100644 --- a/gcc/testsuite/ChangeLog +++ b/gcc/testsuite/ChangeLog @@ -1,3 +1,7 @@ +2017-04-25 David Malcolm <dmalcolm@redhat.com> + + * g++.dg/lookup/missing-std-include.C: New test file. + 2017-04-25 Ramana Radhakrishnan <ramana.radhakrishnan@arm.com> Jakub Jelinek <jakub@redhat.com> diff --git a/gcc/testsuite/g++.dg/lookup/missing-std-include.C b/gcc/testsuite/g++.dg/lookup/missing-std-include.C new file mode 100644 index 0000000..82f994f --- /dev/null +++ b/gcc/testsuite/g++.dg/lookup/missing-std-include.C @@ -0,0 +1,29 @@ +void test (void) +{ + std::string s ("hello world"); // { dg-error ".string. is not a member of .std." } + // { dg-message ".std::string. is defined in header .<string>.; did you forget to .#include <string>.?" "" { target *-*-* } .-1 } + + std::wstring ws ("hello world"); // { dg-error ".wstring. is not a member of .std." } + // { dg-message ".std::wstring. is defined in header .<string>.; did you forget to .#include <string>.?" "" { target *-*-* } .-1 } + + std::cout << 10; // { dg-error ".cout. is not a member of .std." } + // { dg-message ".std::cout. is defined in header .<iostream>.; did you forget to .#include <iostream>.?" "" { target *-*-* } .-1 } + + int i; + std::cin >> i; // { dg-error ".cin. is not a member of .std." } + // { dg-message ".std::cin. is defined in header .<iostream>.; did you forget to .#include <iostream>.?" "" { target *-*-* } .-1 } + + std::array a; // { dg-error ".array. is not a member of .std." } + // { dg-message ".std::array. is defined in header .<array>.; did you forget to .#include <array>.?" "" { target *-*-* } .-1 } + + std::deque a; // { dg-error ".deque. is not a member of .std." } + // { dg-message ".std::deque. is defined in header .<deque>.; did you forget to .#include <deque>.?" "" { target *-*-* } .-1 } + + std::vector<int> v; // { dg-error ".vector. is not a member of .std." } + // { dg-message ".std::vector. is defined in header .<vector>.; did you forget to .#include <vector>.?" "" { target *-*-* } .-1 } + // { dg-error "expected primary-expression before .int." "" { target *-*-* } .-2 } + + std::list<int> lst; // { dg-error ".list. is not a member of .std." } + // { dg-message ".std::list. is defined in header .<list>.; did you forget to .#include <list>.?" "" { target *-*-* } .-1 } + // { dg-error "expected primary-expression before .int." "" { target *-*-* } .-2 } +} |