C++: simplify output from suggest_alternatives_for
authorDavid Malcolm <dmalcolm@redhat.com>
Mon, 29 Oct 2018 23:53:50 +0000 (23:53 +0000)
committerDavid Malcolm <dmalcolm@gcc.gnu.org>
Mon, 29 Oct 2018 23:53:50 +0000 (23:53 +0000)
In the C++ FE, after emitting various errors about unrecognized names,
the parser can call
  suggest_alternatives_for
and/or
  suggest_alternative_in_explicit_scope.
These can issue zero or more suggestions for the unrecognized name,
or various other "note" diagnostics suggesting how to fix the problem.

For example, currently g++ emits:

t.cc:12:3: error: 'gtk_widget_showall' was not declared in this scope
12 |   gtk_widget_showall (w);
   |   ^~~~~~~~~~~~~~~~~~
t.cc:12:3: note: suggested alternative: 'gtk_widget_show_all'
12 |   gtk_widget_showall (w);
   |   ^~~~~~~~~~~~~~~~~~
   |   gtk_widget_show_all

This patch consolidates the common case when there is a single
candidate, so that the error can issue a fix-it hint directly.

This simplifies the above to:

t.cc:12:3: error: 'gtk_widget_showall' was not declared in this scope;
 did you mean 'gtk_widget_show_all'?
12 |   gtk_widget_showall (w);
   |   ^~~~~~~~~~~~~~~~~~
   |   gtk_widget_show_all

omitting the second "note" diagnostic.

Doing so requires changing the above "suggest_" functions so that
rather than being called after "error" and emitting a note directly,
they are called before the "error", and return a name_hint, which
can contain a suggestion and/or a deferred diagnostic.  The "single
candidate" case is handled via a suggestion, and the "multiple
candidates" case via a new subclass of deferred_diagnostic.

There was some complication due to the fact that we don't always have
enough location information to issue a fix-it hint.  Specifically,
for the case in qualified_name_lookup_error, the location is that of
the name, but the location of the qualifier prefix isn't reliably
available.  For some hints, e.g. spell-corrections, the replacement
is of the name, and for others, e.g. parent namespaces, it's for the
qualified name.  The patch addresses this by splitting this case out
into a new "suggest_alternatives_in_other_namespaces" function, for
which fix-it hints aren't issued.

Another complication is that of emitting a note when
  --param cxx-max-namespaces-for-diagnostic-help
is reached.  The patch emulates the existing behavior by emitting
the note from a deferred_diagnostic.  This potentially needs to
co-exist with another deferred_diagnostic, so it works as a decorator
around any other such deferred_diagnostic.  Doing so requires slightly
extending class name_hint.

On adding test coverage for the various cases, I discovered that
after emitting a "FOO is not a namespace-name" error, we also emit
a "expected namespace-name before" error.  The patch removes this
second error for the case where it's redundant, simplifying this case
from e.g.:

spellcheck-ns.C:10:24: error: 'inner_ms' is not a namespace-name
10 | using namespace outer::inner_ms;
   |                        ^~~~~~~~
spellcheck-ns.C:10:24: note: suggested alternative: 'inner_ns'
10 | using namespace outer::inner_ms;
   |                        ^~~~~~~~
   |                        inner_ns
spellcheck-ns.C:10:32: error: expected namespace-name before ';' token
10 | using namespace outer::inner_ms;
   |                                ^

to:

spellcheck-ns.C:10:24: error: 'inner_ms' is not a namespace-name;
 did you mean 'inner_ns'?
10 | using namespace outer::inner_ms;
   |                        ^~~~~~~~
   |                        inner_ns

include/ChangeLog:
* unique-ptr.h (gnu::move): Generalize so it applies to all
lvalue references, rather than just to unique_ptr values.

gcc/c-family/ChangeLog:
* name-hint.h (name_hint::take_deferred): New member function.

gcc/c/ChangeLog:
* c-decl.c (implicit_decl_warning): Update "is there a suggestion"
logic for change to name_hint::operator bool.
(undeclared_variable): Likewise.
* c-parser.c (c_parser_declaration_or_fndef): Likewise.
(c_parser_parameter_declaration): Likewise.

gcc/cp/ChangeLog:
* cp-name-hint.h: New file.
* cp-tree.h (expr_to_string): New decl.
(suggest_alternatives_for): Move to cp-name-hint.h, changing
return type from bool to name_hint.
(suggest_alternative_in_explicit_scope): Likewise.
* error.c: Define INCLUDE_UNIQUE_PTR.  Include "cp-name-hint.h".
(expr_to_string): Make non-static.
(qualified_name_lookup_error): For the non-"::" case, take
responsibity for issuing any suggestion from
suggest_alternative_in_explicit_scope, as it changes from
returning a bool to returning a name_hint.  Replace fallback call
to suggest_alternatives_for to a call to
suggest_alternatives_in_other_namespaces, capturing the fact that
we don't have enough location information to issue a fix-it hint
for this case.  Update the error to support emitting a fix-it hint
where appropriate.  For the "::" case, take responsibility for
issuing any suggestion from suggest_alternatives_for, supporting
emitting a fix-it hint.
* lex.c: Define INCLUDE_UNIQUE_PTR.  Include "gcc-rich-location.h"
and "cp-name-hint.h".
(unqualified_name_lookup_error): Take responsibility for issuing
any suggestion from suggest_alternatives_for, supporting emitting
a fix-it hint.
* name-lookup.c (class namespace_limit_reached): New subclass of
deferred_diagnostic.
(class show_candidate_location): Likewise.
(class suggest_alternatives): Likewise.
(class namespace_hints): New class.
(suggest_alternatives_for): Convert return type from bool to
name_hint, replacing all direct diagnostic emission by setting
suggestions on the return value, or creating deferred diagnostics.
Specifically, split out initial traversal of namespaces into
namespace_hints' ctor, and maybe_decorate_with_limit, and move the
rest of the implementation to
namespace_hints::convert_candidates_to_name_hint and
suggest_alternatives_for_1.
(namespace_hints::namespace_hints): New ctor, adapted from
suggest_alternatives_for's initial namespace traversal, storing
location and name, and converting locals "candidates", "limited"
and "limit" into members.
(namespace_hints::convert_candidates_to_name_hint): New member
function.
(namespace_hints::maybe_decorate_with_limit): New member function.
(suggest_alternatives_for_1): New function, based on second half
of old implementation of suggest_alternatives_for, converting from
immediate emission of suggestions to using name_hint.
(suggest_alternatives_in_other_namespaces): New function.
(maybe_suggest_missing_std_header): Convert from immediate
emission of suggestions to using name_hint, moving emission
implementation to...
(class missing_std_header): New subclass of deferred_diagnostic.
(maybe_suggest_missing_header): Convert return type from bool to
name_hint.
(suggest_alternative_in_explicit_scope): Convert from immediate
emission of suggestions to using name_hint.
* parser.c: Replace include of "c-family/name-hint.h" with
"cp-name-hint.h".
(cp_parser_diagnose_invalid_type_name): Update
"is there a suggestion" logic for change to
name_hint::operator bool.  Take responsibility for emitting
fix-it hints from suggest_alternative_in_explicit_scope.
(cp_parser_namespace_name): Take responsibility for emitting
fix-it hints from suggest_alternative_in_explicit_scope.  Don't
emit the "expected namespace-name" error if we've already emitted
an "is not a namespace-name" error.

gcc/testsuite/ChangeLog:
* c-c++-common/spellcheck-reserved.c: Update expected output for
C++ for merger of "did you mean" suggestions into the error
message.
* g++.dg/ext/builtin3.C: Update expected output for merger of "did
you mean" suggestion into the error.
* g++.dg/lookup/error1.C: Likewise.
* g++.dg/lookup/pr77549.C: Likewise.
* g++.dg/lookup/pr80913.C: Likewise.
* g++.dg/lookup/suggestions1.C: Likewise.
* g++.dg/lookup/suggestions2.C: New test.
* g++.dg/overload/koenig1.C: Update expected output as above.
* g++.dg/spellcheck-identifiers-2.C: Likewise.
* g++.dg/spellcheck-identifiers.C: Likewise.
* g++.dg/spellcheck-ns.C: New test.
* g++.dg/spellcheck-pr77829.C: Update expected output as above.
* g++.dg/spellcheck-pr78656.C: Likewise.
* g++.dg/spellcheck-pr79298.C: Likewise, adding
-fdiagnostics-show-caret to options.
* g++.dg/spellcheck-pr80177.C: Likewise.
* g++.dg/spellcheck-single-vs-multiple.C: New test.
* g++.dg/spellcheck-typenames.C: Update expected output as above.
* g++.dg/template/static10.C: Likewise.
* g++.old-deja/g++.mike/ns5.C: Likewise.
* g++.old-deja/g++.mike/ns7.C: Likewise.
* g++.old-deja/g++.ns/koenig5.C: Likewise.
* g++.old-deja/g++.other/lineno5.C: Likewise.

libstdc++-v3/ChangeLog:
* testsuite/17_intro/using_namespace_std_exp_neg.cc: Remove
"expected namespace-name before" error.
* testsuite/17_intro/using_namespace_std_tr1_neg.cc: Likewise.

From-SVN: r265610

40 files changed:
gcc/c-family/ChangeLog
gcc/c-family/name-hint.h
gcc/c/ChangeLog
gcc/c/c-decl.c
gcc/c/c-parser.c
gcc/cp/ChangeLog
gcc/cp/cp-name-hint.h [new file with mode: 0644]
gcc/cp/cp-tree.h
gcc/cp/error.c
gcc/cp/lex.c
gcc/cp/name-lookup.c
gcc/cp/parser.c
gcc/testsuite/ChangeLog
gcc/testsuite/c-c++-common/spellcheck-reserved.c
gcc/testsuite/g++.dg/ext/builtin3.C
gcc/testsuite/g++.dg/lookup/error1.C
gcc/testsuite/g++.dg/lookup/pr77549.C
gcc/testsuite/g++.dg/lookup/pr80913.C
gcc/testsuite/g++.dg/lookup/suggestions1.C
gcc/testsuite/g++.dg/lookup/suggestions2.C [new file with mode: 0644]
gcc/testsuite/g++.dg/overload/koenig1.C
gcc/testsuite/g++.dg/spellcheck-identifiers-2.C
gcc/testsuite/g++.dg/spellcheck-identifiers.C
gcc/testsuite/g++.dg/spellcheck-ns.C [new file with mode: 0644]
gcc/testsuite/g++.dg/spellcheck-pr77829.C
gcc/testsuite/g++.dg/spellcheck-pr78656.C
gcc/testsuite/g++.dg/spellcheck-pr79298.C
gcc/testsuite/g++.dg/spellcheck-pr80177.C
gcc/testsuite/g++.dg/spellcheck-single-vs-multiple.C [new file with mode: 0644]
gcc/testsuite/g++.dg/spellcheck-typenames.C
gcc/testsuite/g++.dg/template/static10.C
gcc/testsuite/g++.old-deja/g++.mike/ns5.C
gcc/testsuite/g++.old-deja/g++.mike/ns7.C
gcc/testsuite/g++.old-deja/g++.ns/koenig5.C
gcc/testsuite/g++.old-deja/g++.other/lineno5.C
include/ChangeLog
include/unique-ptr.h
libstdc++-v3/ChangeLog
libstdc++-v3/testsuite/17_intro/using_namespace_std_exp_neg.cc
libstdc++-v3/testsuite/17_intro/using_namespace_std_tr1_neg.cc

index 6199db74f8a8094f0305eab57ef133939784a348..64e098816ec4f364c6fb962a7ba2cb25e84bab70 100644 (file)
@@ -1,3 +1,7 @@
+2018-10-29  David Malcolm  <dmalcolm@redhat.com>
+
+       * name-hint.h (name_hint::take_deferred): New member function.
+
 2018-10-29  David Malcolm  <dmalcolm@redhat.com>
 
        PR c++/56856
index ef0e4a363740eb0651e64236e496fe35b71172c8..ddc35259c721936aa5d44d3c5bb254c5595bf968 100644 (file)
@@ -99,7 +99,14 @@ public:
   }
 
   const char *suggestion () const { return m_suggestion; }
-  operator bool () const { return m_suggestion != NULL; }
+
+  /* Does this name_hint have a suggestion or a deferred diagnostic?  */
+  operator bool () const { return (m_suggestion != NULL
+                                  || m_deferred != NULL); }
+
+  /* Take ownership of this name_hint's deferred_diagnostic, for use
+     in chaining up deferred diagnostics.  */
+  gnu::unique_ptr<deferred_diagnostic> take_deferred () { return move (m_deferred); }
 
   /* Call this on a name_hint if the corresponding warning was not emitted,
      in which case we should also not emit the deferred_diagnostic.  */
index 2c07f2f612599e1598b5d293c6cdfb40a52c79a0..708ef5d7da2a361398e04b1f31088d79ad82b7fb 100644 (file)
@@ -1,3 +1,11 @@
+2018-10-29  David Malcolm  <dmalcolm@redhat.com>
+
+       * c-decl.c (implicit_decl_warning): Update "is there a suggestion"
+       logic for change to name_hint::operator bool.
+       (undeclared_variable): Likewise.
+       * c-parser.c (c_parser_declaration_or_fndef): Likewise.
+       (c_parser_parameter_declaration): Likewise.
+
 2018-10-17  Joseph Myers  <joseph@codesourcery.com>
 
        * c-errors.c (pedwarn_c11): New function.
index 160ce357cb1628d7ac07c836dc53f67e79045b97..cbbf7eba51fd8c5c547a0fe9e91c53a00103b6ee 100644 (file)
@@ -3150,27 +3150,27 @@ implicit_decl_warning (location_t loc, tree id, tree olddecl)
 
   if (flag_isoc99)
     {
-      if (hint)
+      if (const char *suggestion = hint.suggestion ())
        {
          gcc_rich_location richloc (loc);
-         richloc.add_fixit_replace (hint.suggestion ());
+         richloc.add_fixit_replace (suggestion);
          warned = pedwarn (&richloc, OPT_Wimplicit_function_declaration,
                            "implicit declaration of function %qE;"
                            " did you mean %qs?",
-                           id, hint.suggestion ());
+                           id, suggestion);
        }
       else
        warned = pedwarn (loc, OPT_Wimplicit_function_declaration,
                          "implicit declaration of function %qE", id);
     }
-  else if (hint)
+  else if (const char *suggestion = hint.suggestion ())
     {
       gcc_rich_location richloc (loc);
-      richloc.add_fixit_replace (hint.suggestion ());
+      richloc.add_fixit_replace (suggestion);
       warned = warning_at
        (&richloc, OPT_Wimplicit_function_declaration,
         G_("implicit declaration of function %qE; did you mean %qs?"),
-        id, hint.suggestion ());
+        id, suggestion);
     }
   else
     warned = warning_at (loc, OPT_Wimplicit_function_declaration,
@@ -3513,14 +3513,14 @@ undeclared_variable (location_t loc, tree id)
   if (current_function_decl == NULL_TREE)
     {
       name_hint guessed_id = lookup_name_fuzzy (id, FUZZY_LOOKUP_NAME, loc);
-      if (guessed_id)
+      if (const char *suggestion = guessed_id.suggestion ())
        {
          gcc_rich_location richloc (loc);
-         richloc.add_fixit_replace (guessed_id.suggestion ());
+         richloc.add_fixit_replace (suggestion);
          error_at (&richloc,
                    "%qE undeclared here (not in a function);"
                    " did you mean %qs?",
-                   id, guessed_id.suggestion ());
+                   id, suggestion);
        }
       else
        error_at (loc, "%qE undeclared here (not in a function)", id);
@@ -3531,14 +3531,14 @@ undeclared_variable (location_t loc, tree id)
       if (!objc_diagnose_private_ivar (id))
        {
          name_hint guessed_id = lookup_name_fuzzy (id, FUZZY_LOOKUP_NAME, loc);
-         if (guessed_id)
+         if (const char *suggestion = guessed_id.suggestion ())
            {
              gcc_rich_location richloc (loc);
-             richloc.add_fixit_replace (guessed_id.suggestion ());
+             richloc.add_fixit_replace (suggestion);
              error_at (&richloc,
                        "%qE undeclared (first use in this function);"
                        " did you mean %qs?",
-                       id, guessed_id.suggestion ());
+                       id, suggestion);
            }
          else
            error_at (loc, "%qE undeclared (first use in this function)", id);
index ee66ce89b5dea3f56956c74a1d223a3e6d271483..b36fca9a330acdfc7bb1d9ab5f32c7974c5383bf 100644 (file)
@@ -1822,12 +1822,12 @@ c_parser_declaration_or_fndef (c_parser *parser, bool fndef_ok,
          auto_diagnostic_group d;
          name_hint hint = lookup_name_fuzzy (name, FUZZY_LOOKUP_TYPENAME,
                                              here);
-         if (hint)
+         if (const char *suggestion = hint.suggestion ())
            {
-             richloc.add_fixit_replace (hint.suggestion ());
+             richloc.add_fixit_replace (suggestion);
              error_at (&richloc,
                        "unknown type name %qE; did you mean %qs?",
-                       name, hint.suggestion ());
+                       name, suggestion);
            }
          else
            error_at (here, "unknown type name %qE", name);
@@ -4074,13 +4074,13 @@ c_parser_parameter_declaration (c_parser *parser, tree attrs)
          name_hint hint = lookup_name_fuzzy (token->value,
                                              FUZZY_LOOKUP_TYPENAME,
                                              token->location);
-         if (hint)
+         if (const char *suggestion = hint.suggestion ())
            {
              gcc_rich_location richloc (token->location);
-             richloc.add_fixit_replace (hint.suggestion ());
+             richloc.add_fixit_replace (suggestion);
              error_at (&richloc,
                        "unknown type name %qE; did you mean %qs?",
-                       token->value, hint.suggestion ());
+                       token->value, suggestion);
            }
          else
            error_at (token->location, "unknown type name %qE", token->value);
index 78d2b5bab501922de79583b1380144ab8f920149..e1167761ffc8aff9fd032602acd95ea701718a11 100644 (file)
@@ -1,3 +1,71 @@
+2018-10-29  David Malcolm  <dmalcolm@redhat.com>
+
+       * cp-name-hint.h: New file.
+       * cp-tree.h (expr_to_string): New decl.
+       (suggest_alternatives_for): Move to cp-name-hint.h, changing
+       return type from bool to name_hint.
+       (suggest_alternative_in_explicit_scope): Likewise.
+       * error.c: Define INCLUDE_UNIQUE_PTR.  Include "cp-name-hint.h".
+       (expr_to_string): Make non-static.
+       (qualified_name_lookup_error): For the non-"::" case, take
+       responsibity for issuing any suggestion from
+       suggest_alternative_in_explicit_scope, as it changes from
+       returning a bool to returning a name_hint.  Replace fallback call
+       to suggest_alternatives_for to a call to
+       suggest_alternatives_in_other_namespaces, capturing the fact that
+       we don't have enough location information to issue a fix-it hint
+       for this case.  Update the error to support emitting a fix-it hint
+       where appropriate.  For the "::" case, take responsibility for
+       issuing any suggestion from suggest_alternatives_for, supporting
+       emitting a fix-it hint.
+       * lex.c: Define INCLUDE_UNIQUE_PTR.  Include "gcc-rich-location.h"
+       and "cp-name-hint.h".
+       (unqualified_name_lookup_error): Take responsibility for issuing
+       any suggestion from suggest_alternatives_for, supporting emitting
+       a fix-it hint.
+       * name-lookup.c (class namespace_limit_reached): New subclass of
+       deferred_diagnostic.
+       (class show_candidate_location): Likewise.
+       (class suggest_alternatives): Likewise.
+       (class namespace_hints): New class.
+       (suggest_alternatives_for): Convert return type from bool to
+       name_hint, replacing all direct diagnostic emission by setting
+       suggestions on the return value, or creating deferred diagnostics.
+       Specifically, split out initial traversal of namespaces into
+       namespace_hints' ctor, and maybe_decorate_with_limit, and move the
+       rest of the implementation to
+       namespace_hints::convert_candidates_to_name_hint and
+       suggest_alternatives_for_1.
+       (namespace_hints::namespace_hints): New ctor, adapted from
+       suggest_alternatives_for's initial namespace traversal, storing
+       location and name, and converting locals "candidates", "limited"
+       and "limit" into members.
+       (namespace_hints::convert_candidates_to_name_hint): New member
+       function.
+       (namespace_hints::maybe_decorate_with_limit): New member function.
+       (suggest_alternatives_for_1): New function, based on second half
+       of old implementation of suggest_alternatives_for, converting from
+       immediate emission of suggestions to using name_hint.
+       (suggest_alternatives_in_other_namespaces): New function.
+       (maybe_suggest_missing_std_header): Convert from immediate
+       emission of suggestions to using name_hint, moving emission
+       implementation to...
+       (class missing_std_header): New subclass of deferred_diagnostic.
+       (maybe_suggest_missing_header): Convert return type from bool to
+       name_hint.
+       (suggest_alternative_in_explicit_scope): Convert from immediate
+       emission of suggestions to using name_hint.
+       * parser.c: Replace include of "c-family/name-hint.h" with
+       "cp-name-hint.h".
+       (cp_parser_diagnose_invalid_type_name): Update
+       "is there a suggestion" logic for change to
+       name_hint::operator bool.  Take responsibility for emitting
+       fix-it hints from suggest_alternative_in_explicit_scope.
+       (cp_parser_namespace_name): Take responsibility for emitting
+       fix-it hints from suggest_alternative_in_explicit_scope.  Don't
+       emit the "expected namespace-name" error if we've already emitted
+       an "is not a namespace-name" error.
+
 2018-10-29  David Malcolm  <dmalcolm@redhat.com>
 
        PR c++/56856
diff --git a/gcc/cp/cp-name-hint.h b/gcc/cp/cp-name-hint.h
new file mode 100644 (file)
index 0000000..5d1cdc3
--- /dev/null
@@ -0,0 +1,37 @@
+/* Declarations for working with name_hint instances in the C++ frontend.
+   Copyright (C) 2018 Free Software Foundation, Inc.
+   Contributed by David Malcolm <dmalcolm@redhat.com>
+
+This file is part of GCC.
+
+GCC is free software; you can redistribute it and/or modify
+it under the terms of the GNU General Public License as published by
+the Free Software Foundation; either version 3, or (at your option)
+any later version.
+
+GCC is distributed in the hope that it will be useful,
+but WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+GNU General Public License for more details.
+
+You should have received a copy of the GNU General Public License
+along with GCC; see the file COPYING3.  If not see
+<http://www.gnu.org/licenses/>.  */
+
+#ifndef GCC_CP_NAME_HINT_H
+#define GCC_CP_NAME_HINT_H
+
+/* class name_hint is declared in c-family/name-hint.h, but due
+   to issues described in that header, we have to jump through some
+   #define hoops to be able to include it.
+
+   This header (cp/cp-name-hint.h) exists to limit the C++ frontend's
+   exposure to the issue.  */
+
+#include "c-family/name-hint.h"
+
+extern name_hint suggest_alternatives_for (location_t, tree, bool);
+extern name_hint suggest_alternatives_in_other_namespaces (location_t, tree);
+extern name_hint suggest_alternative_in_explicit_scope (location_t, tree, tree);
+
+#endif /* GCC_CP_NAME_HINT_H */
index 26ded3a921438d80dcfc15d65a8d03f3502b891e..8454cb4e178528f377692554a82e820ff8a39d49 100644 (file)
@@ -6445,6 +6445,7 @@ extern const char *decl_as_string         (tree, int);
 extern const char *decl_as_string_translate    (tree, int);
 extern const char *decl_as_dwarf_string                (tree, int);
 extern const char *expr_as_string              (tree, int);
+extern const char *expr_to_string              (tree);
 extern const char *lang_decl_name              (tree, int, bool);
 extern const char *lang_decl_dwarf_name                (tree, int, bool);
 extern const char *language_to_string          (enum languages);
@@ -7478,8 +7479,6 @@ extern tree cp_fully_fold                 (tree);
 extern void clear_fold_cache                   (void);
 
 /* in name-lookup.c */
-extern void suggest_alternatives_for            (location_t, tree, bool);
-extern bool suggest_alternative_in_explicit_scope (location_t, tree, tree);
 extern tree strip_using_decl                    (tree);
 
 /* Tell the binding oracle what kind of binding we are looking for.  */
index 0b14dccba3a125581eb79bc47d4d17e36bad5da3..fa115aa211ce5363cf4aa1dd152d0a130ed829af 100644 (file)
@@ -18,6 +18,8 @@ along with GCC; see the file COPYING3.  If not see
 <http://www.gnu.org/licenses/>.  */
 
 #include "config.h"
+/* For use with name_hint.  */
+#define INCLUDE_UNIQUE_PTR
 #include "system.h"
 #include "coretypes.h"
 #include "cp-tree.h"
@@ -32,6 +34,7 @@ along with GCC; see the file COPYING3.  If not see
 #include "ubsan.h"
 #include "internal-fn.h"
 #include "gcc-rich-location.h"
+#include "cp-name-hint.h"
 
 #define pp_separate_with_comma(PP) pp_cxx_separate_with (PP, ',')
 #define pp_separate_with_semicolon(PP) pp_cxx_separate_with (PP, ';')
@@ -54,7 +57,6 @@ static const char *args_to_string (tree, int);
 static const char *code_to_string (enum tree_code);
 static const char *cv_to_string (tree, int);
 static const char *decl_to_string (tree, int);
-static const char *expr_to_string (tree);
 static const char *fndecl_to_string (tree, int);
 static const char *op_to_string        (bool, enum tree_code);
 static const char *parm_to_string (int);
@@ -3059,7 +3061,7 @@ decl_to_string (tree decl, int verbose)
   return pp_ggc_formatted_text (cxx_pp);
 }
 
-static const char *
+const char *
 expr_to_string (tree decl)
 {
   reinit_cxx_pp ();
@@ -4261,15 +4263,42 @@ qualified_name_lookup_error (tree scope, tree name,
   else if (scope != global_namespace)
     {
       auto_diagnostic_group d;
-      error_at (location, "%qD is not a member of %qD", name, scope);
-      if (!suggest_alternative_in_explicit_scope (location, name, scope))
-       suggest_alternatives_for (location, name, false);
+      bool emit_fixit = true;
+      name_hint hint
+       = suggest_alternative_in_explicit_scope (location, name, scope);
+      if (!hint)
+       {
+         hint = suggest_alternatives_in_other_namespaces (location, name);
+         /* "location" is just the location of the name, not of the explicit
+            scope, and it's not easy to get at the latter, so we can't issue
+            fix-it hints for the suggestion.  */
+         emit_fixit = false;
+       }
+      if (const char *suggestion = hint.suggestion ())
+       {
+         gcc_rich_location richloc (location);
+         if (emit_fixit)
+           richloc.add_fixit_replace (suggestion);
+         error_at (&richloc, "%qD is not a member of %qD; did you mean %qs?",
+                   name, scope, suggestion);
+       }
+      else
+       error_at (location, "%qD is not a member of %qD", name, scope);
     }
   else
     {
       auto_diagnostic_group d;
-      error_at (location, "%<::%D%> has not been declared", name);
-      suggest_alternatives_for (location, name, true);
+      name_hint hint = suggest_alternatives_for (location, name, true);
+      if (const char *suggestion = hint.suggestion ())
+       {
+         gcc_rich_location richloc (location);
+         richloc.add_fixit_replace (suggestion);
+         error_at (&richloc,
+                   "%<::%D%> has not been declared; did you mean %qs?",
+                   name, suggestion);
+       }
+      else
+       error_at (location, "%<::%D%> has not been declared", name);
     }
 }
 
index 47b99c3c46927571393f44d1a5c66df5790d06c8..410dfd1bc5b4980bc0a6815d867926d9aad592e4 100644 (file)
@@ -22,12 +22,16 @@ along with GCC; see the file COPYING3.  If not see
 /* This file is the lexical analyzer for GNU C++.  */
 
 #include "config.h"
+/* For use with name_hint.  */
+#define INCLUDE_UNIQUE_PTR
 #include "system.h"
 #include "coretypes.h"
 #include "cp-tree.h"
 #include "stringpool.h"
 #include "c-family/c-pragma.h"
 #include "c-family/c-objc.h"
+#include "gcc-rich-location.h"
+#include "cp-name-hint.h"
 
 static int interface_strcmp (const char *);
 static void init_cp_pragma (void);
@@ -500,8 +504,17 @@ unqualified_name_lookup_error (tree name, location_t loc)
       if (!objc_diagnose_private_ivar (name))
        {
          auto_diagnostic_group d;
-         error_at (loc, "%qD was not declared in this scope", name);
-         suggest_alternatives_for (loc, name, true);
+         name_hint hint = suggest_alternatives_for (loc, name, true);
+         if (const char *suggestion = hint.suggestion ())
+           {
+             gcc_rich_location richloc (loc);
+             richloc.add_fixit_replace (suggestion);
+             error_at (&richloc,
+                       "%qD was not declared in this scope; did you mean %qs?",
+                       name, suggestion);
+           }
+         else
+           error_at (loc, "%qD was not declared in this scope", name);
        }
       /* Prevent repeated error messages by creating a VAR_DECL with
         this NAME in the innermost block scope.  */
index 08632c382b7b758432270edbd91fbfcda024940d..5b026da59e0bf9f34eb146a3d3ffa15e974849cb 100644 (file)
@@ -41,7 +41,10 @@ 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);
+static name_hint maybe_suggest_missing_std_header (location_t location,
+                                                  tree name);
+static name_hint suggest_alternatives_for_1 (location_t location, tree name,
+                                            bool suggest_misspellings);
 
 /* Create an overload suitable for recording an artificial TYPE_DECL
    and another decl.  We use this machanism to implement the struct
@@ -5299,20 +5302,132 @@ has_using_namespace_std_directive_p ()
   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
-   SUGGEST_MISSPELLINGS is true, then also look for near-matches and
-   suggest the best near-match, if there is one.  */
+/* Subclass of deferred_diagnostic, for issuing a note when
+   --param cxx-max-namespaces-for-diagnostic-help is reached.
 
-void
-suggest_alternatives_for (location_t location, tree name,
-                         bool suggest_misspellings)
+   The note should be issued after the error, but before any other
+   deferred diagnostics.  This is handled by decorating a wrapped
+   deferred_diagnostic, and emitting a note before that wrapped note is
+   deleted.  */
+
+class namespace_limit_reached : public deferred_diagnostic
+{
+ public:
+  namespace_limit_reached (location_t loc, unsigned limit, tree name,
+                          gnu::unique_ptr<deferred_diagnostic> wrapped)
+  : deferred_diagnostic (loc),
+    m_limit (limit), m_name (name),
+    m_wrapped (move (wrapped))
+  {
+  }
+
+  ~namespace_limit_reached ()
+  {
+    /* Unconditionally warn that the search was truncated.  */
+    inform (get_location (),
+           "maximum limit of %d namespaces searched for %qE",
+           m_limit, m_name);
+    /* m_wrapped will be implicitly deleted after this, emitting any followup
+       diagnostic after the above note.  */
+  }
+
+ private:
+  unsigned m_limit;
+  tree m_name;
+  gnu::unique_ptr<deferred_diagnostic> m_wrapped;
+};
+
+/* Subclass of deferred_diagnostic, for use when issuing a single suggestion.
+   Emit a note showing the location of the declaration of the suggestion.  */
+
+class show_candidate_location : public deferred_diagnostic
+{
+ public:
+  show_candidate_location (location_t loc, tree candidate)
+  : deferred_diagnostic (loc),
+    m_candidate (candidate)
+  {
+  }
+
+  ~show_candidate_location ()
+  {
+    inform (location_of (m_candidate), "%qE declared here", m_candidate);
+  }
+
+ private:
+  tree m_candidate;
+};
+
+/* Subclass of deferred_diagnostic, for use when there are multiple candidates
+   to be suggested by suggest_alternatives_for.
+
+   Emit a series of notes showing the various suggestions.  */
+
+class suggest_alternatives : public deferred_diagnostic
 {
-  vec<tree> candidates = vNULL;
-  vec<tree> worklist = vNULL;
-  unsigned limit = PARAM_VALUE (CXX_MAX_NAMESPACES_FOR_DIAGNOSTIC_HELP);
-  bool limited = false;
+ public:
+  suggest_alternatives (location_t loc, vec<tree> candidates)
+  : deferred_diagnostic (loc),
+    m_candidates (candidates)
+  {
+  }
+
+  ~suggest_alternatives ()
+  {
+    if (m_candidates.length ())
+      {
+       inform_n (get_location (), m_candidates.length (),
+                 "suggested alternative:",
+                 "suggested alternatives:");
+       for (unsigned ix = 0; ix != m_candidates.length (); ix++)
+         {
+           tree val = m_candidates[ix];
+
+           inform (location_of (val), "  %qE", val);
+         }
+      }
+    m_candidates.release ();
+  }
+
+ private:
+  vec<tree> m_candidates;
+};
+
+/* A class for encapsulating the result of a search across
+   multiple namespaces for an unrecognized name seen at a
+   given source location.  */
+
+class namespace_hints
+{
+ public:
+  namespace_hints (location_t loc, tree name);
+
+  name_hint convert_candidates_to_name_hint ();
+  name_hint maybe_decorate_with_limit (name_hint);
+
+ private:
+  location_t m_loc;
+  tree m_name;
+  vec<tree> m_candidates;
+
+  /* Value of "--param cxx-max-namespaces-for-diagnostic-help".  */
+  unsigned m_limit;
+
+  /* Was the limit reached?  */
+  bool m_limited;
+};
+
+/* Constructor for namespace_hints.  Search namespaces, looking for a match
+   for unrecognized NAME seen at LOC.  */
+
+namespace_hints::namespace_hints (location_t loc, tree name)
+: m_loc(loc), m_name (name)
+{
+  auto_vec<tree> worklist;
+
+  m_candidates = vNULL;
+  m_limited = false;
+  m_limit = PARAM_VALUE (CXX_MAX_NAMESPACES_FOR_DIAGNOSTIC_HELP);
 
   /* Breadth-first search of namespaces.  Up to limit namespaces
      searched (limit zero == unlimited).  */
@@ -5323,14 +5438,14 @@ suggest_alternatives_for (location_t location, tree name,
       name_lookup lookup (name);
 
       if (lookup.search_qualified (ns, false))
-       candidates.safe_push (lookup.value);
+       m_candidates.safe_push (lookup.value);
 
-      if (!limited)
+      if (!m_limited)
        {
          /* Look for child namespaces.  We have to do this
             indirectly because they are chained in reverse order,
             which is confusing to the user.  */
-         vec<tree> children = vNULL;
+         auto_vec<tree> children;
 
          for (tree decl = NAMESPACE_LEVEL (ns)->names;
               decl; decl = TREE_CHAIN (decl))
@@ -5339,60 +5454,141 @@ suggest_alternatives_for (location_t location, tree name,
                && !DECL_NAMESPACE_INLINE_P (decl))
              children.safe_push (decl);
 
-         while (!limited && !children.is_empty ())
+         while (!m_limited && !children.is_empty ())
            {
-             if (worklist.length () == limit)
-               {
-                 /* Unconditionally warn that the search was truncated.  */
-                 inform (location,
-                         "maximum limit of %d namespaces searched for %qE",
-                         limit, name);
-                 limited = true;
-               }
+             if (worklist.length () == m_limit)
+               m_limited = true;
              else
                worklist.safe_push (children.pop ());
            }
-         children.release ();
        }
     }
-  worklist.release ();
+}
 
-  if (candidates.length ())
-    {
-      inform_n (location, candidates.length (),
-               "suggested alternative:",
-               "suggested alternatives:");
-      for (unsigned ix = 0; ix != candidates.length (); ix++)
-       {
-         tree val = candidates[ix];
+/* Drop ownership of m_candidates, using it to generate a name_hint at m_loc
+   for m_name, an IDENTIFIER_NODE for which name lookup failed.
 
-         inform (location_of (val), "  %qE", val);
-       }
-      candidates.release ();
-      return;
+   If m_candidates is non-empty, use it to generate a suggestion and/or
+   a deferred diagnostic that lists the possible candidate(s).
+*/
+
+name_hint
+namespace_hints::convert_candidates_to_name_hint ()
+{
+  /* How many candidates do we have?  */
+
+  /* If we have just one candidate, issue a name_hint with it as a suggestion
+     (so that consumers are able to suggest it within the error message and emit
+     it as a fix-it hint), and with a note showing the candidate's location.  */
+  if (m_candidates.length () == 1)
+    {
+      tree candidate = m_candidates[0];
+      /* Clean up CANDIDATES.  */
+      m_candidates.release ();
+      return name_hint (expr_to_string (candidate),
+                       new show_candidate_location (m_loc, candidate));
     }
+  else if (m_candidates.length () > 1)
+    /* If we have more than one candidate, issue a name_hint without a single
+       "suggestion", but with a deferred diagnostic that lists the
+       various candidates.  This takes ownership of m_candidates.  */
+    return name_hint (NULL, new suggest_alternatives (m_loc, m_candidates));
 
+  /* Otherwise, m_candidates ought to be empty, so no cleanup is necessary.  */
+  gcc_assert (m_candidates.length () == 0);
+  gcc_assert (m_candidates == vNULL);
+
+  return name_hint ();
+}
+
+/* If --param cxx-max-namespaces-for-diagnostic-help was reached,
+   then we want to emit a note about after the error, but before
+   any other deferred diagnostics.
+
+   Handle this by figuring out what hint is needed, then optionally
+   decorating HINT with a namespace_limit_reached wrapper.  */
+
+name_hint
+namespace_hints::maybe_decorate_with_limit (name_hint hint)
+{
+  if (m_limited)
+    return name_hint (hint.suggestion (),
+                     new namespace_limit_reached (m_loc, m_limit,
+                                                  m_name,
+                                                  hint.take_deferred ()));
+  else
+    return hint;
+}
+
+/* Generate a name_hint at LOCATION for NAME, an IDENTIFIER_NODE for which
+   name lookup failed.
+
+   Search through all available namespaces and generate a suggestion and/or
+   a deferred diagnostic that lists possible candidate(s).
+
+   If no exact matches are found, and SUGGEST_MISSPELLINGS is true, then also
+   look for near-matches and suggest the best near-match, if there is one.
+
+   If nothing is found, then an empty name_hint is returned.  */
+
+name_hint
+suggest_alternatives_for (location_t location, tree name,
+                         bool suggest_misspellings)
+{
+  /* First, search for exact matches in other namespaces.  */
+  namespace_hints ns_hints (location, name);
+  name_hint result = ns_hints.convert_candidates_to_name_hint ();
+
+  /* Otherwise, try other approaches.  */
+  if (!result)
+    result = suggest_alternatives_for_1 (location, name, suggest_misspellings);
+
+  return ns_hints.maybe_decorate_with_limit (gnu::move (result));
+}
+
+/* The second half of suggest_alternatives_for, for when no exact matches
+   were found in other namespaces.  */
+
+static name_hint
+suggest_alternatives_for_1 (location_t location, tree name,
+                           bool suggest_misspellings)
+{
   /* 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;
+    {
+      name_hint hint = maybe_suggest_missing_std_header (location, name);
+      if (hint)
+       return hint;
+    }
 
   /* 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);
+    return name_hint ();
 
-      richloc.add_fixit_replace (hint.suggestion ());
-      inform (&richloc, "suggested alternative: %qs", hint.suggestion ());
-    }
+  return lookup_name_fuzzy (name, FUZZY_LOOKUP_NAME, location);
+}
+
+/* Generate a name_hint at LOCATION for NAME, an IDENTIFIER_NODE for which
+   name lookup failed.
+
+   Search through all available namespaces and generate a suggestion and/or
+   a deferred diagnostic that lists possible candidate(s).
+
+   This is similiar to suggest_alternatives_for, but doesn't fallback to
+   the other approaches used by that function.  */
+
+name_hint
+suggest_alternatives_in_other_namespaces (location_t location, tree name)
+{
+  namespace_hints ns_hints (location, name);
+
+  name_hint result = ns_hints.convert_candidates_to_name_hint ();
+
+  return ns_hints.maybe_decorate_with_limit (gnu::move (result));
 }
 
 /* A well-known name within the C++ standard library, returned by
@@ -5603,11 +5799,51 @@ get_cxx_dialect_name (enum cxx_dialect dialect)
     }
 }
 
-/* Suggest pertinent header files for NAME at LOCATION, for common
-   names within the "std" namespace.
-   Return true iff a suggestion was offered.  */
+/* Subclass of deferred_diagnostic for use for names in the "std" namespace
+   that weren't recognized, but for which we know which header it ought to be
+   in.
 
-static bool
+   Emit a note either suggesting the header to be included, or noting that
+   the current dialect is too early for the given name.  */
+
+class missing_std_header : public deferred_diagnostic
+{
+ public:
+  missing_std_header (location_t loc,
+                     const char *name_str,
+                     const std_name_hint *header_hint)
+  : deferred_diagnostic (loc),
+    m_name_str (name_str),
+    m_header_hint (header_hint)
+  {}
+  ~missing_std_header ()
+  {
+    gcc_rich_location richloc (get_location ());
+    if (cxx_dialect >= m_header_hint->min_dialect)
+      {
+       const char *header = m_header_hint->header;
+       maybe_add_include_fixit (&richloc, header, true);
+       inform (&richloc,
+               "%<std::%s%> is defined in header %qs;"
+               " did you forget to %<#include %s%>?",
+               m_name_str, header, header);
+      }
+    else
+      inform (&richloc,
+             "%<std::%s%> is only available from %s onwards",
+             m_name_str, get_cxx_dialect_name (m_header_hint->min_dialect));
+  }
+
+private:
+  const char *m_name_str;
+  const std_name_hint *m_header_hint;
+};
+
+/* Attempt to generate a name_hint that suggests pertinent header files
+   for NAME at LOCATION, for common names within the "std" namespace,
+   or an empty name_hint if this isn't applicable.  */
+
+static name_hint
 maybe_suggest_missing_std_header (location_t location, tree name)
 {
   gcc_assert (TREE_CODE (name) == IDENTIFIER_NODE);
@@ -5615,62 +5851,49 @@ maybe_suggest_missing_std_header (location_t location, tree name)
   const char *name_str = IDENTIFIER_POINTER (name);
   const std_name_hint *header_hint = get_std_name_hint (name_str);
   if (!header_hint)
-    return false;
+    return name_hint ();
 
-  gcc_rich_location richloc (location);
-  if (cxx_dialect >= header_hint->min_dialect)
-    {
-      const char *header = header_hint->header;
-      maybe_add_include_fixit (&richloc, header, true);
-      inform (&richloc,
-             "%<std::%s%> is defined in header %qs;"
-             " did you forget to %<#include %s%>?",
-             name_str, header, header);
-    }
-  else
-    {
-      inform (&richloc,
-             "%<std::%s%> is only available from %s onwards",
-             name_str, get_cxx_dialect_name (header_hint->min_dialect));
-    }
-  return true;
+  return name_hint (NULL, new missing_std_header (location, name_str,
+                                                 header_hint));
 }
 
-/* If SCOPE is the "std" namespace, then suggest pertinent header
-   files for NAME at LOCATION.
-   Return true iff a suggestion was offered.  */
+/* Attempt to generate a name_hint that suggests a missing header file
+   for NAME within SCOPE at LOCATION, or an empty name_hint if this isn't
+   applicable.  */
 
-static bool
+static name_hint
 maybe_suggest_missing_header (location_t location, tree name, tree scope)
 {
   if (scope == NULL_TREE)
-    return false;
+    return name_hint ();
   if (TREE_CODE (scope) != NAMESPACE_DECL)
-    return false;
+    return name_hint ();
   /* We only offer suggestions for the "std" namespace.  */
   if (scope != std_node)
-    return false;
+    return name_hint ();
   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.
-   Return true iff a suggestion was provided.  */
+/* Generate a name_hint at LOCATION for NAME, an IDENTIFIER_NODE for which name
+   lookup failed within the explicitly provided SCOPE.
 
-bool
+   Suggest the the best meaningful candidates (if any), otherwise
+   an empty name_hint is returned.  */
+
+name_hint
 suggest_alternative_in_explicit_scope (location_t location, tree name,
                                       tree scope)
 {
   /* Something went very wrong; don't suggest anything.  */
   if (name == error_mark_node)
-    return false;
+    return name_hint ();
 
   /* Resolve any namespace aliases.  */
   scope = ORIGINAL_NAMESPACE (scope);
 
-  if (maybe_suggest_missing_header (location, name, scope))
-    return true;
+  name_hint hint = maybe_suggest_missing_header (location, name, scope);
+  if (hint)
+    return hint;
 
   cp_binding_level *level = NAMESPACE_LEVEL (scope);
 
@@ -5680,15 +5903,9 @@ suggest_alternative_in_explicit_scope (location_t location, tree name,
   /* See if we have a good suggesion for the user.  */
   const char *fuzzy_name = bm.get_best_meaningful_candidate ();
   if (fuzzy_name)
-    {
-      gcc_rich_location richloc (location);
-      richloc.add_fixit_replace (fuzzy_name);
-      inform (&richloc, "suggested alternative: %qs",
-             fuzzy_name);
-      return true;
-    }
+    return name_hint (fuzzy_name, NULL);
 
-  return false;
+  return name_hint ();
 }
 
 /* Look up NAME (an IDENTIFIER_NODE) in SCOPE (either a NAMESPACE_DECL
index ebe326eb923d0f3613d1d87872daab08d44d52f8..c4bda7fc59e7cb236f1694b00c82b0849be5862b 100644 (file)
@@ -43,7 +43,7 @@ along with GCC; see the file COPYING3.  If not see
 #include "context.h"
 #include "gcc-rich-location.h"
 #include "tree-iterator.h"
-#include "c-family/name-hint.h"
+#include "cp-name-hint.h"
 
 \f
 /* The lexer.  */
@@ -3292,13 +3292,13 @@ cp_parser_diagnose_invalid_type_name (cp_parser *parser, tree id,
       name_hint hint;
       if (TREE_CODE (id) == IDENTIFIER_NODE)
        hint = lookup_name_fuzzy (id, FUZZY_LOOKUP_TYPENAME, location);
-      if (hint)
+      if (const char *suggestion = hint.suggestion ())
        {
          gcc_rich_location richloc (location);
-         richloc.add_fixit_replace (hint.suggestion ());
+         richloc.add_fixit_replace (suggestion);
          error_at (&richloc,
                    "%qE does not name a type; did you mean %qs?",
-                   id, hint.suggestion ());
+                   id, suggestion);
        }
       else
        error_at (location, "%qE does not name a type", id);
@@ -3364,23 +3364,53 @@ cp_parser_diagnose_invalid_type_name (cp_parser *parser, tree id,
       if (TREE_CODE (parser->scope) == NAMESPACE_DECL)
        {
          auto_diagnostic_group d;
+         name_hint hint;
+         if (decl == error_mark_node)
+           hint = suggest_alternative_in_explicit_scope (location, id,
+                                                         parser->scope);
+         const char *suggestion = hint.suggestion ();
+         gcc_rich_location richloc (location_of (id));
+         if (suggestion)
+           richloc.add_fixit_replace (suggestion);
          if (cp_lexer_next_token_is (parser->lexer, CPP_LESS))
-           error_at (location_of (id),
-                     "%qE in namespace %qE does not name a template type",
-                     id, parser->scope);
+           {
+             if (suggestion)
+               error_at (&richloc,
+                         "%qE in namespace %qE does not name a template"
+                         " type; did you mean %qs?",
+                         id, parser->scope, suggestion);
+             else
+               error_at (&richloc,
+                         "%qE in namespace %qE does not name a template type",
+                         id, parser->scope);
+           }
          else if (TREE_CODE (id) == TEMPLATE_ID_EXPR)
-           error_at (location_of (id),
-                     "%qE in namespace %qE does not name a template type",
-                     TREE_OPERAND (id, 0), parser->scope);
+           {
+             if (suggestion)
+               error_at (&richloc,
+                         "%qE in namespace %qE does not name a template"
+                         " type; did you mean %qs?",
+                         TREE_OPERAND (id, 0), parser->scope, suggestion);
+             else
+               error_at (&richloc,
+                         "%qE in namespace %qE does not name a template"
+                         " type",
+                         TREE_OPERAND (id, 0), parser->scope);
+           }
          else
-           error_at (location_of (id),
-                     "%qE in namespace %qE does not name a type",
-                     id, parser->scope);
+           {
+             if (suggestion)
+               error_at (&richloc,
+                         "%qE in namespace %qE does not name a type"
+                         "; did you mean %qs?",
+                         id, parser->scope, suggestion);
+             else
+               error_at (&richloc,
+                         "%qE in namespace %qE does not name a type",
+                         id, parser->scope);
+           }
          if (DECL_P (decl))
            inform (DECL_SOURCE_LOCATION (decl), "%qD declared here", decl);
-         else if (decl == error_mark_node)
-           suggest_alternative_in_explicit_scope (location, id,
-                                                  parser->scope);
        }
       else if (CLASS_TYPE_P (parser->scope)
               && constructor_name_p (id, parser->scope))
@@ -18620,13 +18650,26 @@ cp_parser_namespace_name (cp_parser* parser)
       if (!cp_parser_uncommitted_to_tentative_parse_p (parser))
        {
          auto_diagnostic_group d;
-         error_at (token->location, "%qD is not a namespace-name", identifier);
+         name_hint hint;
          if (namespace_decl == error_mark_node
              && parser->scope && TREE_CODE (parser->scope) == NAMESPACE_DECL)
-           suggest_alternative_in_explicit_scope (token->location, identifier,
-                                                  parser->scope);
+           hint = suggest_alternative_in_explicit_scope (token->location,
+                                                         identifier,
+                                                         parser->scope);
+         if (const char *suggestion = hint.suggestion ())
+           {
+             gcc_rich_location richloc (token->location);
+             richloc.add_fixit_replace (suggestion);
+             error_at (&richloc,
+                       "%qD is not a namespace-name; did you mean %qs?",
+                       identifier, suggestion);
+           }
+         else
+           error_at (token->location, "%qD is not a namespace-name",
+                     identifier);
        }
-      cp_parser_error (parser, "expected namespace-name");
+      else
+       cp_parser_error (parser, "expected namespace-name");
       namespace_decl = error_mark_node;
     }
 
index 85e910f2097c1c9ea21a56c677b25df874aba6b2..e6e59050bae0fd55edb61e46a97e787fc4b5bd8c 100644 (file)
@@ -1,3 +1,32 @@
+2018-10-29  David Malcolm  <dmalcolm@redhat.com>
+
+       * c-c++-common/spellcheck-reserved.c: Update expected output for
+       C++ for merger of "did you mean" suggestions into the error
+       message.
+       * g++.dg/ext/builtin3.C: Update expected output for merger of "did
+       you mean" suggestion into the error.
+       * g++.dg/lookup/error1.C: Likewise.
+       * g++.dg/lookup/pr77549.C: Likewise.
+       * g++.dg/lookup/pr80913.C: Likewise.
+       * g++.dg/lookup/suggestions1.C: Likewise.
+       * g++.dg/lookup/suggestions2.C: New test.
+       * g++.dg/overload/koenig1.C: Update expected output as above.
+       * g++.dg/spellcheck-identifiers-2.C: Likewise.
+       * g++.dg/spellcheck-identifiers.C: Likewise.
+       * g++.dg/spellcheck-ns.C: New test.
+       * g++.dg/spellcheck-pr77829.C: Update expected output as above.
+       * g++.dg/spellcheck-pr78656.C: Likewise.
+       * g++.dg/spellcheck-pr79298.C: Likewise, adding
+       -fdiagnostics-show-caret to options.
+       * g++.dg/spellcheck-pr80177.C: Likewise.
+       * g++.dg/spellcheck-single-vs-multiple.C: New test.
+       * g++.dg/spellcheck-typenames.C: Update expected output as above.
+       * g++.dg/template/static10.C: Likewise.
+       * g++.old-deja/g++.mike/ns5.C: Likewise.
+       * g++.old-deja/g++.mike/ns7.C: Likewise.
+       * g++.old-deja/g++.ns/koenig5.C: Likewise.
+       * g++.old-deja/g++.other/lineno5.C: Likewise.
+
 2018-10-29  Paolo Carlini  <paolo.carlini@oracle.com>
 
        * g++.dg/cpp0x/auto24.C: Test location too.
index 79b653241dcbba66cc5ab6369fe3603985f1b9a3..ed292f2bae0f3ef6a9f2cd092605199a1e880907 100644 (file)
@@ -30,8 +30,7 @@ void test (const char *buf, char ch)
 {
   __builtin_strtchr (buf, ch); /* { dg-line misspelled_reserved } */
   /* { dg-warning "did you mean '__builtin_strchr'" "" { target c } misspelled_reserved } */
-  /* { dg-error "not declared"  "" { target c++ } misspelled_reserved } */
-  /* { dg-message "'__builtin_strrchr'"  "" { target c++ } misspelled_reserved } */
+  /* { dg-error "'__builtin_strtchr' was not declared in this scope; did you mean '__builtin_strrchr'\\?" "" { target c++ } misspelled_reserved } */
 }
 
 /* Similarly for a name that begins with a single underscore.  */
@@ -40,8 +39,7 @@ void test_2 (const char *buf, char ch)
 {
   _builtin_strchr (buf, ch); /* { dg-line misspelled_one_underscore } */
   /* { dg-warning "did you mean '__builtin_strchr'" "" { target c } misspelled_one_underscore } */
-  /* { dg-error "not declared"  "" { target c++ } misspelled_one_underscore } */
-  /* { dg-message "'__builtin_strchr'"  "" { target c++ } misspelled_one_underscore } */
+  /* { dg-error "'_builtin_strchr' was not declared in this scope; did you mean '__builtin_strchr'\\?" "" { target c++ } misspelled_one_underscore } */
 }
 
 /* Verify that we can correct "__FILE_" to "__FILE__".  */
@@ -50,6 +48,5 @@ const char * test_3 (void)
 {
   return __FILE_; /* { dg-line misspelled__FILE_ } */
   /* { dg-error "did you mean '__FILE__'" "" { target c } misspelled__FILE_ } */
-  /* { dg-error "not declared"  "" { target c++ } misspelled__FILE_ } */
-  /* { dg-message "'__FILE__'"  "" { target c++ } misspelled__FILE_ } */
+  /* { dg-error "'__FILE_' was not declared in this scope; did you mean '__FILE__'\\?"  "" { target c++ } misspelled__FILE_ } */
 }
index 6becaa055e6480338f5d06aebffb48c5869f33dc..31d2ac6f313c0b75c09247e07e0d5b48ca491fa5 100644 (file)
@@ -9,6 +9,5 @@ extern "C" int printf(char*, ...); // { dg-message "std::printf" }
 }
 
 void foo() {
-  printf("abc");               // { dg-error "3:'printf' was not declared" }
-  // { dg-message "suggested alternative" "suggested alternative" { target *-*-* } .-1 }
+  printf("abc"); // { dg-error "3:'printf' was not declared in this scope; did you mean 'std::printf'\\?" }
 }
index d2741fb2812be0509cf6648ca414c21a6a15d634..1f267e7b2544938f8c3b8232091087a16d5d01e0 100644 (file)
@@ -3,8 +3,7 @@
 // { dg-do compile }
 
 namespace N { int i; }         // { dg-message "N::i" }
-void foo() { i; }   // { dg-error "not declared" }
-  // { dg-message "suggested alternative" "suggested alternative" { target *-*-* } .-1 }
+void foo() { i; }   // { dg-error "'i' was not declared in this scope; did you mean 'N::i'\\?" }
 
 using namespace N;
 void bar() { i; }
index b4b8d0ef25423f9677bc5ba9f87b7ed21e52c846..af7c630197a5b609b08191c4087088602ef1af64 100644 (file)
@@ -22,8 +22,8 @@ void
 f2 ()
 {
   using N::bar;
-  baz++;               // { dg-error "'baz' was not declared in this scope" }
-}                      // { dg-message "note: suggested alternative: 'bar'" "" { target *-*-* } .-1 }
+  baz++;               // { dg-error "'baz' was not declared in this scope; did you mean 'bar'\\?" }
+}
 
 int
 bar ()
@@ -44,8 +44,8 @@ void
 f3 ()
 {
   using M::bar;
-  baz ();              // { dg-error "'baz' was not declared in this scope" }
-}                      // { dg-message "note: suggested alternative: 'bar'" "" { target *-*-* } .-1 }
+  baz ();              // { dg-error "'baz' was not declared in this scope; did you mean 'bar'\\?" }
+}
 
 namespace O
 {
@@ -70,7 +70,6 @@ f4 ()
 {
   using O::foo;
   using P::bar;
-  fooo ();             // { dg-error "'fooo' was not declared in this scope" }
-                       // { dg-message "note: suggested alternative: 'foo'" "" { target *-*-* } .-1 }
-  baz ();              // { dg-error "'baz' was not declared in this scope" }
-}                      // { dg-message "note: suggested alternative: 'bar'" "" { target *-*-* } .-1 }
+  fooo ();             // { dg-error "'fooo' was not declared in this scope; did you mean 'foo'\\?" }
+  baz ();              // { dg-error "'baz' was not declared in this scope; did you mean 'bar'\\?" }
+}
index a7866bcc8a35004a03591888e26f5483517d9fa2..028e61a3f12cc335f9c079fb25567f56aaafea59 100644 (file)
@@ -6,6 +6,5 @@ struct meminfo {};
 
 void frob ()
 {
-  meminf (); // { dg-error "not declared" }
-  // { dg-message "suggested alternative" "" { target *-*-* } .-1 }
+  meminf (); // { dg-error "'meminf' was not declared in this scope; did you mean 'meminfo'\\?" }
 }
index da98d11cbc9deefdcfb7c48b34bce75a2b50df4a..47126a363e3f031e506fa23a08816a94d87c29e0 100644 (file)
@@ -1,8 +1,6 @@
 // { dg-do compile }
 
-namespace N { namespace M { int foo; } } // { dg-message "N::M::foo" }
-int f (void) { return N::foo; }                 // { dg-error "not a member" }
-// { dg-message "suggested alternative" "missing namespace" { target *-*-* } .-1 }
+namespace N { namespace M { int foo; } } // { dg-message "'N::M::foo' declared here" }
+int f (void) { return N::foo; }                 // { dg-error "'foo' is not a member of 'N'; did you mean 'N::M::foo'\\?" }
 
-int g (void) { return ::foo; } // { dg-error "not been declared" }
-// { dg-message "suggested alternative" "omitted namespace" { target *-*-* } .-1 }
+int g (void) { return ::foo; } // { dg-error "'::foo' has not been declared; did you mean 'N::M::foo'\\?" }
diff --git a/gcc/testsuite/g++.dg/lookup/suggestions2.C b/gcc/testsuite/g++.dg/lookup/suggestions2.C
new file mode 100644 (file)
index 0000000..900439f
--- /dev/null
@@ -0,0 +1,128 @@
+/* Suggestions involving namespaces.
+
+   The long variable names in this test case are close enough that we offer
+   spellchecking suggestions for them in the given namespace, with fix-it
+   hints.
+
+   The short variable names don't get spellchecking suggestions; instead
+   we offer suggestions about other namespaces.  However, as we don't
+   reliably have location information about the namespace part of the name,
+   we shouldn't offer fix-it hints for such cases.  */
+
+// { dg-do compile }
+// { dg-options "-fdiagnostics-show-caret" }
+
+namespace outer_ns {
+  int var_in_outer_ns; // { dg-line decl_of_var_in_outer_ns }
+  int o; // { dg-line decl_of_o }
+
+  namespace inner_ns_a {
+    int var_in_inner_ns_a;
+    int a; // { dg-line decl_of_a }
+  }
+  namespace inner_ns_b {
+    int var_in_inner_ns_b;
+    int b; // { dg-line decl_of_b }
+  }
+}
+
+/* This one should get spell-corrected within the same namespace,
+   with a fix-it hint.  */
+
+int test_1_long (void) {
+  return outer_ns::var_in_inner_ns_a; // { dg-error "did you mean 'var_in_outer_ns'" }
+  /* { dg-begin-multiline-output "" }
+   return outer_ns::var_in_inner_ns_a;
+                    ^~~~~~~~~~~~~~~~~
+                    var_in_outer_ns
+     { dg-end-multiline-output "" } */
+}
+
+/* This one should get a namespace suggestion (child namespace),
+   with no fix-it hint.  */
+
+int test_1_short (void) {
+  return outer_ns::a; // { dg-error "did you mean 'outer_ns::inner_ns_a::a'" }
+  /* { dg-begin-multiline-output "" }
+   return outer_ns::a;
+                    ^
+     { dg-end-multiline-output "" } */
+  // { dg-message "declared here" "" { target *-*-*} decl_of_a }
+  /* { dg-begin-multiline-output "" }
+     int a;
+         ^
+     { dg-end-multiline-output "" } */
+}
+
+/* This one should get spell-corrected within the same namespace,
+   with a fix-it hint.  */
+
+int test_2_long (void) {
+  return outer_ns::inner_ns_a::var_in_outer_ns; // { dg-error "did you mean 'var_in_inner_ns_a'" }
+  /* { dg-begin-multiline-output "" }
+   return outer_ns::inner_ns_a::var_in_outer_ns;
+                                ^~~~~~~~~~~~~~~
+                                var_in_inner_ns_a
+     { dg-end-multiline-output "" } */
+}
+
+/* This one should get a namespace suggestion (parent namespace),
+   with no fix-it hint.  */
+
+int test_2_short (void) {
+  return outer_ns::inner_ns_a::o; // { dg-error "did you mean 'outer_ns::o'" }
+  /* { dg-begin-multiline-output "" }
+   return outer_ns::inner_ns_a::o;
+                                ^
+     { dg-end-multiline-output "" } */
+  // { dg-message "declared here" "" { target *-*-*} decl_of_o }
+  /* { dg-begin-multiline-output "" }
+   int o;
+       ^
+     { dg-end-multiline-output "" } */
+}
+
+/* This one should get spell-corrected within the same namespace,
+   with a fix-it hint.  */
+
+int test_3_long (void) {
+  return outer_ns::inner_ns_a::var_in_inner_ns_b; // { dg-error "did you mean 'var_in_inner_ns_a'" }
+  /* { dg-begin-multiline-output "" }
+   return outer_ns::inner_ns_a::var_in_inner_ns_b;
+                                ^~~~~~~~~~~~~~~~~
+                                var_in_inner_ns_a
+     { dg-end-multiline-output "" } */
+}
+
+/* This one should get a namespace suggestion (sibling namespace),
+   with no fix-it hint.  */
+
+int test_3_short (void) {
+  return outer_ns::inner_ns_a::b; // { dg-error "did you mean 'outer_ns::inner_ns_b::b'" }
+  /* { dg-begin-multiline-output "" }
+   return outer_ns::inner_ns_a::b;
+                                ^
+     { dg-end-multiline-output "" } */
+  // { dg-message "declared here" "" { target *-*-*} decl_of_b }
+  /* { dg-begin-multiline-output "" }
+     int b;
+         ^
+     { dg-end-multiline-output "" } */
+}
+
+/* This one should get a namespace suggestion, from the global ns to a child ns.
+   It should get a fix-it hint.  */
+
+int test_4_long (void) {
+  return ::var_in_outer_ns; // { dg-error "did you mean 'outer_ns::var_in_outer_ns'" }
+  /* { dg-begin-multiline-output "" }
+   return ::var_in_outer_ns;
+            ^~~~~~~~~~~~~~~
+            outer_ns::var_in_outer_ns
+     { dg-end-multiline-output "" } */
+  // { dg-message "declared here" "" { target *-*-*} decl_of_var_in_outer_ns }
+  /* { dg-begin-multiline-output "" }
+   int var_in_outer_ns;
+       ^~~~~~~~~~~~~~~
+     { dg-end-multiline-output "" } */
+}
index 3c1c293560b52fc5aadbdf4cf0a0b5cc46f1f5d9..550806124229cc805f5ab21420f1926ae077ea94 100644 (file)
@@ -13,7 +13,6 @@ void g ()
 {
   B *bp;
   N::A *ap;
-  f (bp);                      // { dg-error "3:'f' was not declared" }
-  // { dg-message "suggested alternative" "suggested alternative" { target *-*-* } .-1 }
+  f (bp);                      // { dg-error "3:'f' was not declared in this scope; did you mean 'N::f'" }
   f (ap);
 }
index 59a8ec55c61e6c9dd02c72dcdea23f85ad06c3c9..67ae52bdee4282e92b6de1879294e02b56843235 100644 (file)
@@ -9,12 +9,7 @@ int
 test_1 (const char *p)
 {
   int i;
-  return ssacnf (p, "%d", &i); /* { dg-error "10: .ssacnf. was not declared in this scope" } */
-  /* { dg-begin-multiline-output "" }
-   return ssacnf (p, "%d", &i);
-          ^~~~~~
-   { dg-end-multiline-output "" } */
-  // { dg-message "10: suggested alternative: 'sscafn'" "" { target *-*-* } 12 }
+  return ssacnf (p, "%d", &i); /* { dg-error "10: .ssacnf. was not declared in this scope; did you mean 'sscafn'\\?" } */
   /* { dg-begin-multiline-output "" }
    return ssacnf (p, "%d", &i);
           ^~~~~~
@@ -29,12 +24,7 @@ int
 test_2 (void)
 {
   int i;
-  return sacnf ("%d", &i); /* { dg-error "10: .sacnf. was not declared in this scope" } */
-  /* { dg-begin-multiline-output "" }
-   return sacnf ("%d", &i);
-          ^~~~~
-   { dg-end-multiline-output "" } */
-  // { dg-message "10: suggested alternative: 'scanf'" "" { target *-*-* } 32 }
+  return sacnf ("%d", &i); /* { dg-error "10: .sacnf. was not declared in this scope; did you mean 'scanf'\\?" } */
   /* { dg-begin-multiline-output "" }
    return sacnf ("%d", &i);
           ^~~~~
index e4a606e2052a70fb57d83757f5f86788bee34cf7..a9521af8c53aaf15e09869c82b08e80c744f7535 100644 (file)
@@ -9,12 +9,7 @@ extern void gtk_widget_show_all (GtkWidget *w);
 void
 test_1 (GtkWidget *w)
 {
-  gtk_widget_showall (w); // { dg-error "3: 'gtk_widget_showall' was not declared in this scope" }
-  /* { dg-begin-multiline-output "" }
-   gtk_widget_showall (w);
-   ^~~~~~~~~~~~~~~~~~
-   { dg-end-multiline-output "" } */
-  // { dg-message "3: suggested alternative: 'gtk_widget_show_all'" "" { target *-*-* } 12 }
+  gtk_widget_showall (w); // { dg-error "3: 'gtk_widget_showall' was not declared in this scope; did you mean 'gtk_widget_show_all'\\?" }
   /* { dg-begin-multiline-output "" }
    gtk_widget_showall (w);
    ^~~~~~~~~~~~~~~~~~
@@ -23,24 +18,14 @@ test_1 (GtkWidget *w)
 
   /* Ensure we don't try to suggest "gtk_widget_showall" for subsequent
      corrections.  */
-  gtk_widget_showall_ (w); // { dg-error "3: 'gtk_widget_showall_' was not declared in this scope" }
-  /* { dg-begin-multiline-output "" }
-   gtk_widget_showall_ (w);
-   ^~~~~~~~~~~~~~~~~~~
-   { dg-end-multiline-output "" } */
-  // { dg-message "3: suggested alternative: 'gtk_widget_show_all'" "" { target *-*-* } 26 }
+  gtk_widget_showall_ (w); // { dg-error "3: 'gtk_widget_showall_' was not declared in this scope; did you mean 'gtk_widget_show_all'\\?" }
   /* { dg-begin-multiline-output "" }
    gtk_widget_showall_ (w);
    ^~~~~~~~~~~~~~~~~~~
    gtk_widget_show_all
    { dg-end-multiline-output "" } */
 
-  GtkWidgetShowAll (w); // { dg-error "3: 'GtkWidgetShowAll' was not declared in this scope" }
-  /* { dg-begin-multiline-output "" }
-   GtkWidgetShowAll (w);
-   ^~~~~~~~~~~~~~~~
-   { dg-end-multiline-output "" } */
-  // { dg-message "3: suggested alternative: 'gtk_widget_show_all'" "" { target *-*-* } 38 }
+  GtkWidgetShowAll (w); // { dg-error "3: 'GtkWidgetShowAll' was not declared in this scope; did you mean 'gtk_widget_show_all'\\?" }
   /* { dg-begin-multiline-output "" }
    GtkWidgetShowAll (w);
    ^~~~~~~~~~~~~~~~
@@ -51,12 +36,7 @@ test_1 (GtkWidget *w)
 int
 test_2 (int param)
 {
-  return parma * parma; // { dg-error "10: 'parma' was not declared in this scope" }
-  /* { dg-begin-multiline-output "" }
-   return parma * parma;
-          ^~~~~
-   { dg-end-multiline-output "" } */
-  // { dg-message "10: suggested alternative: 'param'" "" { target *-*-* } 54 }
+  return parma * parma; // { dg-error "10: 'parma' was not declared in this scope; did you mean 'param'\\?" }
   /* { dg-begin-multiline-output "" }
    return parma * parma;
           ^~~~~
@@ -69,12 +49,7 @@ test_2 (int param)
 int
 test_3 (int i)
 {
-  return MACRAME (i); // { dg-error "10: 'MACRAME' was not declared in this scope" }
-  /* { dg-begin-multiline-output "" }
-   return MACRAME (i);
-          ^~~~~~~
-   { dg-end-multiline-output "" } */
-  // { dg-message "10: suggested alternative: 'MACRO'" "" { target *-*-* } 72 }
+  return MACRAME (i); // { dg-error "10: 'MACRAME' was not declared in this scope; did you mean 'MACRO'\\?" }
   /* { dg-begin-multiline-output "" }
    return MACRAME (i);
           ^~~~~~~
@@ -87,12 +62,7 @@ test_3 (int i)
 int
 test_4 (int node)
 {
-  return IDENTIFIER_PTR (node); // { dg-error "10: 'IDENTIFIER_PTR' was not declared in this scope" }
-  /* { dg-begin-multiline-output "" }
-   return IDENTIFIER_PTR (node);
-          ^~~~~~~~~~~~~~
-   { dg-end-multiline-output "" } */
-  // { dg-message "10: suggested alternative: 'IDENTIFIER_POINTER'" "" { target *-*-* } 90 }
+  return IDENTIFIER_PTR (node); // { dg-error "10: 'IDENTIFIER_PTR' was not declared in this scope; did you mean 'IDENTIFIER_POINTER'\\?" }
   /* { dg-begin-multiline-output "" }
    return IDENTIFIER_PTR (node);
           ^~~~~~~~~~~~~~
@@ -104,12 +74,7 @@ test_4 (int node)
 int
 test_5 (void)
 {
-  return __LINE_; /* { dg-error "10: '__LINE_' was not declared in this scope" }
-  /* { dg-begin-multiline-output "" }
-   return __LINE_;
-          ^~~~~~~
-   { dg-end-multiline-output "" } */
-  // { dg-message "10: suggested alternative: '__LINE__'" "" { target *-*-* } 107 }
+  return __LINE_; /* { dg-error "10: '__LINE_' was not declared in this scope; did you mean '__LINE__'\\?" }
   /* { dg-begin-multiline-output "" }
    return __LINE_;
           ^~~~~~~
@@ -118,12 +83,7 @@ test_5 (void)
 }
 
 #define MAX_ITEMS 100
-int array[MAX_ITEM]; // { dg-error "11: 'MAX_ITEM' was not declared in this scope" }
-  /* { dg-begin-multiline-output "" }
- int array[MAX_ITEM];
-           ^~~~~~~~
-   { dg-end-multiline-output "" } */
-  // { dg-message "11: suggested alternative: 'MAX_ITEMS'" "" { target *-*-* } 121 }
+int array[MAX_ITEM]; // { dg-error "11: 'MAX_ITEM' was not declared in this scope; did you mean 'MAX_ITEMS'\\?" }
   /* { dg-begin-multiline-output "" }
  int array[MAX_ITEM];
            ^~~~~~~~
@@ -141,26 +101,16 @@ test_6 (enum foo f)
 {
   switch (f)
     {
-    case FOO_FURST: // { dg-error "10: 'FOO_FURST' was not declared in this scope" }
+    case FOO_FURST: // { dg-error "10: 'FOO_FURST' was not declared in this scope; did you mean 'FOO_FIRST'\\?" }
       break;
-  /* { dg-begin-multiline-output "" }
-     case FOO_FURST:
-          ^~~~~~~~~
-   { dg-end-multiline-output "" } */
-  // { dg-message "10: suggested alternative: 'FOO_FIRST'" "" { target *-*-* } 144 }
   /* { dg-begin-multiline-output "" }
      case FOO_FURST:
           ^~~~~~~~~
           FOO_FIRST
    { dg-end-multiline-output "" } */
 
-    case FOO_SECCOND: // { dg-error "10: 'FOO_SECCOND' was not declared in this scope" }
+    case FOO_SECCOND: // { dg-error "10: 'FOO_SECCOND' was not declared in this scope; did you mean 'FOO_SECOND'\\?" }
       break;
-  /* { dg-begin-multiline-output "" }
-     case FOO_SECCOND:
-          ^~~~~~~~~~~
-   { dg-end-multiline-output "" } */
-  // { dg-message "10: suggested alternative: 'FOO_SECOND'" "" { target *-*-* } 157 }
   /* { dg-begin-multiline-output "" }
      case FOO_SECCOND:
           ^~~~~~~~~~~
@@ -178,12 +128,7 @@ void
 test_7 (int i, int j)
 {
   int buffer[100];
-  snprint (buffer, 100, "%i of %i", i, j); // { dg-error "3: 'snprint' was not declared in this scope" }
-  /* { dg-begin-multiline-output "" }
-   snprint (buffer, 100, "%i of %i", i, j);
-   ^~~~~~~
-   { dg-end-multiline-output "" } */
-  // { dg-message "3: suggested alternative: 'snprintf'" "" { target *-*-* } 181 }
+  snprint (buffer, 100, "%i of %i", i, j); // { dg-error "3: 'snprint' was not declared in this scope; did you mean 'snprintf'\\?" }
   /* { dg-begin-multiline-output "" }
    snprint (buffer, 100, "%i of %i", i, j);
    ^~~~~~~
@@ -196,12 +141,7 @@ test_8 ()
 {
   int local = 42;
   
-  return locale; // { dg-error "10: 'locale' was not declared in this scope" }
-  /* { dg-begin-multiline-output "" }
-   return locale;
-          ^~~~~~
-   { dg-end-multiline-output "" } */
-  // { dg-message "10: suggested alternative: 'local'" "" { target *-*-* } 199 }
+  return locale; // { dg-error "10: 'locale' was not declared in this scope; did you mean 'local'\\?" }
   /* { dg-begin-multiline-output "" }
    return locale;
           ^~~~~~
@@ -226,12 +166,7 @@ public:
 
 int base::test_method_1 ()
 {
-  return m_food; // { dg-error "10: 'm_food' was not declared in this scope" }
-  /* { dg-begin-multiline-output "" }
-   return m_food;
-          ^~~~~~
-   { dg-end-multiline-output "" } */
-  // { dg-message "10: suggested alternative: 'm_foo'" "" { target *-*-* } 229 }
+  return m_food; // { dg-error "10: 'm_food' was not declared in this scope; did you mean 'm_foo'\\?" }
   /* { dg-begin-multiline-output "" }
    return m_food;
           ^~~~~~
@@ -241,12 +176,7 @@ int base::test_method_1 ()
 
 int sub::test_method_2 ()
 {
-  return m_food; // { dg-error "10: 'm_food' was not declared in this scope" }
-  /* { dg-begin-multiline-output "" }
-   return m_food;
-          ^~~~~~
-   { dg-end-multiline-output "" } */
-  // { dg-message "10: suggested alternative: 'm_foo'" "" { target *-*-* } 244 }
+  return m_food; // { dg-error "10: 'm_food' was not declared in this scope; did you mean 'm_foo'\\?" }
   /* { dg-begin-multiline-output "" }
    return m_food;
           ^~~~~~
diff --git a/gcc/testsuite/g++.dg/spellcheck-ns.C b/gcc/testsuite/g++.dg/spellcheck-ns.C
new file mode 100644 (file)
index 0000000..4f7452a
--- /dev/null
@@ -0,0 +1,22 @@
+// { dg-options "-fdiagnostics-show-caret" }
+
+namespace outer {
+  namespace inner_ns {
+  }
+  typedef int some_typedef;
+}
+
+using namespace outer;
+using namespace outer::inner_ms; // { dg-error "'inner_ms' is not a namespace-name; did you mean 'inner_ns'" }
+/* { dg-begin-multiline-output "" }
+ using namespace outer::inner_ms;
+                        ^~~~~~~~
+                        inner_ns
+   { dg-end-multiline-output "" } */
+
+outer::some_typedfe var; // { dg-error "'some_typedfe' in namespace 'outer' does not name a type; did you mean 'some_typedef'" }
+/* { dg-begin-multiline-output "" }
+ outer::some_typedfe var;
+        ^~~~~~~~~~~~
+        some_typedef
+   { dg-end-multiline-output "" } */
index 2f75779a1b426e6acf51753ce8d48109c030d718..17071345d3fb0ddc96eaa4a26a637065276e80b8 100644 (file)
@@ -18,12 +18,7 @@ namespace detail {
 
 void fn_1_explicit ()
 {
-  detail::some_type i; // { dg-error ".some_type. is not a member of .detail." }
-  // { dg-message "suggested alternative: .some_typedef." "" { target *-*-* } .-1 }
-  /* { dg-begin-multiline-output "" }
-   detail::some_type i;
-           ^~~~~~~~~
-     { dg-end-multiline-output "" } */
+  detail::some_type i; // { dg-error ".some_type. is not a member of .detail.; did you mean 'some_typedef'\\?" }
   /* { dg-begin-multiline-output "" }
    detail::some_type i;
            ^~~~~~~~~
@@ -35,12 +30,7 @@ namespace detail {
 
 void fn_1_implicit ()
 {
-  some_type i; // { dg-error ".some_type. was not declared in this scope" }
-  // { dg-message "suggested alternative: .some_typedef." "" { target *-*-* } .-1 }
-  /* { dg-begin-multiline-output "" }
-   some_type i;
-   ^~~~~~~~~
-     { dg-end-multiline-output "" } */
+  some_type i; // { dg-error ".some_type. was not declared in this scope; did you mean 'some_typedef'\\?" }
   /* { dg-begin-multiline-output "" }
    some_type i;
    ^~~~~~~~~
@@ -54,12 +44,7 @@ void fn_1_implicit ()
 /* Tests of lookup of a function.  */
 
 void fn_2_explicit (int i) {
-  detail::foo(i); // { dg-error ".foo. is not a member of .detail." }
-  // { dg-message "suggested alternative: ._foo." "" { target *-*-* } .-1 }
-  /* { dg-begin-multiline-output "" }
-   detail::foo(i);
-           ^~~
-     { dg-end-multiline-output "" } */
+  detail::foo(i); // { dg-error ".foo. is not a member of .detail.; did you mean '_foo'\\?" }
   /* { dg-begin-multiline-output "" }
    detail::foo(i);
            ^~~
@@ -70,12 +55,7 @@ void fn_2_explicit (int i) {
 namespace detail {
 
 void fn_2_implicit (int i) {
-  foo(i); // { dg-error ".foo. was not declared in this scope" }
-  // { dg-message "suggested alternative: ._foo." "" { target *-*-* } .-1 }
-  /* { dg-begin-multiline-output "" }
-   foo(i);
-   ^~~
-     { dg-end-multiline-output "" } */
+  foo(i); // { dg-error ".foo. was not declared in this scope; did you mean '_foo'\\?" }
   /* { dg-begin-multiline-output "" }
    foo(i);
    ^~~
@@ -89,13 +69,7 @@ void fn_2_implicit (int i) {
 /* Examples using a template.  */
 
 void fn_3_explicit (int i) {
-  detail::something_els(i); // { dg-error ".something_els. is not a member of .detail." }
-  // { dg-message "suggested alternative: .something_else." "" { target *-*-* } .-1 }
-  /* { dg-begin-multiline-output "" }
-   detail::something_els(i);
-           ^~~~~~~~~~~~~
-     { dg-end-multiline-output "" } */
-
+  detail::something_els(i); // { dg-error ".something_els. is not a member of .detail.; did you mean 'something_else'\\?" }
   /* { dg-begin-multiline-output "" }
    detail::something_els(i);
            ^~~~~~~~~~~~~
@@ -106,13 +80,7 @@ void fn_3_explicit (int i) {
 namespace detail {
 
 void fn_3_implicit (int i) {
-  something_els(i); // { dg-error ".something_els. was not declared in this scope" }
-  // { dg-message "suggested alternative: .something_else." "" { target *-*-* } .-1 }
-  /* { dg-begin-multiline-output "" }
-   something_els(i);
-   ^~~~~~~~~~~~~
-     { dg-end-multiline-output "" } */
-
+  something_els(i); // { dg-error ".something_els. was not declared in this scope; did you mean 'something_else'\\?" }
   /* { dg-begin-multiline-output "" }
    something_els(i);
    ^~~~~~~~~~~~~
@@ -153,12 +121,7 @@ typedef int another_typedef;
 
 void fn_5 ()
 {
-  ::another_type i; // { dg-error ".::another_type. has not been declared" }
-  // { dg-message "suggested alternative: .another_typedef." "" { target *-*-* } .-1 }
-  /* { dg-begin-multiline-output "" }
-   ::another_type i;
-     ^~~~~~~~~~~~
-     { dg-end-multiline-output "" } */
+  ::another_type i; // { dg-error ".::another_type. has not been declared; did you mean 'another_typedef'\\?" }
   /* { dg-begin-multiline-output "" }
    ::another_type i;
      ^~~~~~~~~~~~
index ded4bb6be852d742cfd152ffbe9c65ce28c8772e..ead4e0847befe0bceddaa947ee35677d3084fb0f 100644 (file)
@@ -4,12 +4,7 @@
 
 void* allocate(std::size_t n)
 {
-  return std::allocate<char>().allocate(n); // { dg-error ".allocate. is not a member of .std." }
-  // { dg-message "suggested alternative: .allocator." "" { target *-*-* } .-1 }
-  /* { dg-begin-multiline-output "" }
-   return std::allocate<char>().allocate(n);
-               ^~~~~~~~
-     { dg-end-multiline-output "" } */ 
+  return std::allocate<char>().allocate(n); // { dg-error ".allocate. is not a member of .std.; did you mean 'allocator'\\?" }
   /* { dg-begin-multiline-output "" }
    return std::allocate<char>().allocate(n);
                ^~~~~~~~
@@ -22,12 +17,7 @@ void* allocate(std::size_t n)
 
 void* test_2(std::size_t n)
 {
-  return std::alocator<char>().allocate(n); // { dg-error ".alocator. is not a member of .std." }
-  // { dg-message "suggested alternative: .allocator." "" { target *-*-* } .-1 }
-  /* { dg-begin-multiline-output "" }
-   return std::alocator<char>().allocate(n);
-               ^~~~~~~~
-     { dg-end-multiline-output "" } */ 
+  return std::alocator<char>().allocate(n); // { dg-error ".alocator. is not a member of .std.; did you mean 'allocator'\\?" }
   /* { dg-begin-multiline-output "" }
    return std::alocator<char>().allocate(n);
                ^~~~~~~~
index 4d7bbf9ca924f7c0b5a6ea2d410c7cd91a434d61..7016ee5af444868a62a4e83d1b026f78e02196e3 100644 (file)
@@ -1,5 +1,6 @@
 // Ensure that we can offer suggestions for misspellings via a
 // namespace alias.
+// { dg-options "-fdiagnostics-show-caret" }
 
 namespace N { int x; int color; }
 namespace M = N; 
@@ -8,10 +9,18 @@ namespace O = M;
 int foo () 
 {
   return M::y; // { dg-error ".y. is not a member of .M." }
+  /* { dg-begin-multiline-output "" }
+   return M::y;
+             ^
+     { dg-end-multiline-output "" } */
 }
 
 int bar () 
 {
-  return O::colour; // { dg-error ".colour. is not a member of .O." }
-  // { dg-message "suggested alternative: .color." "" { target *-*-* } .-1 }
+  return O::colour; // { dg-error ".colour. is not a member of .O.; did you mean 'color'\\?" }
+  /* { dg-begin-multiline-output "" }
+   return O::colour;
+             ^~~~~~
+             color
+     { dg-end-multiline-output "" } */
 }
index 2ff24e8b288fbb81d87731779d7e76dd118736fc..7367887a37b09ed52d0c58387e77775903d23ecb 100644 (file)
@@ -1,7 +1,12 @@
 // { dg-do compile { target c++11 } }
+// { dg-options "-fdiagnostics-show-caret" }
 
 void pr80177 ()
 {
-  static_assertion (1 == 0, "1 == 0"); // { dg-error "3: 'static_assertion' was not declared in this scope" }
-  // { dg-message "3: suggested alternative: 'static_assert'" "" { target *-*-* } .-1 }
+  static_assertion (1 == 0, "1 == 0"); // { dg-error "3: 'static_assertion' was not declared in this scope; did you mean 'static_assert'\\?" }
+  /* { dg-begin-multiline-output "" }
+   static_assertion (1 == 0, "1 == 0");
+   ^~~~~~~~~~~~~~~~
+   static_assert
+     { dg-end-multiline-output "" } */
 }
diff --git a/gcc/testsuite/g++.dg/spellcheck-single-vs-multiple.C b/gcc/testsuite/g++.dg/spellcheck-single-vs-multiple.C
new file mode 100644 (file)
index 0000000..7d9b87a
--- /dev/null
@@ -0,0 +1,79 @@
+/* Example of namespace suggestions, covering the special-case handling
+   of where there's one suggestion, vs multiple suggestions.  */
+
+/* { dg-options "-fdiagnostics-show-caret" } */
+
+/* Missing a namespace, where there's one candidate.
+   Verify that we issue a fix-it hint.  */
+
+namespace ns1
+{
+  void foo_1 (); // { dg-line foo_1_decl }
+}
+
+void test_1 ()
+{
+  foo_1 (); // { dg-error "'foo_1' was not declared in this scope; did you mean 'ns1::foo_1'\\?" }
+  /* { dg-begin-multiline-output "" }
+   foo_1 ();
+   ^~~~~
+   ns1::foo_1
+     { dg-end-multiline-output "" } */
+  // { dg-message "'ns1::foo_1' declared here" "" { target *-*-*} foo_1_decl }
+  /* { dg-begin-multiline-output "" }
+   void foo_1 ();
+        ^~~~~
+     { dg-end-multiline-output "" } */
+}
+
+/* Missing a namespace, where there are multiple candidates.
+   We don't issue a fix-it hint.  */
+
+namespace ns2_a
+{
+  char foo_2 (); // { dg-line ns2_a_foo_2_decl }
+}
+
+namespace ns2_b
+{
+  int foo_2 (); // { dg-line ns2_b_foo_2_decl }
+}
+
+void test_2 ()
+{
+  foo_2 (); // { dg-line foo_2_usage }
+  // { dg-error "'foo_2' was not declared in this scope" "" { target *-*-*} foo_2_usage }
+  /* { dg-begin-multiline-output "" }
+   foo_2 ();
+   ^~~~~
+     { dg-end-multiline-output "" } */
+  // { dg-message "suggested alternatives:" "" { target *-*-*} foo_2_usage }
+  // { dg-message "  'ns2_a::foo_2'" "" { target *-*-*} ns2_a_foo_2_decl }
+  /* { dg-begin-multiline-output "" }
+   char foo_2 ();
+        ^~~~~
+     { dg-end-multiline-output "" } */
+  // { dg-message "  'ns2_b::foo_2'" "" { target *-*-*} ns2_b_foo_2_decl }
+  /* { dg-begin-multiline-output "" }
+   int foo_2 ();
+       ^~~~~
+     { dg-end-multiline-output "" } */
+}
+
+/* Misspelling within an explicit namespace.
+   Verify that we issue a fix-it hint.  */
+
+namespace ns3
+{
+  void foo_3 ();
+}
+
+void test_3 ()
+{
+  ns3::goo_3 (); // { dg-error "'goo_3' is not a member of 'ns3'; did you mean 'foo_3'\\?" }
+  /* { dg-begin-multiline-output "" }
+   ns3::goo_3 ();
+        ^~~~~
+        foo_3
+     { dg-end-multiline-output "" } */
+}
index 01bcf78781e8bf5471bce4f6e79ef039126ac430..25d3f1dcefd8eb322a392f1e7721640e383e00bd 100644 (file)
@@ -9,12 +9,7 @@ void test_2 (singed char e); // { dg-error "21: variable or field 'test_2' decla
  void test_2 (singed char e);
                      ^~~~
    { dg-end-multiline-output "" } */
-// { dg-message "14: 'singed' was not declared in this scope" "" { target *-*-* } 7 }
-/* { dg-begin-multiline-output "" }
- void test_2 (singed char e);
-              ^~~~~~
-   { dg-end-multiline-output "" } */
-// { dg-message "14: suggested alternative: 'signed'" "" { target *-*-* } 7 }
+// { dg-message "14: 'singed' was not declared in this scope; did you mean 'signed'\\?" "" { target *-*-* } 7 }
 /* { dg-begin-multiline-output "" }
  void test_2 (singed char e);
               ^~~~~~
@@ -26,8 +21,7 @@ void test_3 (car e); // { dg-error "14: variable or field 'test_3' declared void
  void test_3 (car e);
               ^~~
    { dg-end-multiline-output "" } */
-// { dg-message "14: 'car' was not declared in this scope" "" { target *-*-* } 24 }
-// { dg-message "14: suggested alternative: 'char'" "" { target *-*-* } 24 }
+// { dg-message "14: 'car' was not declared in this scope; did you mean 'char'\\?" "" { target *-*-* } 19 }
 /* { dg-begin-multiline-output "" }
  void test_3 (car e);
               ^~~
index 5740ac44eeab183a78603fa31525ceab91f6b6d5..36fed386e493bd681330f39aad47704a3709de53 100644 (file)
@@ -19,6 +19,6 @@ namespace __gnu_debug_def
 namespace std
 {
   template<> void
-  vector<int, allocator<int> >::swap(vector<int, allocator<int> >&) { } // { dg-error "" }
-  // { dg-message "suggested alternative" "suggested alternative" { target *-*-* } .-1 }
+  vector<int, allocator<int> >::swap(vector<int, allocator<int> >&) { } // { dg-error "did you mean 'std::allocator'" }
+  // { dg-error "" "" { target *-*-*} .-1 }
 }
index 3d317bf2d53da44b01961ea6468ce91c8e9f15ae..832b5e8c1ddf18e95ca184290516dd41337380cc 100644 (file)
@@ -3,5 +3,4 @@ namespace A {
   int i = 1;                   // { dg-message "A::i" }
 }
 
-int j = i;             // { dg-error "" } 
-  // { dg-message "suggested alternative" "suggested alternative" { target *-*-* } .-1 }
+int j = i;             // { dg-error "'i' was not declared in this scope; did you mean 'A::i'" } 
index 14a38b6267e9caf38f2764d53c3954d41618c422..6f9e6d21b1f8fed56d0ea5ba8825ab9a13ef6ee6 100644 (file)
@@ -5,6 +5,5 @@ namespace A {
 }
 
 namespace B {
-  int j = i;   // { dg-error "" } 
-  // { dg-message "suggested alternative" "suggested alternative" { target *-*-* } .-1 }
+  int j = i;   // { dg-error "'i' was not declared in this scope; did you mean 'A::i'" } 
 }
index 2246f8a4c4c61dd2e851c4548ed247cf2d484c21..4461d13dce2bb2706b155b57f3f96c40af14f8e0 100644 (file)
@@ -14,6 +14,5 @@ void g()
   foo(new X);            // ok -- DR 218 says that we find the global
                         // foo variable first, and therefore do not
                         // perform argument-dependent lookup.
-  bar(new X);            // { dg-error "3:'bar' was not declared" }
-  // { dg-message "suggested alternative" "suggested alternative" { target *-*-* } .-1 }
+  bar(new X);            // { dg-error "3:'bar' was not declared in this scope; did you mean 'A::bar'" }
 }
index 63dc0b4b6daab04c29fc1350513c92bbb327b122..1865f117e0f6ac2a774047048537249df66e76c6 100644 (file)
@@ -15,6 +15,5 @@ namespace tmp {
 
 class A {
   public:
-  int kaka(tmp::B = b);                // { dg-error "" } no b in scope
-  // { dg-message "suggested alternative" "suggested alternative" { target *-*-* } .-1 }
+  int kaka(tmp::B = b);                // { dg-error "'b' was not declared in this scope; did you mean 'tmp::b'" }
 };
index e2e115a2eed86c412b4abc86a3fee89f221b973c..4584f7cb8afd62654b6cef50e362c3d99eda32f8 100644 (file)
@@ -1,3 +1,8 @@
+2018-10-29  David Malcolm  <dmalcolm@redhat.com>
+
+       * unique-ptr.h (gnu::move): Generalize so it applies to all
+       lvalue references, rather than just to unique_ptr values.
+
 2018-07-26  Martin Liska  <mliska@suse.cz>
 
        PR lto/86548
index a12c2196173f0df7eb4ebcbd0e7ca1f667fc237f..a7255fc554610562b3abcb9867d17160a52aeba8 100644 (file)
@@ -336,13 +336,13 @@ operator>= (const detail::unique_ptr_base<T, D> &x,
 { return !(x < y); }
 
 /* std::move "emulation".  This is as simple as it can be -- no
-   attempt is made to emulate rvalue references.  Instead relies on
-   the fact that gnu::unique_ptr has move semantics like
-   std::auto_ptr.  I.e., copy/assignment actually moves.  */
+   attempt is made to emulate rvalue references.  This relies on T
+   having move semantics like std::auto_ptr.
+   I.e., copy/assignment actually moves.  */
 
-template<typename T, typename D>
-unique_ptr<T, D>
-move (unique_ptr<T, D> v)
+template<typename T>
+const T&
+move (T& v)
 {
   return v;
 }
index 71a9df1e09f538c9690e03b9c61f148db4cfcafe..a3a40568fcdbb40e65189f0daed98088a1c80bec 100644 (file)
@@ -1,3 +1,9 @@
+2018-10-29  David Malcolm  <dmalcolm@redhat.com>
+
+       * testsuite/17_intro/using_namespace_std_exp_neg.cc: Remove
+       "expected namespace-name before" error.
+       * testsuite/17_intro/using_namespace_std_tr1_neg.cc: Likewise.
+
 2018-10-28  François Dumont  <fdumont@gcc.gnu.org>
 
        * testsuite/23_containers/deque/48101_neg.cc: Remove dg-prune-output
index 5821f2f8cf0bc68cd73d04943677fcb4f3ead7df..2bf8f12e59fc0eb13ac2f1f0728fddec1af7fdb0 100644 (file)
@@ -61,5 +61,3 @@ namespace gnu
 {
   using namespace std::experimental;  // { dg-error "is not a namespace-name" }
 }
-
-// { dg-error "expected namespace-name before" "" { target *-*-* } 62 }
index aad4894917ce6c698f9882d2116bf17366be237b..8a1527ca6cbd0008575145ef6a1a99b40207d9e1 100644 (file)
@@ -64,5 +64,3 @@ namespace gnu
 {
   using namespace std::tr1;  // { dg-error "is not a namespace-name" }
 }
-
-// { dg-error "expected namespace-name before" "" { target *-*-* } 65 }