aboutsummaryrefslogtreecommitdiff
path: root/gcc
diff options
context:
space:
mode:
authorDavid Malcolm <dmalcolm@redhat.com>2018-04-06 15:46:04 +0000
committerDavid Malcolm <dmalcolm@gcc.gnu.org>2018-04-06 15:46:04 +0000
commitcb731872870ff15c4d4a4dc081191ed607faaa2b (patch)
tree3483741b7ae559112f750a988ecb3cdcd8369315 /gcc
parenta82f886aa67b81ef2c8499b698c2803f262bb582 (diff)
downloadgcc-cb731872870ff15c4d4a4dc081191ed607faaa2b.zip
gcc-cb731872870ff15c4d4a4dc081191ed607faaa2b.tar.gz
gcc-cb731872870ff15c4d4a4dc081191ed607faaa2b.tar.bz2
C++: suggest missing headers for implicit use of "std" (PR c++/85021)
We provide fix-it hints for the most common "std" names when an explicit "std::" prefix is present, however we don't yet provide fix-it hints for this implicit case: using namespace std; void f() { cout << "test"; } for which we emit: t.cc: In function 'void f()': t.cc:2:13: error: 'cout' was not declared in this scope void f() { cout << "test"; } ^~~~ This patch detects if a "using namespace std;" directive is present in the current namespace, and if so, offers a suggestion for unrecognized names that are in our list of common "std" names: t.cc: In function 'void f()': t.cc:2:13: error: 'cout' was not declared in this scope void f() { cout << "test"; } ^~~~ t.cc:2:13: note: 'std::cout' is defined in header '<iostream>'; did you forget to '#include <iostream>'? +#include <iostream> using namespace std; void f() { cout << "test"; } ^~~~ gcc/cp/ChangeLog: PR c++/85021 * name-lookup.c (using_directives_contain_std_p): New function. (has_using_namespace_std_directive_p): New function. (suggest_alternatives_for): Simplify if/else logic using early returns. If no candidates were found, and there's a "using namespace std;" directive, call maybe_suggest_missing_std_header. (maybe_suggest_missing_header): Split later part of the function into.. (maybe_suggest_missing_std_header): New. gcc/testsuite/ChangeLog: PR c++/85021 * g++.dg/lookup/missing-std-include-7.C: New test. From-SVN: r259179
Diffstat (limited to 'gcc')
-rw-r--r--gcc/cp/ChangeLog13
-rw-r--r--gcc/cp/name-lookup.c93
-rw-r--r--gcc/testsuite/ChangeLog5
-rw-r--r--gcc/testsuite/g++.dg/lookup/missing-std-include-7.C100
4 files changed, 197 insertions, 14 deletions
diff --git a/gcc/cp/ChangeLog b/gcc/cp/ChangeLog
index 71a5d45..a27484b 100644
--- a/gcc/cp/ChangeLog
+++ b/gcc/cp/ChangeLog
@@ -1,3 +1,16 @@
+2018-04-06 David Malcolm <dmalcolm@redhat.com>
+
+ PR c++/85021
+ * name-lookup.c (using_directives_contain_std_p): New function.
+ (has_using_namespace_std_directive_p): New function.
+ (suggest_alternatives_for): Simplify if/else logic using early
+ returns. If no candidates were found, and there's a
+ "using namespace std;" directive, call
+ maybe_suggest_missing_std_header.
+ (maybe_suggest_missing_header): Split later part of the function
+ into..
+ (maybe_suggest_missing_std_header): New.
+
2018-04-06 Jason Merrill <jason@redhat.com>
PR c++/85242 - ICE with class definition in template parm.
diff --git a/gcc/cp/name-lookup.c b/gcc/cp/name-lookup.c
index 62f0b3f..dc7699d 100644
--- a/gcc/cp/name-lookup.c
+++ b/gcc/cp/name-lookup.c
@@ -41,6 +41,7 @@ static cxx_binding *cxx_binding_make (tree value, tree type);
static cp_binding_level *innermost_nonclass_level (void);
static void set_identifier_type_value_with_scope (tree id, tree decl,
cp_binding_level *b);
+static bool maybe_suggest_missing_std_header (location_t location, tree name);
/* Create an overload suitable for recording an artificial TYPE_DECL
and another decl. We use this machanism to implement the struct
@@ -5330,6 +5331,48 @@ qualify_lookup (tree val, int flags)
return true;
}
+/* Is there a "using namespace std;" directive within USINGS? */
+
+static bool
+using_directives_contain_std_p (vec<tree, va_gc> *usings)
+{
+ if (!usings)
+ return false;
+
+ for (unsigned ix = usings->length (); ix--;)
+ if ((*usings)[ix] == std_node)
+ return true;
+
+ return false;
+}
+
+/* Is there a "using namespace std;" directive within the current
+ namespace (or its ancestors)?
+ Compare with name_lookup::search_unqualified. */
+
+static bool
+has_using_namespace_std_directive_p ()
+{
+ /* Look at local using-directives. */
+ for (cp_binding_level *level = current_binding_level;
+ level->kind != sk_namespace;
+ level = level->level_chain)
+ if (using_directives_contain_std_p (level->using_directives))
+ return true;
+
+ /* Look at this namespace and its ancestors. */
+ for (tree scope = current_namespace; scope; scope = CP_DECL_CONTEXT (scope))
+ {
+ if (using_directives_contain_std_p (DECL_NAMESPACE_USING (scope)))
+ return true;
+
+ if (scope == global_namespace)
+ break;
+ }
+
+ return false;
+}
+
/* Suggest alternatives for NAME, an IDENTIFIER_NODE for which name
lookup failed. Search through all available namespaces and print out
possible candidates. If no exact matches are found, and
@@ -5400,11 +5443,23 @@ suggest_alternatives_for (location_t location, tree name,
inform (location_of (val), " %qE", val);
}
candidates.release ();
+ return;
}
- else if (!suggest_misspellings)
- ;
- else if (name_hint hint = lookup_name_fuzzy (name, FUZZY_LOOKUP_NAME,
- location))
+
+ /* No candidates were found in the available namespaces. */
+
+ /* If there's a "using namespace std;" active, and this
+ is one of the most common "std::" names, then it's probably a
+ missing #include. */
+ if (has_using_namespace_std_directive_p ())
+ if (maybe_suggest_missing_std_header (location, name))
+ return;
+
+ /* Otherwise, consider misspellings. */
+ if (!suggest_misspellings)
+ return;
+ if (name_hint hint = lookup_name_fuzzy (name, FUZZY_LOOKUP_NAME,
+ location))
{
/* Show a spelling correction. */
gcc_rich_location richloc (location);
@@ -5512,20 +5567,13 @@ get_std_name_hint (const char *name)
return NULL;
}
-/* If SCOPE is the "std" namespace, then suggest pertinent header
- files for NAME at LOCATION.
+/* Suggest pertinent header files for NAME at LOCATION, for common
+ names within the "std" namespace.
Return true iff a suggestion was offered. */
static bool
-maybe_suggest_missing_header (location_t location, tree name, tree scope)
+maybe_suggest_missing_std_header (location_t location, tree name)
{
- if (scope == NULL_TREE)
- return false;
- if (TREE_CODE (scope) != NAMESPACE_DECL)
- return false;
- /* We only offer suggestions for the "std" namespace. */
- if (scope != std_node)
- return false;
gcc_assert (TREE_CODE (name) == IDENTIFIER_NODE);
const char *name_str = IDENTIFIER_POINTER (name);
@@ -5542,6 +5590,23 @@ maybe_suggest_missing_header (location_t location, tree name, tree scope)
return true;
}
+/* If SCOPE is the "std" namespace, then suggest pertinent header
+ files for NAME at LOCATION.
+ Return true iff a suggestion was offered. */
+
+static bool
+maybe_suggest_missing_header (location_t location, tree name, tree scope)
+{
+ if (scope == NULL_TREE)
+ return false;
+ if (TREE_CODE (scope) != NAMESPACE_DECL)
+ return false;
+ /* We only offer suggestions for the "std" namespace. */
+ if (scope != std_node)
+ return false;
+ return maybe_suggest_missing_std_header (location, name);
+}
+
/* 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.
diff --git a/gcc/testsuite/ChangeLog b/gcc/testsuite/ChangeLog
index 0ea9f64..e192061 100644
--- a/gcc/testsuite/ChangeLog
+++ b/gcc/testsuite/ChangeLog
@@ -1,3 +1,8 @@
+2018-04-06 David Malcolm <dmalcolm@redhat.com>
+
+ PR c++/85021
+ * g++.dg/lookup/missing-std-include-7.C: New test.
+
2018-04-06 Tamar Christina <tamar.christina@arm.com>
* gcc.dg/struct-simple.c: Revert r254862.
diff --git a/gcc/testsuite/g++.dg/lookup/missing-std-include-7.C b/gcc/testsuite/g++.dg/lookup/missing-std-include-7.C
new file mode 100644
index 0000000..4c87c8c
--- /dev/null
+++ b/gcc/testsuite/g++.dg/lookup/missing-std-include-7.C
@@ -0,0 +1,100 @@
+/* PR c++/85021: Verify that we suggest missing headers for common names in std::
+ if there's a "using namespace std;" active. */
+
+/* No using-directive. */
+
+void test_1 ()
+{
+ cout << "test"; // { dg-error "'cout' was not declared in this scope" }
+ // { dg-bogus "'<iostream>'" "" { target *-*-* } .-1 }
+}
+
+/* Local using-directive. */
+
+void test_2 ()
+{
+ using namespace std;
+ cout << "test"; // { dg-error "'cout' was not declared in this scope" }
+ // { dg-message "'std::cout' is defined in header '<iostream>'" "" { target *-*-* } .-1 }
+}
+
+/* Local using-directive, but not of "std". */
+
+namespace not_std {}
+void test_3 ()
+{
+ using namespace not_std;
+ cout << "test"; // { dg-error "'cout' was not declared in this scope" }
+ // { dg-bogus "'<iostream>'" "" { target *-*-* } .-1 }
+}
+
+/* Local using-directive in wrong block. */
+
+void test_4 ()
+{
+ {
+ using namespace std;
+ }
+ cout << "test"; // { dg-error "'cout' was not declared in this scope" }
+ // { dg-bogus "'<iostream>'" "" { target *-*-* } .-1 }
+}
+
+/* Local using-directive used from nested block. */
+
+void test_5 ()
+{
+ using namespace std;
+
+ for (int i = 0; i < 10; i++)
+ {
+ cout << "test"; // { dg-error "'cout' was not declared in this scope" }
+ // { dg-message "'std::cout' is defined in header '<iostream>'" "" { target *-*-* } .-1 }
+ }
+}
+
+namespace ns_1 {
+
+namespace ns_2 {
+
+using namespace std;
+
+/* using-directive within the same namespace. */
+
+void test_6 ()
+{
+ cout << "test"; // { dg-error "'cout' was not declared in this scope" }
+ // { dg-message "'std::cout' is defined in header '<iostream>'" "" { target *-*-* } .-1 }
+}
+
+namespace ns_3 {
+
+/* Locate the using-directive within ns_2, the parent namespace. */
+
+void test_7 ()
+{
+ cout << "test"; // { dg-error "'cout' was not declared in this scope" }
+ // { dg-message "'std::cout' is defined in header '<iostream>'" "" { target *-*-* } .-1 }
+}
+
+} // namespace ns_3
+} // namespace ns_2
+
+/* Back in ns_1, should not locate the using-directive. */
+
+void test_8 ()
+{
+ cout << "test"; // { dg-error "'cout' was not declared in this scope" }
+ // { dg-bogus "'<iostream>'" "" { target *-*-* } .-1 }
+}
+
+} // namespace ns_1
+
+/* using-directive in global namespace. */
+using namespace std;
+
+void test_9 ()
+{
+ cout << "test"; // { dg-error "'cout' was not declared in this scope" }
+ // { dg-message "'std::cout' is defined in header '<iostream>'" "" { target *-*-* } .-1 }
+}
+