* [PATCH] C++: simplify output from suggest_alternatives_for
@ 2018-10-09 19:08 David Malcolm
2018-10-09 23:29 ` Jason Merrill
2018-10-10 15:35 ` [PATCH] " Jason Merrill
0 siblings, 2 replies; 8+ messages in thread
From: David Malcolm @ 2018-10-09 19:08 UTC (permalink / raw)
To: gcc-patches, jason; +Cc: David Malcolm
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
Successfully bootstrapped & regrtested on x86_64-pc-linux-gnu
(on top of
https://gcc.gnu.org/ml/gcc-patches/2018-09/msg01272.html
"v2: C++: suggestions for misspelled private members (PR c++/84993)")
OK for trunk?
gcc/c-family/ChangeLog:
* name-hint.h (class name_hint): Add copy constructor and copy
assignment operator.
(name_hint::operator bool): Also return true if m_deferred is
non-NULL.
(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.
---
gcc/c-family/name-hint.h | 27 +-
gcc/c/c-decl.c | 24 +-
gcc/c/c-parser.c | 12 +-
gcc/cp/cp-name-hint.h | 37 ++
gcc/cp/cp-tree.h | 3 +-
gcc/cp/error.c | 43 ++-
gcc/cp/lex.c | 17 +-
gcc/cp/name-lookup.c | 407 ++++++++++++++++-----
gcc/cp/parser.c | 84 ++++-
gcc/testsuite/c-c++-common/spellcheck-reserved.c | 9 +-
gcc/testsuite/g++.dg/ext/builtin3.C | 3 +-
gcc/testsuite/g++.dg/lookup/error1.C | 3 +-
gcc/testsuite/g++.dg/lookup/pr77549.C | 15 +-
gcc/testsuite/g++.dg/lookup/pr80913.C | 3 +-
gcc/testsuite/g++.dg/lookup/suggestions1.C | 8 +-
gcc/testsuite/g++.dg/lookup/suggestions2.C | 128 +++++++
gcc/testsuite/g++.dg/overload/koenig1.C | 3 +-
gcc/testsuite/g++.dg/spellcheck-identifiers-2.C | 14 +-
gcc/testsuite/g++.dg/spellcheck-identifiers.C | 98 +----
gcc/testsuite/g++.dg/spellcheck-ns.C | 22 ++
gcc/testsuite/g++.dg/spellcheck-pr77829.C | 51 +--
gcc/testsuite/g++.dg/spellcheck-pr78656.C | 14 +-
gcc/testsuite/g++.dg/spellcheck-pr79298.C | 13 +-
gcc/testsuite/g++.dg/spellcheck-pr80177.C | 9 +-
.../g++.dg/spellcheck-single-vs-multiple.C | 79 ++++
gcc/testsuite/g++.dg/spellcheck-typenames.C | 10 +-
gcc/testsuite/g++.dg/template/static10.C | 4 +-
gcc/testsuite/g++.old-deja/g++.mike/ns5.C | 3 +-
gcc/testsuite/g++.old-deja/g++.mike/ns7.C | 3 +-
gcc/testsuite/g++.old-deja/g++.ns/koenig5.C | 3 +-
gcc/testsuite/g++.old-deja/g++.other/lineno5.C | 3 +-
.../17_intro/using_namespace_std_exp_neg.cc | 2 -
.../17_intro/using_namespace_std_tr1_neg.cc | 2 -
33 files changed, 806 insertions(+), 350 deletions(-)
create mode 100644 gcc/cp/cp-name-hint.h
create mode 100644 gcc/testsuite/g++.dg/lookup/suggestions2.C
create mode 100644 gcc/testsuite/g++.dg/spellcheck-ns.C
create mode 100644 gcc/testsuite/g++.dg/spellcheck-single-vs-multiple.C
diff --git a/gcc/c-family/name-hint.h b/gcc/c-family/name-hint.h
index ef0e4a3..f1788e1 100644
--- a/gcc/c-family/name-hint.h
+++ b/gcc/c-family/name-hint.h
@@ -98,8 +98,33 @@ public:
{
}
+ /* Emulation of a "move" constructor, but really a copy
+ constructor. */
+
+ name_hint (const name_hint &other)
+ : m_suggestion (other.m_suggestion),
+ m_deferred (const_cast<name_hint &> (other).take_deferred ())
+ {
+ }
+
+ /* Emulation of "move" assigment, but really copy assignment. */
+
+ name_hint& operator= (const name_hint &other)
+ {
+ m_suggestion = other.m_suggestion;
+ m_deferred = const_cast<name_hint &> (other).take_deferred ();
+ return *this;
+ }
+
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. */
diff --git a/gcc/c/c-decl.c b/gcc/c/c-decl.c
index fdcfbde..cc9dc67 100644
--- a/gcc/c/c-decl.c
+++ b/gcc/c/c-decl.c
@@ -3152,27 +3152,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,
@@ -3515,14 +3515,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);
@@ -3533,14 +3533,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);
diff --git a/gcc/c/c-parser.c b/gcc/c/c-parser.c
index 1766a25..3afdda6 100644
--- a/gcc/c/c-parser.c
+++ b/gcc/c/c-parser.c
@@ -1817,12 +1817,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);
@@ -4054,13 +4054,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);
diff --git a/gcc/cp/cp-name-hint.h b/gcc/cp/cp-name-hint.h
new file mode 100644
index 0000000..5d1cdc3
--- /dev/null
+++ b/gcc/cp/cp-name-hint.h
@@ -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 */
diff --git a/gcc/cp/cp-tree.h b/gcc/cp/cp-tree.h
index 6c12c5f..9fac9aa 100644
--- a/gcc/cp/cp-tree.h
+++ b/gcc/cp/cp-tree.h
@@ -6443,6 +6443,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);
@@ -7476,8 +7477,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. */
diff --git a/gcc/cp/error.c b/gcc/cp/error.c
index 601f6d2..0f70360 100644
--- a/gcc/cp/error.c
+++ b/gcc/cp/error.c
@@ -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 ();
@@ -4271,15 +4273,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);
}
}
diff --git a/gcc/cp/lex.c b/gcc/cp/lex.c
index 47b99c3..410dfd1 100644
--- a/gcc/cp/lex.c
+++ b/gcc/cp/lex.c
@@ -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. */
diff --git a/gcc/cp/name-lookup.c b/gcc/cp/name-lookup.c
index c56bfe5..ac18996 100644
--- a/gcc/cp/name-lookup.c
+++ b/gcc/cp/name-lookup.c
@@ -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
@@ -5318,20 +5321,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). */
@@ -5342,14 +5457,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))
@@ -5358,60 +5473,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 (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 (result);
}
/* A well-known name within the C++ standard library, returned by
@@ -5622,11 +5818,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);
@@ -5634,62 +5870,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);
@@ -5699,15 +5922,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
diff --git a/gcc/cp/parser.c b/gcc/cp/parser.c
index f5e4fa4..28c9edc 100644
--- a/gcc/cp/parser.c
+++ b/gcc/cp/parser.c
@@ -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. */
@@ -3301,13 +3301,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);
@@ -3373,23 +3373,54 @@ 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_P (decl)
+ && 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))
@@ -18630,13 +18661,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;
}
diff --git a/gcc/testsuite/c-c++-common/spellcheck-reserved.c b/gcc/testsuite/c-c++-common/spellcheck-reserved.c
index 79b6532..ed292f2 100644
--- a/gcc/testsuite/c-c++-common/spellcheck-reserved.c
+++ b/gcc/testsuite/c-c++-common/spellcheck-reserved.c
@@ -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_ } */
}
diff --git a/gcc/testsuite/g++.dg/ext/builtin3.C b/gcc/testsuite/g++.dg/ext/builtin3.C
index 6becaa0..31d2ac6 100644
--- a/gcc/testsuite/g++.dg/ext/builtin3.C
+++ b/gcc/testsuite/g++.dg/ext/builtin3.C
@@ -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'\\?" }
}
diff --git a/gcc/testsuite/g++.dg/lookup/error1.C b/gcc/testsuite/g++.dg/lookup/error1.C
index d2741fb..1f267e7 100644
--- a/gcc/testsuite/g++.dg/lookup/error1.C
+++ b/gcc/testsuite/g++.dg/lookup/error1.C
@@ -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; }
diff --git a/gcc/testsuite/g++.dg/lookup/pr77549.C b/gcc/testsuite/g++.dg/lookup/pr77549.C
index b4b8d0e..af7c630 100644
--- a/gcc/testsuite/g++.dg/lookup/pr77549.C
+++ b/gcc/testsuite/g++.dg/lookup/pr77549.C
@@ -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'\\?" }
+}
diff --git a/gcc/testsuite/g++.dg/lookup/pr80913.C b/gcc/testsuite/g++.dg/lookup/pr80913.C
index a7866bc..028e61a 100644
--- a/gcc/testsuite/g++.dg/lookup/pr80913.C
+++ b/gcc/testsuite/g++.dg/lookup/pr80913.C
@@ -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'\\?" }
}
diff --git a/gcc/testsuite/g++.dg/lookup/suggestions1.C b/gcc/testsuite/g++.dg/lookup/suggestions1.C
index da98d11c..47126a3 100644
--- a/gcc/testsuite/g++.dg/lookup/suggestions1.C
+++ b/gcc/testsuite/g++.dg/lookup/suggestions1.C
@@ -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
index 0000000..900439f
--- /dev/null
+++ b/gcc/testsuite/g++.dg/lookup/suggestions2.C
@@ -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 "" } */
+}
diff --git a/gcc/testsuite/g++.dg/overload/koenig1.C b/gcc/testsuite/g++.dg/overload/koenig1.C
index 3c1c293..5508061 100644
--- a/gcc/testsuite/g++.dg/overload/koenig1.C
+++ b/gcc/testsuite/g++.dg/overload/koenig1.C
@@ -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);
}
diff --git a/gcc/testsuite/g++.dg/spellcheck-identifiers-2.C b/gcc/testsuite/g++.dg/spellcheck-identifiers-2.C
index 59a8ec5..67ae52b 100644
--- a/gcc/testsuite/g++.dg/spellcheck-identifiers-2.C
+++ b/gcc/testsuite/g++.dg/spellcheck-identifiers-2.C
@@ -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);
^~~~~
diff --git a/gcc/testsuite/g++.dg/spellcheck-identifiers.C b/gcc/testsuite/g++.dg/spellcheck-identifiers.C
index e4a606e..a9521af 100644
--- a/gcc/testsuite/g++.dg/spellcheck-identifiers.C
+++ b/gcc/testsuite/g++.dg/spellcheck-identifiers.C
@@ -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,29 +101,19 @@ 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:
- ^~~~~~~~~~~
FOO_SECOND
{ dg-end-multiline-output "" } */
@@ -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
index 0000000..4f7452a
--- /dev/null
+++ b/gcc/testsuite/g++.dg/spellcheck-ns.C
@@ -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 "" } */
diff --git a/gcc/testsuite/g++.dg/spellcheck-pr77829.C b/gcc/testsuite/g++.dg/spellcheck-pr77829.C
index 2f75779..1707134 100644
--- a/gcc/testsuite/g++.dg/spellcheck-pr77829.C
+++ b/gcc/testsuite/g++.dg/spellcheck-pr77829.C
@@ -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;
^~~~~~~~~~~~
diff --git a/gcc/testsuite/g++.dg/spellcheck-pr78656.C b/gcc/testsuite/g++.dg/spellcheck-pr78656.C
index ded4bb6..ead4e08 100644
--- a/gcc/testsuite/g++.dg/spellcheck-pr78656.C
+++ b/gcc/testsuite/g++.dg/spellcheck-pr78656.C
@@ -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);
^~~~~~~~
diff --git a/gcc/testsuite/g++.dg/spellcheck-pr79298.C b/gcc/testsuite/g++.dg/spellcheck-pr79298.C
index 4d7bbf9..7016ee5 100644
--- a/gcc/testsuite/g++.dg/spellcheck-pr79298.C
+++ b/gcc/testsuite/g++.dg/spellcheck-pr79298.C
@@ -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 "" } */
}
diff --git a/gcc/testsuite/g++.dg/spellcheck-pr80177.C b/gcc/testsuite/g++.dg/spellcheck-pr80177.C
index 2ff24e8..7367887 100644
--- a/gcc/testsuite/g++.dg/spellcheck-pr80177.C
+++ b/gcc/testsuite/g++.dg/spellcheck-pr80177.C
@@ -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
index 0000000..7d9b87a1
--- /dev/null
+++ b/gcc/testsuite/g++.dg/spellcheck-single-vs-multiple.C
@@ -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 "" } */
+}
diff --git a/gcc/testsuite/g++.dg/spellcheck-typenames.C b/gcc/testsuite/g++.dg/spellcheck-typenames.C
index 01bcf78..25d3f1d 100644
--- a/gcc/testsuite/g++.dg/spellcheck-typenames.C
+++ b/gcc/testsuite/g++.dg/spellcheck-typenames.C
@@ -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);
^~~
diff --git a/gcc/testsuite/g++.dg/template/static10.C b/gcc/testsuite/g++.dg/template/static10.C
index 5740ac4..36fed38 100644
--- a/gcc/testsuite/g++.dg/template/static10.C
+++ b/gcc/testsuite/g++.dg/template/static10.C
@@ -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 }
}
diff --git a/gcc/testsuite/g++.old-deja/g++.mike/ns5.C b/gcc/testsuite/g++.old-deja/g++.mike/ns5.C
index 3d317bf..832b5e8 100644
--- a/gcc/testsuite/g++.old-deja/g++.mike/ns5.C
+++ b/gcc/testsuite/g++.old-deja/g++.mike/ns5.C
@@ -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'" }
diff --git a/gcc/testsuite/g++.old-deja/g++.mike/ns7.C b/gcc/testsuite/g++.old-deja/g++.mike/ns7.C
index 14a38b6..6f9e6d2 100644
--- a/gcc/testsuite/g++.old-deja/g++.mike/ns7.C
+++ b/gcc/testsuite/g++.old-deja/g++.mike/ns7.C
@@ -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'" }
}
diff --git a/gcc/testsuite/g++.old-deja/g++.ns/koenig5.C b/gcc/testsuite/g++.old-deja/g++.ns/koenig5.C
index 2246f8a..4461d13 100644
--- a/gcc/testsuite/g++.old-deja/g++.ns/koenig5.C
+++ b/gcc/testsuite/g++.old-deja/g++.ns/koenig5.C
@@ -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'" }
}
diff --git a/gcc/testsuite/g++.old-deja/g++.other/lineno5.C b/gcc/testsuite/g++.old-deja/g++.other/lineno5.C
index 63dc0b4..1865f11 100644
--- a/gcc/testsuite/g++.old-deja/g++.other/lineno5.C
+++ b/gcc/testsuite/g++.old-deja/g++.other/lineno5.C
@@ -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'" }
};
diff --git a/libstdc++-v3/testsuite/17_intro/using_namespace_std_exp_neg.cc b/libstdc++-v3/testsuite/17_intro/using_namespace_std_exp_neg.cc
index 5821f2f..2bf8f12 100644
--- a/libstdc++-v3/testsuite/17_intro/using_namespace_std_exp_neg.cc
+++ b/libstdc++-v3/testsuite/17_intro/using_namespace_std_exp_neg.cc
@@ -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 }
diff --git a/libstdc++-v3/testsuite/17_intro/using_namespace_std_tr1_neg.cc b/libstdc++-v3/testsuite/17_intro/using_namespace_std_tr1_neg.cc
index aad4894..8a1527c 100644
--- a/libstdc++-v3/testsuite/17_intro/using_namespace_std_tr1_neg.cc
+++ b/libstdc++-v3/testsuite/17_intro/using_namespace_std_tr1_neg.cc
@@ -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 }
--
1.8.5.3
^ permalink raw reply [flat|nested] 8+ messages in thread
* Re: [PATCH] C++: simplify output from suggest_alternatives_for
2018-10-09 19:08 [PATCH] C++: simplify output from suggest_alternatives_for David Malcolm
@ 2018-10-09 23:29 ` Jason Merrill
2018-10-10 21:18 ` [PATCH] v2: " David Malcolm
2018-10-10 15:35 ` [PATCH] " Jason Merrill
1 sibling, 1 reply; 8+ messages in thread
From: Jason Merrill @ 2018-10-09 23:29 UTC (permalink / raw)
To: David Malcolm; +Cc: gcc-patches List
On Tue, Oct 9, 2018 at 1:19 PM David Malcolm <dmalcolm@redhat.com> wrote:
> + /* Emulation of a "move" constructor, but really a copy
> + constructor. */
> +
> + name_hint (const name_hint &other)
> + : m_suggestion (other.m_suggestion),
> + m_deferred (const_cast<name_hint &> (other).take_deferred ())
> + {
> + }
> +
> + /* Emulation of "move" assigment, but really copy assignment. */
> +
> + name_hint& operator= (const name_hint &other)
> + {
> + m_suggestion = other.m_suggestion;
> + m_deferred = const_cast<name_hint &> (other).take_deferred ();
> + return *this;
> + }
> +
> + /* 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); }
Why do you want to propagate this hackery into name_hint? I would
expect the defaulted special member functions to do the right thing
with m_deferred: in -std=c++98 the implicit copy ops call the
gnu::unique_ptr copy ops that actually move, and in -std=c++11 and up
we're calling the move constructor for std::unique_ptr, which does the
right thing.
This also doesn't limit the hack to C++98 mode the way unique-ptr.h does.
Jason
^ permalink raw reply [flat|nested] 8+ messages in thread
* Re: [PATCH] C++: simplify output from suggest_alternatives_for
2018-10-09 19:08 [PATCH] C++: simplify output from suggest_alternatives_for David Malcolm
2018-10-09 23:29 ` Jason Merrill
@ 2018-10-10 15:35 ` Jason Merrill
1 sibling, 0 replies; 8+ messages in thread
From: Jason Merrill @ 2018-10-10 15:35 UTC (permalink / raw)
To: David Malcolm; +Cc: gcc-patches List
On Tue, Oct 9, 2018 at 1:19 PM David Malcolm <dmalcolm@redhat.com> wrote:
> + if (!DECL_P (decl)
> + && decl == error_mark_node)
You don't need to check DECL_P here.
Jason
^ permalink raw reply [flat|nested] 8+ messages in thread
* [PATCH] v2: C++: simplify output from suggest_alternatives_for
2018-10-09 23:29 ` Jason Merrill
@ 2018-10-10 21:18 ` David Malcolm
2018-10-11 14:39 ` Jason Merrill
0 siblings, 1 reply; 8+ messages in thread
From: David Malcolm @ 2018-10-10 21:18 UTC (permalink / raw)
To: Jason Merrill; +Cc: gcc-patches, David Malcolm
On Tue, 2018-10-09 at 18:38 -0400, Jason Merrill wrote:
> On Tue, Oct 9, 2018 at 1:19 PM David Malcolm <dmalcolm@redhat.com>
> wrote:
> > + /* Emulation of a "move" constructor, but really a copy
> > + constructor. */
> > +
> > + name_hint (const name_hint &other)
> > + : m_suggestion (other.m_suggestion),
> > + m_deferred (const_cast<name_hint &> (other).take_deferred ())
> > + {
> > + }
> > +
> > + /* Emulation of "move" assigment, but really copy
> > assignment. */
> > +
> > + name_hint& operator= (const name_hint &other)
> > + {
> > + m_suggestion = other.m_suggestion;
> > + m_deferred = const_cast<name_hint &> (other).take_deferred ();
> > + return *this;
> > + }
> > +
> > + /* 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); }
>
> Why do you want to propagate this hackery into name_hint? I would
> expect the defaulted special member functions to do the right thing
> with m_deferred: in -std=c++98 the implicit copy ops call the
> gnu::unique_ptr copy ops that actually move, and in -std=c++11 and up
> we're calling the move constructor for std::unique_ptr, which does
> the
> right thing.
>
> This also doesn't limit the hack to C++98 mode the way unique-ptr.h
> does.
>
> Jason
Thanks for looking at this.
I ran into issues trying to pass around name_hint instances:
../../src/gcc/cp/name-lookup.c: In function 'name_hint suggest_alternatives_in_other_namespaces(location_t, tree)':
../../src/gcc/cp/name-lookup.c:5591:52: error: use of deleted function 'name_hint::name_hint(const name_hint&)'
5591 | return ns_hints.maybe_decorate_with_limit (result);
| ^
In file included from ../../src/gcc/cp/name-lookup.c:36:
../../src/gcc/c-family/name-hint.h:91:7: note: 'name_hint::name_hint(const name_hint&)' is implicitly deleted because the default definition would be ill-formed:
91 | class name_hint
| ^~~~~~~~~
../../src/gcc/c-family/name-hint.h:91:7: error: use of deleted function 'std::unique_ptr<_Tp, _Dp>::unique_ptr(const std::unique_ptr<_Tp, _Dp>&) [with _Tp = deferred_diagnostic; _Dp = std::default_delete<deferred_diagnostic>]'
In file included from /home/david/coding/gcc-python/gcc-svn-trunk/install-dogfood/include/c++/9.0.0/memory:80,
from ../../src/gcc/../include/unique-ptr.h:78,
from ../../src/gcc/system.h:730,
from ../../src/gcc/cp/name-lookup.c:23:
/home/david/coding/gcc-python/gcc-svn-trunk/install-dogfood/include/c++/9.0.0/bits/unique_ptr.h:394:7: note: declared here
394 | unique_ptr(const unique_ptr&) = delete;
| ^~~~~~~~~~
../../src/gcc/cp/name-lookup.c:5512:1: note: initializing argument 1 of 'name_hint namespace_hints::maybe_decorate_with_limit(name_hint)'
5512 | namespace_hints::maybe_decorate_with_limit (name_hint hint)
| ^~~~~~~~~~~~~~~
I can't use the default copy constructor or assignment operators for an
object containing a gnu::unique_ptr on C++11, as std::unique_ptr has:
// Disable copy from lvalue.
unique_ptr(const unique_ptr&) = delete;
unique_ptr& operator=(const unique_ptr&) = delete;
If I understand things right, in C++11 I should be using move
construction/move assignment for this.
I can't write "&&" in the function params to explicitly request an
rvalue-reference, as the code need to be compatible with C++98.
std::move is only defined in C++11 onwards.
Our include/unique-ptr.h defines a gnu::move: for C++11 it's std::move,
but for C++98 it's only defined for the unique_ptr template.
A solution that seems to work appears to be to define gnu::move for
C++98 for all types rather than just gnu::unique_ptr, implementing it
in terms of copying an object via lvalue reference, so that we can
explicitly request a move using "gnu::move" (==std::move on C++),
without using C++11 syntax, and falling back to a copy on C++98
(which effectively moves the ptr from the "victim").
Does that sound sane?
I implemented "take_deferred" as I wanted to keep m_deferred private,
and needed an "accessor". With the above formulation, it becomes:
{ return move (m_deferred); }
Here's an updated version of the patch which implements the above idea:
Changed in v2:
* dropped addition of name_hint copy ctor and copy assignment in
favor of using gnu::move wherever move assignment needs to happen
or be emulated
* generalized gnu::move for pre-C++11 to apply to all lvalue references,
rather than just to gnu::unique_ptr
* drop stray !DECL_P identified in another email
Successfully bootstrapped & regrtested on x86_64-pc-linux-gnu
I also tested a non-bootstrap build with gcc 4.8 and with trunk (to build
without and with C++11), running various testcases under valgrind.
OK for trunk?
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.
---
gcc/c-family/name-hint.h | 9 +-
gcc/c/c-decl.c | 24 +-
gcc/c/c-parser.c | 12 +-
gcc/cp/cp-name-hint.h | 37 ++
gcc/cp/cp-tree.h | 3 +-
gcc/cp/error.c | 43 ++-
gcc/cp/lex.c | 17 +-
gcc/cp/name-lookup.c | 407 ++++++++++++++++-----
gcc/cp/parser.c | 83 ++++-
gcc/testsuite/c-c++-common/spellcheck-reserved.c | 9 +-
gcc/testsuite/g++.dg/ext/builtin3.C | 3 +-
gcc/testsuite/g++.dg/lookup/error1.C | 3 +-
gcc/testsuite/g++.dg/lookup/pr77549.C | 15 +-
gcc/testsuite/g++.dg/lookup/pr80913.C | 3 +-
gcc/testsuite/g++.dg/lookup/suggestions1.C | 8 +-
gcc/testsuite/g++.dg/lookup/suggestions2.C | 128 +++++++
gcc/testsuite/g++.dg/overload/koenig1.C | 3 +-
gcc/testsuite/g++.dg/spellcheck-identifiers-2.C | 14 +-
gcc/testsuite/g++.dg/spellcheck-identifiers.C | 98 +----
gcc/testsuite/g++.dg/spellcheck-ns.C | 22 ++
gcc/testsuite/g++.dg/spellcheck-pr77829.C | 51 +--
gcc/testsuite/g++.dg/spellcheck-pr78656.C | 14 +-
gcc/testsuite/g++.dg/spellcheck-pr79298.C | 13 +-
gcc/testsuite/g++.dg/spellcheck-pr80177.C | 9 +-
.../g++.dg/spellcheck-single-vs-multiple.C | 79 ++++
gcc/testsuite/g++.dg/spellcheck-typenames.C | 10 +-
gcc/testsuite/g++.dg/template/static10.C | 4 +-
gcc/testsuite/g++.old-deja/g++.mike/ns5.C | 3 +-
gcc/testsuite/g++.old-deja/g++.mike/ns7.C | 3 +-
gcc/testsuite/g++.old-deja/g++.ns/koenig5.C | 3 +-
gcc/testsuite/g++.old-deja/g++.other/lineno5.C | 3 +-
include/unique-ptr.h | 12 +-
.../17_intro/using_namespace_std_exp_neg.cc | 2 -
.../17_intro/using_namespace_std_tr1_neg.cc | 2 -
34 files changed, 793 insertions(+), 356 deletions(-)
create mode 100644 gcc/cp/cp-name-hint.h
create mode 100644 gcc/testsuite/g++.dg/lookup/suggestions2.C
create mode 100644 gcc/testsuite/g++.dg/spellcheck-ns.C
create mode 100644 gcc/testsuite/g++.dg/spellcheck-single-vs-multiple.C
diff --git a/gcc/c-family/name-hint.h b/gcc/c-family/name-hint.h
index ef0e4a3..ddc3525 100644
--- a/gcc/c-family/name-hint.h
+++ b/gcc/c-family/name-hint.h
@@ -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. */
diff --git a/gcc/c/c-decl.c b/gcc/c/c-decl.c
index 160ce35..cbbf7eb 100644
--- a/gcc/c/c-decl.c
+++ b/gcc/c/c-decl.c
@@ -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);
diff --git a/gcc/c/c-parser.c b/gcc/c/c-parser.c
index 1f173fc..46dd366 100644
--- a/gcc/c/c-parser.c
+++ b/gcc/c/c-parser.c
@@ -1817,12 +1817,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);
@@ -4054,13 +4054,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);
diff --git a/gcc/cp/cp-name-hint.h b/gcc/cp/cp-name-hint.h
new file mode 100644
index 0000000..5d1cdc3
--- /dev/null
+++ b/gcc/cp/cp-name-hint.h
@@ -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 */
diff --git a/gcc/cp/cp-tree.h b/gcc/cp/cp-tree.h
index 26ded3a..8454cb4 100644
--- a/gcc/cp/cp-tree.h
+++ b/gcc/cp/cp-tree.h
@@ -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. */
diff --git a/gcc/cp/error.c b/gcc/cp/error.c
index 0b14dcc..fa115aa 100644
--- a/gcc/cp/error.c
+++ b/gcc/cp/error.c
@@ -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);
}
}
diff --git a/gcc/cp/lex.c b/gcc/cp/lex.c
index 47b99c3..410dfd1 100644
--- a/gcc/cp/lex.c
+++ b/gcc/cp/lex.c
@@ -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. */
diff --git a/gcc/cp/name-lookup.c b/gcc/cp/name-lookup.c
index 08632c3..5b026da 100644
--- a/gcc/cp/name-lookup.c
+++ b/gcc/cp/name-lookup.c
@@ -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
diff --git a/gcc/cp/parser.c b/gcc/cp/parser.c
index 032108a..21c3892 100644
--- a/gcc/cp/parser.c
+++ b/gcc/cp/parser.c
@@ -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. */
@@ -3293,13 +3293,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);
@@ -3365,23 +3365,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))
@@ -18635,13 +18665,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;
}
diff --git a/gcc/testsuite/c-c++-common/spellcheck-reserved.c b/gcc/testsuite/c-c++-common/spellcheck-reserved.c
index 79b6532..ed292f2 100644
--- a/gcc/testsuite/c-c++-common/spellcheck-reserved.c
+++ b/gcc/testsuite/c-c++-common/spellcheck-reserved.c
@@ -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_ } */
}
diff --git a/gcc/testsuite/g++.dg/ext/builtin3.C b/gcc/testsuite/g++.dg/ext/builtin3.C
index 6becaa0..31d2ac6 100644
--- a/gcc/testsuite/g++.dg/ext/builtin3.C
+++ b/gcc/testsuite/g++.dg/ext/builtin3.C
@@ -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'\\?" }
}
diff --git a/gcc/testsuite/g++.dg/lookup/error1.C b/gcc/testsuite/g++.dg/lookup/error1.C
index d2741fb..1f267e7 100644
--- a/gcc/testsuite/g++.dg/lookup/error1.C
+++ b/gcc/testsuite/g++.dg/lookup/error1.C
@@ -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; }
diff --git a/gcc/testsuite/g++.dg/lookup/pr77549.C b/gcc/testsuite/g++.dg/lookup/pr77549.C
index b4b8d0e..af7c630 100644
--- a/gcc/testsuite/g++.dg/lookup/pr77549.C
+++ b/gcc/testsuite/g++.dg/lookup/pr77549.C
@@ -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'\\?" }
+}
diff --git a/gcc/testsuite/g++.dg/lookup/pr80913.C b/gcc/testsuite/g++.dg/lookup/pr80913.C
index a7866bc..028e61a 100644
--- a/gcc/testsuite/g++.dg/lookup/pr80913.C
+++ b/gcc/testsuite/g++.dg/lookup/pr80913.C
@@ -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'\\?" }
}
diff --git a/gcc/testsuite/g++.dg/lookup/suggestions1.C b/gcc/testsuite/g++.dg/lookup/suggestions1.C
index da98d11c..47126a3 100644
--- a/gcc/testsuite/g++.dg/lookup/suggestions1.C
+++ b/gcc/testsuite/g++.dg/lookup/suggestions1.C
@@ -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
index 0000000..900439f
--- /dev/null
+++ b/gcc/testsuite/g++.dg/lookup/suggestions2.C
@@ -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 "" } */
+}
diff --git a/gcc/testsuite/g++.dg/overload/koenig1.C b/gcc/testsuite/g++.dg/overload/koenig1.C
index 3c1c293..5508061 100644
--- a/gcc/testsuite/g++.dg/overload/koenig1.C
+++ b/gcc/testsuite/g++.dg/overload/koenig1.C
@@ -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);
}
diff --git a/gcc/testsuite/g++.dg/spellcheck-identifiers-2.C b/gcc/testsuite/g++.dg/spellcheck-identifiers-2.C
index 59a8ec5..67ae52b 100644
--- a/gcc/testsuite/g++.dg/spellcheck-identifiers-2.C
+++ b/gcc/testsuite/g++.dg/spellcheck-identifiers-2.C
@@ -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);
^~~~~
diff --git a/gcc/testsuite/g++.dg/spellcheck-identifiers.C b/gcc/testsuite/g++.dg/spellcheck-identifiers.C
index e4a606e..a9521af 100644
--- a/gcc/testsuite/g++.dg/spellcheck-identifiers.C
+++ b/gcc/testsuite/g++.dg/spellcheck-identifiers.C
@@ -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,29 +101,19 @@ 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:
- ^~~~~~~~~~~
FOO_SECOND
{ dg-end-multiline-output "" } */
@@ -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
index 0000000..4f7452a
--- /dev/null
+++ b/gcc/testsuite/g++.dg/spellcheck-ns.C
@@ -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 "" } */
diff --git a/gcc/testsuite/g++.dg/spellcheck-pr77829.C b/gcc/testsuite/g++.dg/spellcheck-pr77829.C
index 2f75779..1707134 100644
--- a/gcc/testsuite/g++.dg/spellcheck-pr77829.C
+++ b/gcc/testsuite/g++.dg/spellcheck-pr77829.C
@@ -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;
^~~~~~~~~~~~
diff --git a/gcc/testsuite/g++.dg/spellcheck-pr78656.C b/gcc/testsuite/g++.dg/spellcheck-pr78656.C
index ded4bb6..ead4e08 100644
--- a/gcc/testsuite/g++.dg/spellcheck-pr78656.C
+++ b/gcc/testsuite/g++.dg/spellcheck-pr78656.C
@@ -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);
^~~~~~~~
diff --git a/gcc/testsuite/g++.dg/spellcheck-pr79298.C b/gcc/testsuite/g++.dg/spellcheck-pr79298.C
index 4d7bbf9..7016ee5 100644
--- a/gcc/testsuite/g++.dg/spellcheck-pr79298.C
+++ b/gcc/testsuite/g++.dg/spellcheck-pr79298.C
@@ -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 "" } */
}
diff --git a/gcc/testsuite/g++.dg/spellcheck-pr80177.C b/gcc/testsuite/g++.dg/spellcheck-pr80177.C
index 2ff24e8..7367887 100644
--- a/gcc/testsuite/g++.dg/spellcheck-pr80177.C
+++ b/gcc/testsuite/g++.dg/spellcheck-pr80177.C
@@ -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
index 0000000..7d9b87a1
--- /dev/null
+++ b/gcc/testsuite/g++.dg/spellcheck-single-vs-multiple.C
@@ -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 "" } */
+}
diff --git a/gcc/testsuite/g++.dg/spellcheck-typenames.C b/gcc/testsuite/g++.dg/spellcheck-typenames.C
index 01bcf78..25d3f1d 100644
--- a/gcc/testsuite/g++.dg/spellcheck-typenames.C
+++ b/gcc/testsuite/g++.dg/spellcheck-typenames.C
@@ -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);
^~~
diff --git a/gcc/testsuite/g++.dg/template/static10.C b/gcc/testsuite/g++.dg/template/static10.C
index 5740ac4..36fed38 100644
--- a/gcc/testsuite/g++.dg/template/static10.C
+++ b/gcc/testsuite/g++.dg/template/static10.C
@@ -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 }
}
diff --git a/gcc/testsuite/g++.old-deja/g++.mike/ns5.C b/gcc/testsuite/g++.old-deja/g++.mike/ns5.C
index 3d317bf..832b5e8 100644
--- a/gcc/testsuite/g++.old-deja/g++.mike/ns5.C
+++ b/gcc/testsuite/g++.old-deja/g++.mike/ns5.C
@@ -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'" }
diff --git a/gcc/testsuite/g++.old-deja/g++.mike/ns7.C b/gcc/testsuite/g++.old-deja/g++.mike/ns7.C
index 14a38b6..6f9e6d2 100644
--- a/gcc/testsuite/g++.old-deja/g++.mike/ns7.C
+++ b/gcc/testsuite/g++.old-deja/g++.mike/ns7.C
@@ -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'" }
}
diff --git a/gcc/testsuite/g++.old-deja/g++.ns/koenig5.C b/gcc/testsuite/g++.old-deja/g++.ns/koenig5.C
index 2246f8a..4461d13 100644
--- a/gcc/testsuite/g++.old-deja/g++.ns/koenig5.C
+++ b/gcc/testsuite/g++.old-deja/g++.ns/koenig5.C
@@ -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'" }
}
diff --git a/gcc/testsuite/g++.old-deja/g++.other/lineno5.C b/gcc/testsuite/g++.old-deja/g++.other/lineno5.C
index 63dc0b4..1865f11 100644
--- a/gcc/testsuite/g++.old-deja/g++.other/lineno5.C
+++ b/gcc/testsuite/g++.old-deja/g++.other/lineno5.C
@@ -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'" }
};
diff --git a/include/unique-ptr.h b/include/unique-ptr.h
index a12c219..2c664b7 100644
--- a/include/unique-ptr.h
+++ b/include/unique-ptr.h
@@ -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 requires T
+ to have 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>
+T
+move (T &v)
{
return v;
}
diff --git a/libstdc++-v3/testsuite/17_intro/using_namespace_std_exp_neg.cc b/libstdc++-v3/testsuite/17_intro/using_namespace_std_exp_neg.cc
index 5821f2f..2bf8f12 100644
--- a/libstdc++-v3/testsuite/17_intro/using_namespace_std_exp_neg.cc
+++ b/libstdc++-v3/testsuite/17_intro/using_namespace_std_exp_neg.cc
@@ -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 }
diff --git a/libstdc++-v3/testsuite/17_intro/using_namespace_std_tr1_neg.cc b/libstdc++-v3/testsuite/17_intro/using_namespace_std_tr1_neg.cc
index aad4894..8a1527c 100644
--- a/libstdc++-v3/testsuite/17_intro/using_namespace_std_tr1_neg.cc
+++ b/libstdc++-v3/testsuite/17_intro/using_namespace_std_tr1_neg.cc
@@ -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 }
--
1.8.5.3
^ permalink raw reply [flat|nested] 8+ messages in thread
* Re: [PATCH] v2: C++: simplify output from suggest_alternatives_for
2018-10-11 14:39 ` Jason Merrill
@ 2018-10-11 14:39 ` Jason Merrill
2018-10-12 0:25 ` [PATCH] v3: " David Malcolm
0 siblings, 1 reply; 8+ messages in thread
From: Jason Merrill @ 2018-10-11 14:39 UTC (permalink / raw)
To: David Malcolm; +Cc: gcc-patches List
On Thu, Oct 11, 2018 at 10:28 AM Jason Merrill <jason@redhat.com> wrote:
>
> On Wed, Oct 10, 2018 at 5:01 PM David Malcolm <dmalcolm@redhat.com> wrote:
> > On Tue, 2018-10-09 at 18:38 -0400, Jason Merrill wrote:
> > > On Tue, Oct 9, 2018 at 1:19 PM David Malcolm <dmalcolm@redhat.com>
> > > wrote:
> > > > + /* Emulation of a "move" constructor, but really a copy
> > > > + constructor. */
> > > > +
> > > > + name_hint (const name_hint &other)
> > > > + : m_suggestion (other.m_suggestion),
> > > > + m_deferred (const_cast<name_hint &> (other).take_deferred ())
> > > > + {
> > > > + }
> > > > +
> > > > + /* Emulation of "move" assigment, but really copy
> > > > assignment. */
> > > > +
> > > > + name_hint& operator= (const name_hint &other)
> > > > + {
> > > > + m_suggestion = other.m_suggestion;
> > > > + m_deferred = const_cast<name_hint &> (other).take_deferred ();
> > > > + return *this;
> > > > + }
> > > > +
> > > > + /* 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); }
> > >
> > > Why do you want to propagate this hackery into name_hint? I would
> > > expect the defaulted special member functions to do the right thing
> > > with m_deferred: in -std=c++98 the implicit copy ops call the
> > > gnu::unique_ptr copy ops that actually move, and in -std=c++11 and up
> > > we're calling the move constructor for std::unique_ptr, which does
> > > the
> > > right thing.
> > >
> > > This also doesn't limit the hack to C++98 mode the way unique-ptr.h
> > > does.
> > >
> > > Jason
> >
> > Thanks for looking at this.
> >
> > I ran into issues trying to pass around name_hint instances:
> >
> > ../../src/gcc/cp/name-lookup.c: In function 'name_hint suggest_alternatives_in_other_namespaces(location_t, tree)':
> > ../../src/gcc/cp/name-lookup.c:5591:52: error: use of deleted function 'name_hint::name_hint(const name_hint&)'
> > 5591 | return ns_hints.maybe_decorate_with_limit (result);
> > | ^
> > In file included from ../../src/gcc/cp/name-lookup.c:36:
> > ../../src/gcc/c-family/name-hint.h:91:7: note: 'name_hint::name_hint(const name_hint&)' is implicitly deleted because the default definition would be ill-formed:
> > 91 | class name_hint
> > | ^~~~~~~~~
> > ../../src/gcc/c-family/name-hint.h:91:7: error: use of deleted function 'std::unique_ptr<_Tp, _Dp>::unique_ptr(const std::unique_ptr<_Tp, _Dp>&) [with _Tp = deferred_diagnostic; _Dp = std::default_delete<deferred_diagnostic>]'
> > In file included from /home/david/coding/gcc-python/gcc-svn-trunk/install-dogfood/include/c++/9.0.0/memory:80,
> > from ../../src/gcc/../include/unique-ptr.h:78,
> > from ../../src/gcc/system.h:730,
> > from ../../src/gcc/cp/name-lookup.c:23:
> > /home/david/coding/gcc-python/gcc-svn-trunk/install-dogfood/include/c++/9.0.0/bits/unique_ptr.h:394:7: note: declared here
> > 394 | unique_ptr(const unique_ptr&) = delete;
> > | ^~~~~~~~~~
> > ../../src/gcc/cp/name-lookup.c:5512:1: note: initializing argument 1 of 'name_hint namespace_hints::maybe_decorate_with_limit(name_hint)'
> > 5512 | namespace_hints::maybe_decorate_with_limit (name_hint hint)
> > | ^~~~~~~~~~~~~~~
> >
> > I can't use the default copy constructor or assignment operators for an
> > object containing a gnu::unique_ptr on C++11, as std::unique_ptr has:
> >
> > // Disable copy from lvalue.
> > unique_ptr(const unique_ptr&) = delete;
> > unique_ptr& operator=(const unique_ptr&) = delete;
> >
> > If I understand things right, in C++11 I should be using move
> > construction/move assignment for this.
> >
> > I can't write "&&" in the function params to explicitly request an
> > rvalue-reference, as the code need to be compatible with C++98.
> >
> > std::move is only defined in C++11 onwards.
> >
> > Our include/unique-ptr.h defines a gnu::move: for C++11 it's std::move,
> > but for C++98 it's only defined for the unique_ptr template.
> >
> > A solution that seems to work appears to be to define gnu::move for
> > C++98 for all types rather than just gnu::unique_ptr, implementing it
> > in terms of copying an object via lvalue reference, so that we can
> > explicitly request a move using "gnu::move" (==std::move on C++),
> > without using C++11 syntax, and falling back to a copy on C++98
> > (which effectively moves the ptr from the "victim").
> >
> > Does that sound sane?
>
> I wouldn't change the unique-ptr.h move to take all types, given that
> it copies rather than just passing the reference through, which could
> be expensive for unsuspecting users. And given how it subverts the
> C++98 type system, I'd rather explicitly opt into it. So, let's
> overload it for name_hint. And I'd probably return a reference, e.g.
>
> #if __cplusplus < 201103
> // std::move emulation to support the use of gnu::unique_ptr in name_hint.
> namespace gnu {
> inline const name_hint &
> move(name_hint &m) { return m; }
> }
> #endif
>
> to avoid the unnecessary copy. Actually, I'd be inclined to do that
> for gnu::unique_ptr as well, but would want to make sure that it
> doesn't break gdb.
And if we made that change to the unique-ptr.h version, i.e.
template<typename T>
const T&
move (T& v)
{
return v;
}
then adding an overload for name_hint wouldn't be necessary.
Jason
^ permalink raw reply [flat|nested] 8+ messages in thread
* Re: [PATCH] v2: C++: simplify output from suggest_alternatives_for
2018-10-10 21:18 ` [PATCH] v2: " David Malcolm
@ 2018-10-11 14:39 ` Jason Merrill
2018-10-11 14:39 ` Jason Merrill
0 siblings, 1 reply; 8+ messages in thread
From: Jason Merrill @ 2018-10-11 14:39 UTC (permalink / raw)
To: David Malcolm; +Cc: gcc-patches List
On Wed, Oct 10, 2018 at 5:01 PM David Malcolm <dmalcolm@redhat.com> wrote:
> On Tue, 2018-10-09 at 18:38 -0400, Jason Merrill wrote:
> > On Tue, Oct 9, 2018 at 1:19 PM David Malcolm <dmalcolm@redhat.com>
> > wrote:
> > > + /* Emulation of a "move" constructor, but really a copy
> > > + constructor. */
> > > +
> > > + name_hint (const name_hint &other)
> > > + : m_suggestion (other.m_suggestion),
> > > + m_deferred (const_cast<name_hint &> (other).take_deferred ())
> > > + {
> > > + }
> > > +
> > > + /* Emulation of "move" assigment, but really copy
> > > assignment. */
> > > +
> > > + name_hint& operator= (const name_hint &other)
> > > + {
> > > + m_suggestion = other.m_suggestion;
> > > + m_deferred = const_cast<name_hint &> (other).take_deferred ();
> > > + return *this;
> > > + }
> > > +
> > > + /* 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); }
> >
> > Why do you want to propagate this hackery into name_hint? I would
> > expect the defaulted special member functions to do the right thing
> > with m_deferred: in -std=c++98 the implicit copy ops call the
> > gnu::unique_ptr copy ops that actually move, and in -std=c++11 and up
> > we're calling the move constructor for std::unique_ptr, which does
> > the
> > right thing.
> >
> > This also doesn't limit the hack to C++98 mode the way unique-ptr.h
> > does.
> >
> > Jason
>
> Thanks for looking at this.
>
> I ran into issues trying to pass around name_hint instances:
>
> ../../src/gcc/cp/name-lookup.c: In function 'name_hint suggest_alternatives_in_other_namespaces(location_t, tree)':
> ../../src/gcc/cp/name-lookup.c:5591:52: error: use of deleted function 'name_hint::name_hint(const name_hint&)'
> 5591 | return ns_hints.maybe_decorate_with_limit (result);
> | ^
> In file included from ../../src/gcc/cp/name-lookup.c:36:
> ../../src/gcc/c-family/name-hint.h:91:7: note: 'name_hint::name_hint(const name_hint&)' is implicitly deleted because the default definition would be ill-formed:
> 91 | class name_hint
> | ^~~~~~~~~
> ../../src/gcc/c-family/name-hint.h:91:7: error: use of deleted function 'std::unique_ptr<_Tp, _Dp>::unique_ptr(const std::unique_ptr<_Tp, _Dp>&) [with _Tp = deferred_diagnostic; _Dp = std::default_delete<deferred_diagnostic>]'
> In file included from /home/david/coding/gcc-python/gcc-svn-trunk/install-dogfood/include/c++/9.0.0/memory:80,
> from ../../src/gcc/../include/unique-ptr.h:78,
> from ../../src/gcc/system.h:730,
> from ../../src/gcc/cp/name-lookup.c:23:
> /home/david/coding/gcc-python/gcc-svn-trunk/install-dogfood/include/c++/9.0.0/bits/unique_ptr.h:394:7: note: declared here
> 394 | unique_ptr(const unique_ptr&) = delete;
> | ^~~~~~~~~~
> ../../src/gcc/cp/name-lookup.c:5512:1: note: initializing argument 1 of 'name_hint namespace_hints::maybe_decorate_with_limit(name_hint)'
> 5512 | namespace_hints::maybe_decorate_with_limit (name_hint hint)
> | ^~~~~~~~~~~~~~~
>
> I can't use the default copy constructor or assignment operators for an
> object containing a gnu::unique_ptr on C++11, as std::unique_ptr has:
>
> // Disable copy from lvalue.
> unique_ptr(const unique_ptr&) = delete;
> unique_ptr& operator=(const unique_ptr&) = delete;
>
> If I understand things right, in C++11 I should be using move
> construction/move assignment for this.
>
> I can't write "&&" in the function params to explicitly request an
> rvalue-reference, as the code need to be compatible with C++98.
>
> std::move is only defined in C++11 onwards.
>
> Our include/unique-ptr.h defines a gnu::move: for C++11 it's std::move,
> but for C++98 it's only defined for the unique_ptr template.
>
> A solution that seems to work appears to be to define gnu::move for
> C++98 for all types rather than just gnu::unique_ptr, implementing it
> in terms of copying an object via lvalue reference, so that we can
> explicitly request a move using "gnu::move" (==std::move on C++),
> without using C++11 syntax, and falling back to a copy on C++98
> (which effectively moves the ptr from the "victim").
>
> Does that sound sane?
I wouldn't change the unique-ptr.h move to take all types, given that
it copies rather than just passing the reference through, which could
be expensive for unsuspecting users. And given how it subverts the
C++98 type system, I'd rather explicitly opt into it. So, let's
overload it for name_hint. And I'd probably return a reference, e.g.
#if __cplusplus < 201103
// std::move emulation to support the use of gnu::unique_ptr in name_hint.
namespace gnu {
inline const name_hint &
move(name_hint &m) { return m; }
}
#endif
to avoid the unnecessary copy. Actually, I'd be inclined to do that
for gnu::unique_ptr as well, but would want to make sure that it
doesn't break gdb.
Jason
^ permalink raw reply [flat|nested] 8+ messages in thread
* [PATCH] v3: C++: simplify output from suggest_alternatives_for
2018-10-11 14:39 ` Jason Merrill
@ 2018-10-12 0:25 ` David Malcolm
2018-10-25 19:07 ` Jason Merrill
0 siblings, 1 reply; 8+ messages in thread
From: David Malcolm @ 2018-10-12 0:25 UTC (permalink / raw)
To: Jason Merrill; +Cc: gcc-patches List, David Malcolm
On Thu, 2018-10-11 at 10:31 -0400, Jason Merrill wrote:
> On Thu, Oct 11, 2018 at 10:28 AM Jason Merrill <jason@redhat.com>
> wrote:
> >
> > On Wed, Oct 10, 2018 at 5:01 PM David Malcolm <dmalcolm@redhat.com>
> > wrote:
> > > On Tue, 2018-10-09 at 18:38 -0400, Jason Merrill wrote:
> > > > On Tue, Oct 9, 2018 at 1:19 PM David Malcolm <dmalcolm@redhat.c
> > > > om>
> > > > wrote:
> > > > > + /* Emulation of a "move" constructor, but really a copy
> > > > > + constructor. */
> > > > > +
> > > > > + name_hint (const name_hint &other)
> > > > > + : m_suggestion (other.m_suggestion),
> > > > > + m_deferred (const_cast<name_hint &>
> > > > > (other).take_deferred ())
> > > > > + {
> > > > > + }
> > > > > +
> > > > > + /* Emulation of "move" assigment, but really copy
> > > > > assignment. */
> > > > > +
> > > > > + name_hint& operator= (const name_hint &other)
> > > > > + {
> > > > > + m_suggestion = other.m_suggestion;
> > > > > + m_deferred = const_cast<name_hint &>
> > > > > (other).take_deferred ();
> > > > > + return *this;
> > > > > + }
> > > > > +
> > > > > + /* 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); }
> > > >
> > > > Why do you want to propagate this hackery into name_hint? I
> > > > would
> > > > expect the defaulted special member functions to do the right
> > > > thing
> > > > with m_deferred: in -std=c++98 the implicit copy ops call the
> > > > gnu::unique_ptr copy ops that actually move, and in -std=c++11
> > > > and up
> > > > we're calling the move constructor for std::unique_ptr, which
> > > > does
> > > > the
> > > > right thing.
> > > >
> > > > This also doesn't limit the hack to C++98 mode the way unique-
> > > > ptr.h
> > > > does.
> > > >
> > > > Jason
> > >
> > > Thanks for looking at this.
> > >
> > > I ran into issues trying to pass around name_hint instances:
> > >
> > > ../../src/gcc/cp/name-lookup.c: In function 'name_hint
> > > suggest_alternatives_in_other_namespaces(location_t, tree)':
> > > ../../src/gcc/cp/name-lookup.c:5591:52: error: use of deleted
> > > function 'name_hint::name_hint(const name_hint&)'
> > > 5591 | return ns_hints.maybe_decorate_with_limit (result);
> > > | ^
> > > In file included from ../../src/gcc/cp/name-lookup.c:36:
> > > ../../src/gcc/c-family/name-hint.h:91:7: note:
> > > 'name_hint::name_hint(const name_hint&)' is implicitly deleted
> > > because the default definition would be ill-formed:
> > > 91 | class name_hint
> > > | ^~~~~~~~~
> > > ../../src/gcc/c-family/name-hint.h:91:7: error: use of deleted
> > > function 'std::unique_ptr<_Tp, _Dp>::unique_ptr(const
> > > std::unique_ptr<_Tp, _Dp>&) [with _Tp = deferred_diagnostic; _Dp
> > > = std::default_delete<deferred_diagnostic>]'
> > > In file included from /home/david/coding/gcc-python/gcc-svn-
> > > trunk/install-dogfood/include/c++/9.0.0/memory:80,
> > > from ../../src/gcc/../include/unique-ptr.h:78,
> > > from ../../src/gcc/system.h:730,
> > > from ../../src/gcc/cp/name-lookup.c:23:
> > > /home/david/coding/gcc-python/gcc-svn-trunk/install-
> > > dogfood/include/c++/9.0.0/bits/unique_ptr.h:394:7: note: declared
> > > here
> > > 394 | unique_ptr(const unique_ptr&) = delete;
> > > | ^~~~~~~~~~
> > > ../../src/gcc/cp/name-lookup.c:5512:1: note: initializing
> > > argument 1 of 'name_hint
> > > namespace_hints::maybe_decorate_with_limit(name_hint)'
> > > 5512 | namespace_hints::maybe_decorate_with_limit (name_hint
> > > hint)
> > > | ^~~~~~~~~~~~~~~
> > >
> > > I can't use the default copy constructor or assignment operators
> > > for an
> > > object containing a gnu::unique_ptr on C++11, as std::unique_ptr
> > > has:
> > >
> > > // Disable copy from lvalue.
> > > unique_ptr(const unique_ptr&) = delete;
> > > unique_ptr& operator=(const unique_ptr&) = delete;
> > >
> > > If I understand things right, in C++11 I should be using move
> > > construction/move assignment for this.
> > >
> > > I can't write "&&" in the function params to explicitly request
> > > an
> > > rvalue-reference, as the code need to be compatible with C++98.
> > >
> > > std::move is only defined in C++11 onwards.
> > >
> > > Our include/unique-ptr.h defines a gnu::move: for C++11 it's
> > > std::move,
> > > but for C++98 it's only defined for the unique_ptr template.
> > >
> > > A solution that seems to work appears to be to define gnu::move
> > > for
> > > C++98 for all types rather than just gnu::unique_ptr,
> > > implementing it
> > > in terms of copying an object via lvalue reference, so that we
> > > can
> > > explicitly request a move using "gnu::move" (==std::move on C++),
> > > without using C++11 syntax, and falling back to a copy on C++98
> > > (which effectively moves the ptr from the "victim").
> > >
> > > Does that sound sane?
> >
> > I wouldn't change the unique-ptr.h move to take all types, given
> > that
> > it copies rather than just passing the reference through, which
> > could
> > be expensive for unsuspecting users. And given how it subverts the
> > C++98 type system, I'd rather explicitly opt into it. So, let's
> > overload it for name_hint. And I'd probably return a reference,
> > e.g.
> >
> > #if __cplusplus < 201103
> > // std::move emulation to support the use of gnu::unique_ptr in
> > name_hint.
> > namespace gnu {
> > inline const name_hint &
> > move(name_hint &m) { return m; }
> > }
> > #endif
> >
> > to avoid the unnecessary copy. Actually, I'd be inclined to do
> > that
> > for gnu::unique_ptr as well, but would want to make sure that it
> > doesn't break gdb.
>
> And if we made that change to the unique-ptr.h version, i.e.
>
> template<typename T>
> const T&
> move (T& v)
> {
> return v;
> }
>
> then adding an overload for name_hint wouldn't be necessary.
>
> Jason
Thanks! Here's an updated version which uses the above.
Successfully bootstrapped & regrtested on x86_64-pc-linux-gnu
As before I also tested non-bootstrap builds with both gcc 4.8 and with
trunk (to build without and with C++11), running various testcases
under valgrind.
OK for trunk?
Changed in v3:
* use Jason's proposed implementation of gnu::move for pre-C++11:
template<typename T>
const T&
move (T& v)
{
return v;
}
Changed in v2:
* dropped addition of name_hint copy ctor and copy assignment in
favor of using gnu::move wherever move assignment needs to happen
or be emulated
* generalized gnu::move for pre-C++11 to apply to all lvalue references,
rather than just to gnu::unique_ptr
* drop stray !DECL_P identified by Jason
Blurb from v1:
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
Successfully bootstrapped & regrtested on x86_64-pc-linux-gnu
(on top of
https://gcc.gnu.org/ml/gcc-patches/2018-09/msg01272.html
"v2: C++: suggestions for misspelled private members (PR c++/84993)")
OK for trunk?
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.
---
gcc/c-family/name-hint.h | 9 +-
gcc/c/c-decl.c | 24 +-
gcc/c/c-parser.c | 12 +-
gcc/cp/cp-name-hint.h | 37 ++
gcc/cp/cp-tree.h | 3 +-
gcc/cp/error.c | 43 ++-
gcc/cp/lex.c | 17 +-
gcc/cp/name-lookup.c | 407 ++++++++++++++++-----
gcc/cp/parser.c | 83 ++++-
gcc/testsuite/c-c++-common/spellcheck-reserved.c | 9 +-
gcc/testsuite/g++.dg/ext/builtin3.C | 3 +-
gcc/testsuite/g++.dg/lookup/error1.C | 3 +-
gcc/testsuite/g++.dg/lookup/pr77549.C | 15 +-
gcc/testsuite/g++.dg/lookup/pr80913.C | 3 +-
gcc/testsuite/g++.dg/lookup/suggestions1.C | 8 +-
gcc/testsuite/g++.dg/lookup/suggestions2.C | 128 +++++++
gcc/testsuite/g++.dg/overload/koenig1.C | 3 +-
gcc/testsuite/g++.dg/spellcheck-identifiers-2.C | 14 +-
gcc/testsuite/g++.dg/spellcheck-identifiers.C | 98 +----
gcc/testsuite/g++.dg/spellcheck-ns.C | 22 ++
gcc/testsuite/g++.dg/spellcheck-pr77829.C | 51 +--
gcc/testsuite/g++.dg/spellcheck-pr78656.C | 14 +-
gcc/testsuite/g++.dg/spellcheck-pr79298.C | 13 +-
gcc/testsuite/g++.dg/spellcheck-pr80177.C | 9 +-
.../g++.dg/spellcheck-single-vs-multiple.C | 79 ++++
gcc/testsuite/g++.dg/spellcheck-typenames.C | 10 +-
gcc/testsuite/g++.dg/template/static10.C | 4 +-
gcc/testsuite/g++.old-deja/g++.mike/ns5.C | 3 +-
gcc/testsuite/g++.old-deja/g++.mike/ns7.C | 3 +-
gcc/testsuite/g++.old-deja/g++.ns/koenig5.C | 3 +-
gcc/testsuite/g++.old-deja/g++.other/lineno5.C | 3 +-
include/unique-ptr.h | 12 +-
.../17_intro/using_namespace_std_exp_neg.cc | 2 -
.../17_intro/using_namespace_std_tr1_neg.cc | 2 -
34 files changed, 793 insertions(+), 356 deletions(-)
create mode 100644 gcc/cp/cp-name-hint.h
create mode 100644 gcc/testsuite/g++.dg/lookup/suggestions2.C
create mode 100644 gcc/testsuite/g++.dg/spellcheck-ns.C
create mode 100644 gcc/testsuite/g++.dg/spellcheck-single-vs-multiple.C
diff --git a/gcc/c-family/name-hint.h b/gcc/c-family/name-hint.h
index ef0e4a3..ddc3525 100644
--- a/gcc/c-family/name-hint.h
+++ b/gcc/c-family/name-hint.h
@@ -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. */
diff --git a/gcc/c/c-decl.c b/gcc/c/c-decl.c
index 160ce35..cbbf7eb 100644
--- a/gcc/c/c-decl.c
+++ b/gcc/c/c-decl.c
@@ -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);
diff --git a/gcc/c/c-parser.c b/gcc/c/c-parser.c
index 1f173fc..46dd366 100644
--- a/gcc/c/c-parser.c
+++ b/gcc/c/c-parser.c
@@ -1817,12 +1817,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);
@@ -4054,13 +4054,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);
diff --git a/gcc/cp/cp-name-hint.h b/gcc/cp/cp-name-hint.h
new file mode 100644
index 0000000..5d1cdc3
--- /dev/null
+++ b/gcc/cp/cp-name-hint.h
@@ -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 */
diff --git a/gcc/cp/cp-tree.h b/gcc/cp/cp-tree.h
index 26ded3a..8454cb4 100644
--- a/gcc/cp/cp-tree.h
+++ b/gcc/cp/cp-tree.h
@@ -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. */
diff --git a/gcc/cp/error.c b/gcc/cp/error.c
index 0b14dcc..fa115aa 100644
--- a/gcc/cp/error.c
+++ b/gcc/cp/error.c
@@ -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);
}
}
diff --git a/gcc/cp/lex.c b/gcc/cp/lex.c
index 47b99c3..410dfd1 100644
--- a/gcc/cp/lex.c
+++ b/gcc/cp/lex.c
@@ -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. */
diff --git a/gcc/cp/name-lookup.c b/gcc/cp/name-lookup.c
index 08632c3..5b026da 100644
--- a/gcc/cp/name-lookup.c
+++ b/gcc/cp/name-lookup.c
@@ -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
diff --git a/gcc/cp/parser.c b/gcc/cp/parser.c
index 032108a..21c3892 100644
--- a/gcc/cp/parser.c
+++ b/gcc/cp/parser.c
@@ -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. */
@@ -3293,13 +3293,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);
@@ -3365,23 +3365,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))
@@ -18635,13 +18665,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;
}
diff --git a/gcc/testsuite/c-c++-common/spellcheck-reserved.c b/gcc/testsuite/c-c++-common/spellcheck-reserved.c
index 79b6532..ed292f2 100644
--- a/gcc/testsuite/c-c++-common/spellcheck-reserved.c
+++ b/gcc/testsuite/c-c++-common/spellcheck-reserved.c
@@ -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_ } */
}
diff --git a/gcc/testsuite/g++.dg/ext/builtin3.C b/gcc/testsuite/g++.dg/ext/builtin3.C
index 6becaa0..31d2ac6 100644
--- a/gcc/testsuite/g++.dg/ext/builtin3.C
+++ b/gcc/testsuite/g++.dg/ext/builtin3.C
@@ -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'\\?" }
}
diff --git a/gcc/testsuite/g++.dg/lookup/error1.C b/gcc/testsuite/g++.dg/lookup/error1.C
index d2741fb..1f267e7 100644
--- a/gcc/testsuite/g++.dg/lookup/error1.C
+++ b/gcc/testsuite/g++.dg/lookup/error1.C
@@ -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; }
diff --git a/gcc/testsuite/g++.dg/lookup/pr77549.C b/gcc/testsuite/g++.dg/lookup/pr77549.C
index b4b8d0e..af7c630 100644
--- a/gcc/testsuite/g++.dg/lookup/pr77549.C
+++ b/gcc/testsuite/g++.dg/lookup/pr77549.C
@@ -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'\\?" }
+}
diff --git a/gcc/testsuite/g++.dg/lookup/pr80913.C b/gcc/testsuite/g++.dg/lookup/pr80913.C
index a7866bc..028e61a 100644
--- a/gcc/testsuite/g++.dg/lookup/pr80913.C
+++ b/gcc/testsuite/g++.dg/lookup/pr80913.C
@@ -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'\\?" }
}
diff --git a/gcc/testsuite/g++.dg/lookup/suggestions1.C b/gcc/testsuite/g++.dg/lookup/suggestions1.C
index da98d11c..47126a3 100644
--- a/gcc/testsuite/g++.dg/lookup/suggestions1.C
+++ b/gcc/testsuite/g++.dg/lookup/suggestions1.C
@@ -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
index 0000000..900439f
--- /dev/null
+++ b/gcc/testsuite/g++.dg/lookup/suggestions2.C
@@ -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 "" } */
+}
diff --git a/gcc/testsuite/g++.dg/overload/koenig1.C b/gcc/testsuite/g++.dg/overload/koenig1.C
index 3c1c293..5508061 100644
--- a/gcc/testsuite/g++.dg/overload/koenig1.C
+++ b/gcc/testsuite/g++.dg/overload/koenig1.C
@@ -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);
}
diff --git a/gcc/testsuite/g++.dg/spellcheck-identifiers-2.C b/gcc/testsuite/g++.dg/spellcheck-identifiers-2.C
index 59a8ec5..67ae52b 100644
--- a/gcc/testsuite/g++.dg/spellcheck-identifiers-2.C
+++ b/gcc/testsuite/g++.dg/spellcheck-identifiers-2.C
@@ -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);
^~~~~
diff --git a/gcc/testsuite/g++.dg/spellcheck-identifiers.C b/gcc/testsuite/g++.dg/spellcheck-identifiers.C
index e4a606e..a9521af 100644
--- a/gcc/testsuite/g++.dg/spellcheck-identifiers.C
+++ b/gcc/testsuite/g++.dg/spellcheck-identifiers.C
@@ -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,29 +101,19 @@ 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:
- ^~~~~~~~~~~
FOO_SECOND
{ dg-end-multiline-output "" } */
@@ -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
index 0000000..4f7452a
--- /dev/null
+++ b/gcc/testsuite/g++.dg/spellcheck-ns.C
@@ -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 "" } */
diff --git a/gcc/testsuite/g++.dg/spellcheck-pr77829.C b/gcc/testsuite/g++.dg/spellcheck-pr77829.C
index 2f75779..1707134 100644
--- a/gcc/testsuite/g++.dg/spellcheck-pr77829.C
+++ b/gcc/testsuite/g++.dg/spellcheck-pr77829.C
@@ -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;
^~~~~~~~~~~~
diff --git a/gcc/testsuite/g++.dg/spellcheck-pr78656.C b/gcc/testsuite/g++.dg/spellcheck-pr78656.C
index ded4bb6..ead4e08 100644
--- a/gcc/testsuite/g++.dg/spellcheck-pr78656.C
+++ b/gcc/testsuite/g++.dg/spellcheck-pr78656.C
@@ -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);
^~~~~~~~
diff --git a/gcc/testsuite/g++.dg/spellcheck-pr79298.C b/gcc/testsuite/g++.dg/spellcheck-pr79298.C
index 4d7bbf9..7016ee5 100644
--- a/gcc/testsuite/g++.dg/spellcheck-pr79298.C
+++ b/gcc/testsuite/g++.dg/spellcheck-pr79298.C
@@ -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 "" } */
}
diff --git a/gcc/testsuite/g++.dg/spellcheck-pr80177.C b/gcc/testsuite/g++.dg/spellcheck-pr80177.C
index 2ff24e8..7367887 100644
--- a/gcc/testsuite/g++.dg/spellcheck-pr80177.C
+++ b/gcc/testsuite/g++.dg/spellcheck-pr80177.C
@@ -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
index 0000000..7d9b87a1
--- /dev/null
+++ b/gcc/testsuite/g++.dg/spellcheck-single-vs-multiple.C
@@ -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 "" } */
+}
diff --git a/gcc/testsuite/g++.dg/spellcheck-typenames.C b/gcc/testsuite/g++.dg/spellcheck-typenames.C
index 01bcf78..25d3f1d 100644
--- a/gcc/testsuite/g++.dg/spellcheck-typenames.C
+++ b/gcc/testsuite/g++.dg/spellcheck-typenames.C
@@ -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);
^~~
diff --git a/gcc/testsuite/g++.dg/template/static10.C b/gcc/testsuite/g++.dg/template/static10.C
index 5740ac4..36fed38 100644
--- a/gcc/testsuite/g++.dg/template/static10.C
+++ b/gcc/testsuite/g++.dg/template/static10.C
@@ -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 }
}
diff --git a/gcc/testsuite/g++.old-deja/g++.mike/ns5.C b/gcc/testsuite/g++.old-deja/g++.mike/ns5.C
index 3d317bf..832b5e8 100644
--- a/gcc/testsuite/g++.old-deja/g++.mike/ns5.C
+++ b/gcc/testsuite/g++.old-deja/g++.mike/ns5.C
@@ -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'" }
diff --git a/gcc/testsuite/g++.old-deja/g++.mike/ns7.C b/gcc/testsuite/g++.old-deja/g++.mike/ns7.C
index 14a38b6..6f9e6d2 100644
--- a/gcc/testsuite/g++.old-deja/g++.mike/ns7.C
+++ b/gcc/testsuite/g++.old-deja/g++.mike/ns7.C
@@ -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'" }
}
diff --git a/gcc/testsuite/g++.old-deja/g++.ns/koenig5.C b/gcc/testsuite/g++.old-deja/g++.ns/koenig5.C
index 2246f8a..4461d13 100644
--- a/gcc/testsuite/g++.old-deja/g++.ns/koenig5.C
+++ b/gcc/testsuite/g++.old-deja/g++.ns/koenig5.C
@@ -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'" }
}
diff --git a/gcc/testsuite/g++.old-deja/g++.other/lineno5.C b/gcc/testsuite/g++.old-deja/g++.other/lineno5.C
index 63dc0b4..1865f11 100644
--- a/gcc/testsuite/g++.old-deja/g++.other/lineno5.C
+++ b/gcc/testsuite/g++.old-deja/g++.other/lineno5.C
@@ -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'" }
};
diff --git a/include/unique-ptr.h b/include/unique-ptr.h
index a12c219..a7255fc 100644
--- a/include/unique-ptr.h
+++ b/include/unique-ptr.h
@@ -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;
}
diff --git a/libstdc++-v3/testsuite/17_intro/using_namespace_std_exp_neg.cc b/libstdc++-v3/testsuite/17_intro/using_namespace_std_exp_neg.cc
index 5821f2f..2bf8f12 100644
--- a/libstdc++-v3/testsuite/17_intro/using_namespace_std_exp_neg.cc
+++ b/libstdc++-v3/testsuite/17_intro/using_namespace_std_exp_neg.cc
@@ -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 }
diff --git a/libstdc++-v3/testsuite/17_intro/using_namespace_std_tr1_neg.cc b/libstdc++-v3/testsuite/17_intro/using_namespace_std_tr1_neg.cc
index aad4894..8a1527c 100644
--- a/libstdc++-v3/testsuite/17_intro/using_namespace_std_tr1_neg.cc
+++ b/libstdc++-v3/testsuite/17_intro/using_namespace_std_tr1_neg.cc
@@ -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 }
--
1.8.5.3
^ permalink raw reply [flat|nested] 8+ messages in thread
* Re: [PATCH] v3: C++: simplify output from suggest_alternatives_for
2018-10-12 0:25 ` [PATCH] v3: " David Malcolm
@ 2018-10-25 19:07 ` Jason Merrill
0 siblings, 0 replies; 8+ messages in thread
From: Jason Merrill @ 2018-10-25 19:07 UTC (permalink / raw)
To: David Malcolm; +Cc: gcc-patches List
On 10/11/18 8:07 PM, David Malcolm wrote:
> On Thu, 2018-10-11 at 10:31 -0400, Jason Merrill wrote:
>> On Thu, Oct 11, 2018 at 10:28 AM Jason Merrill <jason@redhat.com>
>> wrote:
>>>
>>> On Wed, Oct 10, 2018 at 5:01 PM David Malcolm <dmalcolm@redhat.com>
>>> wrote:
>>>> On Tue, 2018-10-09 at 18:38 -0400, Jason Merrill wrote:
>>>>> On Tue, Oct 9, 2018 at 1:19 PM David Malcolm <dmalcolm@redhat.c
>>>>> om>
>>>>> wrote:
>>>>>> + /* Emulation of a "move" constructor, but really a copy
>>>>>> + constructor. */
>>>>>> +
>>>>>> + name_hint (const name_hint &other)
>>>>>> + : m_suggestion (other.m_suggestion),
>>>>>> + m_deferred (const_cast<name_hint &>
>>>>>> (other).take_deferred ())
>>>>>> + {
>>>>>> + }
>>>>>> +
>>>>>> + /* Emulation of "move" assigment, but really copy
>>>>>> assignment. */
>>>>>> +
>>>>>> + name_hint& operator= (const name_hint &other)
>>>>>> + {
>>>>>> + m_suggestion = other.m_suggestion;
>>>>>> + m_deferred = const_cast<name_hint &>
>>>>>> (other).take_deferred ();
>>>>>> + return *this;
>>>>>> + }
>>>>>> +
>>>>>> + /* 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); }
>>>>>
>>>>> Why do you want to propagate this hackery into name_hint? I
>>>>> would
>>>>> expect the defaulted special member functions to do the right
>>>>> thing
>>>>> with m_deferred: in -std=c++98 the implicit copy ops call the
>>>>> gnu::unique_ptr copy ops that actually move, and in -std=c++11
>>>>> and up
>>>>> we're calling the move constructor for std::unique_ptr, which
>>>>> does
>>>>> the
>>>>> right thing.
>>>>>
>>>>> This also doesn't limit the hack to C++98 mode the way unique-
>>>>> ptr.h
>>>>> does.
>>>>>
>>>>> Jason
>>>>
>>>> Thanks for looking at this.
>>>>
>>>> I ran into issues trying to pass around name_hint instances:
>>>>
>>>> ../../src/gcc/cp/name-lookup.c: In function 'name_hint
>>>> suggest_alternatives_in_other_namespaces(location_t, tree)':
>>>> ../../src/gcc/cp/name-lookup.c:5591:52: error: use of deleted
>>>> function 'name_hint::name_hint(const name_hint&)'
>>>> 5591 | return ns_hints.maybe_decorate_with_limit (result);
>>>> | ^
>>>> In file included from ../../src/gcc/cp/name-lookup.c:36:
>>>> ../../src/gcc/c-family/name-hint.h:91:7: note:
>>>> 'name_hint::name_hint(const name_hint&)' is implicitly deleted
>>>> because the default definition would be ill-formed:
>>>> 91 | class name_hint
>>>> | ^~~~~~~~~
>>>> ../../src/gcc/c-family/name-hint.h:91:7: error: use of deleted
>>>> function 'std::unique_ptr<_Tp, _Dp>::unique_ptr(const
>>>> std::unique_ptr<_Tp, _Dp>&) [with _Tp = deferred_diagnostic; _Dp
>>>> = std::default_delete<deferred_diagnostic>]'
>>>> In file included from /home/david/coding/gcc-python/gcc-svn-
>>>> trunk/install-dogfood/include/c++/9.0.0/memory:80,
>>>> from ../../src/gcc/../include/unique-ptr.h:78,
>>>> from ../../src/gcc/system.h:730,
>>>> from ../../src/gcc/cp/name-lookup.c:23:
>>>> /home/david/coding/gcc-python/gcc-svn-trunk/install-
>>>> dogfood/include/c++/9.0.0/bits/unique_ptr.h:394:7: note: declared
>>>> here
>>>> 394 | unique_ptr(const unique_ptr&) = delete;
>>>> | ^~~~~~~~~~
>>>> ../../src/gcc/cp/name-lookup.c:5512:1: note: initializing
>>>> argument 1 of 'name_hint
>>>> namespace_hints::maybe_decorate_with_limit(name_hint)'
>>>> 5512 | namespace_hints::maybe_decorate_with_limit (name_hint
>>>> hint)
>>>> | ^~~~~~~~~~~~~~~
>>>>
>>>> I can't use the default copy constructor or assignment operators
>>>> for an
>>>> object containing a gnu::unique_ptr on C++11, as std::unique_ptr
>>>> has:
>>>>
>>>> // Disable copy from lvalue.
>>>> unique_ptr(const unique_ptr&) = delete;
>>>> unique_ptr& operator=(const unique_ptr&) = delete;
>>>>
>>>> If I understand things right, in C++11 I should be using move
>>>> construction/move assignment for this.
>>>>
>>>> I can't write "&&" in the function params to explicitly request
>>>> an
>>>> rvalue-reference, as the code need to be compatible with C++98.
>>>>
>>>> std::move is only defined in C++11 onwards.
>>>>
>>>> Our include/unique-ptr.h defines a gnu::move: for C++11 it's
>>>> std::move,
>>>> but for C++98 it's only defined for the unique_ptr template.
>>>>
>>>> A solution that seems to work appears to be to define gnu::move
>>>> for
>>>> C++98 for all types rather than just gnu::unique_ptr,
>>>> implementing it
>>>> in terms of copying an object via lvalue reference, so that we
>>>> can
>>>> explicitly request a move using "gnu::move" (==std::move on C++),
>>>> without using C++11 syntax, and falling back to a copy on C++98
>>>> (which effectively moves the ptr from the "victim").
>>>>
>>>> Does that sound sane?
>>>
>>> I wouldn't change the unique-ptr.h move to take all types, given
>>> that
>>> it copies rather than just passing the reference through, which
>>> could
>>> be expensive for unsuspecting users. And given how it subverts the
>>> C++98 type system, I'd rather explicitly opt into it. So, let's
>>> overload it for name_hint. And I'd probably return a reference,
>>> e.g.
>>>
>>> #if __cplusplus < 201103
>>> // std::move emulation to support the use of gnu::unique_ptr in
>>> name_hint.
>>> namespace gnu {
>>> inline const name_hint &
>>> move(name_hint &m) { return m; }
>>> }
>>> #endif
>>>
>>> to avoid the unnecessary copy. Actually, I'd be inclined to do
>>> that
>>> for gnu::unique_ptr as well, but would want to make sure that it
>>> doesn't break gdb.
>>
>> And if we made that change to the unique-ptr.h version, i.e.
>>
>> template<typename T>
>> const T&
>> move (T& v)
>> {
>> return v;
>> }
>>
>> then adding an overload for name_hint wouldn't be necessary.
>>
>> Jason
>
> Thanks! Here's an updated version which uses the above.
>
> Successfully bootstrapped & regrtested on x86_64-pc-linux-gnu
>
> As before I also tested non-bootstrap builds with both gcc 4.8 and with
> trunk (to build without and with C++11), running various testcases
> under valgrind.
>
> OK for trunk?
OK.
Jason
^ permalink raw reply [flat|nested] 8+ messages in thread
end of thread, other threads:[~2018-10-25 17:56 UTC | newest]
Thread overview: 8+ messages (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
2018-10-09 19:08 [PATCH] C++: simplify output from suggest_alternatives_for David Malcolm
2018-10-09 23:29 ` Jason Merrill
2018-10-10 21:18 ` [PATCH] v2: " David Malcolm
2018-10-11 14:39 ` Jason Merrill
2018-10-11 14:39 ` Jason Merrill
2018-10-12 0:25 ` [PATCH] v3: " David Malcolm
2018-10-25 19:07 ` Jason Merrill
2018-10-10 15:35 ` [PATCH] " Jason Merrill
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox;
as well as URLs for read-only IMAP folder(s) and NNTP newsgroup(s).