OK.
On Thu, Apr 5, 2018 at 7:40 PM, David Malcolm <dmalc...@redhat.com> wrote: > On Thu, 2018-03-29 at 15:25 -0400, Jason Merrill wrote: >> On Thu, Mar 22, 2018 at 7:44 PM, David Malcolm <dmalc...@redhat.com> >> 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 > > Thanks. > > Here's an updated version of the patch. > > Rather than just search in DECL_NAMESPACE_USING (current_namespace), > this version mimics name_lookup::search_unqualified by searching for local > using-directives in the current_binding_level until it reaches a sk_namespace, > and then searching in current_namespace and its ancestors. > (and builds out the test coverage accordingly) > > Successfully bootstrapped & regrtested on x86_64-pc-linux-gnu; adds > 57 PASS results to g++.sum. > > OK for trunk? > > 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. > --- > gcc/cp/name-lookup.c | 93 ++++++++++++++++--- > .../g++.dg/lookup/missing-std-include-7.C | 100 > +++++++++++++++++++++ > 2 files changed, 179 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 9b5db3d..a9f3094 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/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 } > +} > + > -- > 1.8.5.3 >