Commit cb731872 by David Malcolm Committed by David Malcolm

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
parent a82f886a
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.
......
......@@ -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.
......
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.
......
/* 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 }
}
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment