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
>

Reply via email to