On Thu, Mar 22, 2018 at 7:44 PM, David Malcolm <[email protected]> wrote:
> 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"; }
> ^~~~
>
> Is there a better way to test for the using directive?
>
> Successfully bootstrapped & regrtested on x86_64-pc-linux-gnu.
>
> OK for trunk?
>
> gcc/cp/ChangeLog:
> PR c++/85021
> * name-lookup.c (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.
> ---
> gcc/cp/name-lookup.c | 68
> +++++++++++++++++-----
> .../g++.dg/lookup/missing-std-include-7.C | 16 +++++
> 2 files changed, 70 insertions(+), 14 deletions(-)
> create mode 100644 gcc/testsuite/g++.dg/lookup/missing-std-include-7.C
>
> diff --git a/gcc/cp/name-lookup.c b/gcc/cp/name-lookup.c
> index 061729a..4eb980e 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
> @@ -5327,6 +5328,23 @@ qualify_lookup (tree val, int flags)
> return true;
> }
>
> +/* Is there a "using namespace std;" directive within the current
> + namespace? */
> +
> +static bool
> +has_using_namespace_std_directive_p ()
> +{
> + vec<tree, va_gc> *usings = DECL_NAMESPACE_USING (current_namespace);
Checking in just the current namespace won't find a "using namespace
std" in an inner or outer scope; I think you want to add something to
name-lookup.c that iterates over the current enclosing scopes like
name_lookup::search_unqualified. Nathan can probably be more
specific.
Jason
> + if (!usings)
> + return false;
> +
> + for (unsigned ix = usings->length (); ix--;)
> + if ((*usings)[ix] == std_node)
> + return true;
> +
> + 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
> @@ -5397,11 +5415,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);
> @@ -5509,20 +5539,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);
> @@ -5539,6 +5562,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/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..95946ff
> --- /dev/null
> +++ b/gcc/testsuite/g++.dg/lookup/missing-std-include-7.C
> @@ -0,0 +1,16 @@
> +/* PR c++/85021: Verify that we suggest missing headers for common names in
> std::
> + if there's a "using namespace std;" active. */
> +
> +void test_without_using_directive ()
> +{
> + cout << "test"; // { dg-error "'cout' was not declared in this scope" }
> + // { dg-bogus "'<iostream>'" "" { target *-*-* } .-1 }
> +}
> +
> +using namespace std;
> +
> +void test_with_using_directive ()
> +{
> + cout << "test"; // { dg-error "'cout' was not declared in this scope" }
> + // { dg-message "'std::cout' is defined in header '<iostream>'" "" {
> target *-*-* } .-1 }
> +}
> --
> 1.8.5.3
>