C++: simplify output from suggest_alternatives_for

In the C++ FE, after emitting various errors about unrecognized names,
the parser can call
  suggest_alternatives_for
and/or
  suggest_alternative_in_explicit_scope.
These can issue zero or more suggestions for the unrecognized name,
or various other "note" diagnostics suggesting how to fix the problem.

For example, currently g++ emits:

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

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

This simplifies the above to:

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

omitting the second "note" diagnostic.

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

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

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

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

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

to:

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

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

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

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

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

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

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

From-SVN: r265610
This commit is contained in:
David Malcolm 2018-10-29 23:53:50 +00:00 committed by David Malcolm
parent b2bf438c02
commit 7e2de6df10
40 changed files with 913 additions and 356 deletions

View File

@ -1,3 +1,7 @@
2018-10-29 David Malcolm <dmalcolm@redhat.com>
* name-hint.h (name_hint::take_deferred): New member function.
2018-10-29 David Malcolm <dmalcolm@redhat.com> 2018-10-29 David Malcolm <dmalcolm@redhat.com>
PR c++/56856 PR c++/56856

View File

@ -99,7 +99,14 @@ public:
} }
const char *suggestion () const { return m_suggestion; } 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, /* Call this on a name_hint if the corresponding warning was not emitted,
in which case we should also not emit the deferred_diagnostic. */ in which case we should also not emit the deferred_diagnostic. */

View File

@ -1,3 +1,11 @@
2018-10-29 David Malcolm <dmalcolm@redhat.com>
* c-decl.c (implicit_decl_warning): Update "is there a suggestion"
logic for change to name_hint::operator bool.
(undeclared_variable): Likewise.
* c-parser.c (c_parser_declaration_or_fndef): Likewise.
(c_parser_parameter_declaration): Likewise.
2018-10-17 Joseph Myers <joseph@codesourcery.com> 2018-10-17 Joseph Myers <joseph@codesourcery.com>
* c-errors.c (pedwarn_c11): New function. * c-errors.c (pedwarn_c11): New function.

View File

@ -3150,27 +3150,27 @@ implicit_decl_warning (location_t loc, tree id, tree olddecl)
if (flag_isoc99) if (flag_isoc99)
{ {
if (hint) if (const char *suggestion = hint.suggestion ())
{ {
gcc_rich_location richloc (loc); gcc_rich_location richloc (loc);
richloc.add_fixit_replace (hint.suggestion ()); richloc.add_fixit_replace (suggestion);
warned = pedwarn (&richloc, OPT_Wimplicit_function_declaration, warned = pedwarn (&richloc, OPT_Wimplicit_function_declaration,
"implicit declaration of function %qE;" "implicit declaration of function %qE;"
" did you mean %qs?", " did you mean %qs?",
id, hint.suggestion ()); id, suggestion);
} }
else else
warned = pedwarn (loc, OPT_Wimplicit_function_declaration, warned = pedwarn (loc, OPT_Wimplicit_function_declaration,
"implicit declaration of function %qE", id); "implicit declaration of function %qE", id);
} }
else if (hint) else if (const char *suggestion = hint.suggestion ())
{ {
gcc_rich_location richloc (loc); gcc_rich_location richloc (loc);
richloc.add_fixit_replace (hint.suggestion ()); richloc.add_fixit_replace (suggestion);
warned = warning_at warned = warning_at
(&richloc, OPT_Wimplicit_function_declaration, (&richloc, OPT_Wimplicit_function_declaration,
G_("implicit declaration of function %qE; did you mean %qs?"), G_("implicit declaration of function %qE; did you mean %qs?"),
id, hint.suggestion ()); id, suggestion);
} }
else else
warned = warning_at (loc, OPT_Wimplicit_function_declaration, 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) if (current_function_decl == NULL_TREE)
{ {
name_hint guessed_id = lookup_name_fuzzy (id, FUZZY_LOOKUP_NAME, loc); 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); gcc_rich_location richloc (loc);
richloc.add_fixit_replace (guessed_id.suggestion ()); richloc.add_fixit_replace (suggestion);
error_at (&richloc, error_at (&richloc,
"%qE undeclared here (not in a function);" "%qE undeclared here (not in a function);"
" did you mean %qs?", " did you mean %qs?",
id, guessed_id.suggestion ()); id, suggestion);
} }
else else
error_at (loc, "%qE undeclared here (not in a function)", id); 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)) if (!objc_diagnose_private_ivar (id))
{ {
name_hint guessed_id = lookup_name_fuzzy (id, FUZZY_LOOKUP_NAME, loc); 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); gcc_rich_location richloc (loc);
richloc.add_fixit_replace (guessed_id.suggestion ()); richloc.add_fixit_replace (suggestion);
error_at (&richloc, error_at (&richloc,
"%qE undeclared (first use in this function);" "%qE undeclared (first use in this function);"
" did you mean %qs?", " did you mean %qs?",
id, guessed_id.suggestion ()); id, suggestion);
} }
else else
error_at (loc, "%qE undeclared (first use in this function)", id); error_at (loc, "%qE undeclared (first use in this function)", id);

View File

@ -1822,12 +1822,12 @@ c_parser_declaration_or_fndef (c_parser *parser, bool fndef_ok,
auto_diagnostic_group d; auto_diagnostic_group d;
name_hint hint = lookup_name_fuzzy (name, FUZZY_LOOKUP_TYPENAME, name_hint hint = lookup_name_fuzzy (name, FUZZY_LOOKUP_TYPENAME,
here); here);
if (hint) if (const char *suggestion = hint.suggestion ())
{ {
richloc.add_fixit_replace (hint.suggestion ()); richloc.add_fixit_replace (suggestion);
error_at (&richloc, error_at (&richloc,
"unknown type name %qE; did you mean %qs?", "unknown type name %qE; did you mean %qs?",
name, hint.suggestion ()); name, suggestion);
} }
else else
error_at (here, "unknown type name %qE", name); error_at (here, "unknown type name %qE", name);
@ -4074,13 +4074,13 @@ c_parser_parameter_declaration (c_parser *parser, tree attrs)
name_hint hint = lookup_name_fuzzy (token->value, name_hint hint = lookup_name_fuzzy (token->value,
FUZZY_LOOKUP_TYPENAME, FUZZY_LOOKUP_TYPENAME,
token->location); token->location);
if (hint) if (const char *suggestion = hint.suggestion ())
{ {
gcc_rich_location richloc (token->location); gcc_rich_location richloc (token->location);
richloc.add_fixit_replace (hint.suggestion ()); richloc.add_fixit_replace (suggestion);
error_at (&richloc, error_at (&richloc,
"unknown type name %qE; did you mean %qs?", "unknown type name %qE; did you mean %qs?",
token->value, hint.suggestion ()); token->value, suggestion);
} }
else else
error_at (token->location, "unknown type name %qE", token->value); error_at (token->location, "unknown type name %qE", token->value);

View File

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

37
gcc/cp/cp-name-hint.h Normal file
View File

@ -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 */

View File

@ -6445,6 +6445,7 @@ extern const char *decl_as_string (tree, int);
extern const char *decl_as_string_translate (tree, int); extern const char *decl_as_string_translate (tree, int);
extern const char *decl_as_dwarf_string (tree, int); extern const char *decl_as_dwarf_string (tree, int);
extern const char *expr_as_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_name (tree, int, bool);
extern const char *lang_decl_dwarf_name (tree, int, bool); extern const char *lang_decl_dwarf_name (tree, int, bool);
extern const char *language_to_string (enum languages); extern const char *language_to_string (enum languages);
@ -7478,8 +7479,6 @@ extern tree cp_fully_fold (tree);
extern void clear_fold_cache (void); extern void clear_fold_cache (void);
/* in name-lookup.c */ /* 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); extern tree strip_using_decl (tree);
/* Tell the binding oracle what kind of binding we are looking for. */ /* Tell the binding oracle what kind of binding we are looking for. */

View File

@ -18,6 +18,8 @@ along with GCC; see the file COPYING3. If not see
<http://www.gnu.org/licenses/>. */ <http://www.gnu.org/licenses/>. */
#include "config.h" #include "config.h"
/* For use with name_hint. */
#define INCLUDE_UNIQUE_PTR
#include "system.h" #include "system.h"
#include "coretypes.h" #include "coretypes.h"
#include "cp-tree.h" #include "cp-tree.h"
@ -32,6 +34,7 @@ along with GCC; see the file COPYING3. If not see
#include "ubsan.h" #include "ubsan.h"
#include "internal-fn.h" #include "internal-fn.h"
#include "gcc-rich-location.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_comma(PP) pp_cxx_separate_with (PP, ',')
#define pp_separate_with_semicolon(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 *code_to_string (enum tree_code);
static const char *cv_to_string (tree, int); static const char *cv_to_string (tree, int);
static const char *decl_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 *fndecl_to_string (tree, int);
static const char *op_to_string (bool, enum tree_code); static const char *op_to_string (bool, enum tree_code);
static const char *parm_to_string (int); 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); return pp_ggc_formatted_text (cxx_pp);
} }
static const char * const char *
expr_to_string (tree decl) expr_to_string (tree decl)
{ {
reinit_cxx_pp (); reinit_cxx_pp ();
@ -4261,15 +4263,42 @@ qualified_name_lookup_error (tree scope, tree name,
else if (scope != global_namespace) else if (scope != global_namespace)
{ {
auto_diagnostic_group d; auto_diagnostic_group d;
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); 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);
} }
else else
{ {
auto_diagnostic_group d; auto_diagnostic_group d;
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); error_at (location, "%<::%D%> has not been declared", name);
suggest_alternatives_for (location, name, true);
} }
} }

View File

@ -22,12 +22,16 @@ along with GCC; see the file COPYING3. If not see
/* This file is the lexical analyzer for GNU C++. */ /* This file is the lexical analyzer for GNU C++. */
#include "config.h" #include "config.h"
/* For use with name_hint. */
#define INCLUDE_UNIQUE_PTR
#include "system.h" #include "system.h"
#include "coretypes.h" #include "coretypes.h"
#include "cp-tree.h" #include "cp-tree.h"
#include "stringpool.h" #include "stringpool.h"
#include "c-family/c-pragma.h" #include "c-family/c-pragma.h"
#include "c-family/c-objc.h" #include "c-family/c-objc.h"
#include "gcc-rich-location.h"
#include "cp-name-hint.h"
static int interface_strcmp (const char *); static int interface_strcmp (const char *);
static void init_cp_pragma (void); 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)) if (!objc_diagnose_private_ivar (name))
{ {
auto_diagnostic_group d; auto_diagnostic_group d;
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); error_at (loc, "%qD was not declared in this scope", name);
suggest_alternatives_for (loc, name, true);
} }
/* Prevent repeated error messages by creating a VAR_DECL with /* Prevent repeated error messages by creating a VAR_DECL with
this NAME in the innermost block scope. */ this NAME in the innermost block scope. */

View File

@ -41,7 +41,10 @@ static cxx_binding *cxx_binding_make (tree value, tree type);
static cp_binding_level *innermost_nonclass_level (void); static cp_binding_level *innermost_nonclass_level (void);
static void set_identifier_type_value_with_scope (tree id, tree decl, static void set_identifier_type_value_with_scope (tree id, tree decl,
cp_binding_level *b); 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 /* Create an overload suitable for recording an artificial TYPE_DECL
and another decl. We use this machanism to implement the struct and another decl. We use this machanism to implement the struct
@ -5299,20 +5302,132 @@ has_using_namespace_std_directive_p ()
return false; return false;
} }
/* Suggest alternatives for NAME, an IDENTIFIER_NODE for which name /* Subclass of deferred_diagnostic, for issuing a note when
lookup failed. Search through all available namespaces and print out --param cxx-max-namespaces-for-diagnostic-help is reached.
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. */
void The note should be issued after the error, but before any other
suggest_alternatives_for (location_t location, tree name, deferred diagnostics. This is handled by decorating a wrapped
bool suggest_misspellings) deferred_diagnostic, and emitting a note before that wrapped note is
deleted. */
class namespace_limit_reached : public deferred_diagnostic
{ {
vec<tree> candidates = vNULL; public:
vec<tree> worklist = vNULL; namespace_limit_reached (location_t loc, unsigned limit, tree name,
unsigned limit = PARAM_VALUE (CXX_MAX_NAMESPACES_FOR_DIAGNOSTIC_HELP); gnu::unique_ptr<deferred_diagnostic> wrapped)
bool limited = false; : 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
{
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 /* Breadth-first search of namespaces. Up to limit namespaces
searched (limit zero == unlimited). */ searched (limit zero == unlimited). */
@ -5323,14 +5438,14 @@ suggest_alternatives_for (location_t location, tree name,
name_lookup lookup (name); name_lookup lookup (name);
if (lookup.search_qualified (ns, false)) 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 /* Look for child namespaces. We have to do this
indirectly because they are chained in reverse order, indirectly because they are chained in reverse order,
which is confusing to the user. */ which is confusing to the user. */
vec<tree> children = vNULL; auto_vec<tree> children;
for (tree decl = NAMESPACE_LEVEL (ns)->names; for (tree decl = NAMESPACE_LEVEL (ns)->names;
decl; decl = TREE_CHAIN (decl)) decl; decl = TREE_CHAIN (decl))
@ -5339,60 +5454,141 @@ suggest_alternatives_for (location_t location, tree name,
&& !DECL_NAMESPACE_INLINE_P (decl)) && !DECL_NAMESPACE_INLINE_P (decl))
children.safe_push (decl); children.safe_push (decl);
while (!limited && !children.is_empty ()) while (!m_limited && !children.is_empty ())
{ {
if (worklist.length () == limit) if (worklist.length () == m_limit)
{ m_limited = true;
/* Unconditionally warn that the search was truncated. */
inform (location,
"maximum limit of %d namespaces searched for %qE",
limit, name);
limited = true;
}
else else
worklist.safe_push (children.pop ()); worklist.safe_push (children.pop ());
} }
children.release ();
} }
} }
worklist.release (); }
if (candidates.length ()) /* 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.
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)
{ {
inform_n (location, candidates.length (), tree candidate = m_candidates[0];
"suggested alternative:", /* Clean up CANDIDATES. */
"suggested alternatives:"); m_candidates.release ();
for (unsigned ix = 0; ix != candidates.length (); ix++) return name_hint (expr_to_string (candidate),
{ new show_candidate_location (m_loc, candidate));
tree val = candidates[ix];
inform (location_of (val), " %qE", val);
}
candidates.release ();
return;
} }
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. */ /* No candidates were found in the available namespaces. */
/* If there's a "using namespace std;" active, and this /* If there's a "using namespace std;" active, and this
is one of the most common "std::" names, then it's probably a is one of the most common "std::" names, then it's probably a
missing #include. */ missing #include. */
if (has_using_namespace_std_directive_p ()) 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. */ /* Otherwise, consider misspellings. */
if (!suggest_misspellings) if (!suggest_misspellings)
return; return name_hint ();
if (name_hint hint = lookup_name_fuzzy (name, FUZZY_LOOKUP_NAME,
location))
{
/* Show a spelling correction. */
gcc_rich_location richloc (location);
richloc.add_fixit_replace (hint.suggestion ()); return lookup_name_fuzzy (name, FUZZY_LOOKUP_NAME, location);
inform (&richloc, "suggested alternative: %qs", hint.suggestion ()); }
}
/* 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 /* 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 /* Subclass of deferred_diagnostic for use for names in the "std" namespace
names within the "std" namespace. that weren't recognized, but for which we know which header it ought to be
Return true iff a suggestion was offered. */ 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) maybe_suggest_missing_std_header (location_t location, tree name)
{ {
gcc_assert (TREE_CODE (name) == IDENTIFIER_NODE); 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 char *name_str = IDENTIFIER_POINTER (name);
const std_name_hint *header_hint = get_std_name_hint (name_str); const std_name_hint *header_hint = get_std_name_hint (name_str);
if (!header_hint) if (!header_hint)
return false; return name_hint ();
gcc_rich_location richloc (location); return name_hint (NULL, new missing_std_header (location, name_str,
if (cxx_dialect >= header_hint->min_dialect) header_hint));
{
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;
} }
/* If SCOPE is the "std" namespace, then suggest pertinent header /* Attempt to generate a name_hint that suggests a missing header file
files for NAME at LOCATION. for NAME within SCOPE at LOCATION, or an empty name_hint if this isn't
Return true iff a suggestion was offered. */ applicable. */
static bool static name_hint
maybe_suggest_missing_header (location_t location, tree name, tree scope) maybe_suggest_missing_header (location_t location, tree name, tree scope)
{ {
if (scope == NULL_TREE) if (scope == NULL_TREE)
return false; return name_hint ();
if (TREE_CODE (scope) != NAMESPACE_DECL) if (TREE_CODE (scope) != NAMESPACE_DECL)
return false; return name_hint ();
/* We only offer suggestions for the "std" namespace. */ /* We only offer suggestions for the "std" namespace. */
if (scope != std_node) if (scope != std_node)
return false; return name_hint ();
return maybe_suggest_missing_std_header (location, name); return maybe_suggest_missing_std_header (location, name);
} }
/* Look for alternatives for NAME, an IDENTIFIER_NODE for which name /* Generate a name_hint at LOCATION for NAME, an IDENTIFIER_NODE for which name
lookup failed within the explicitly provided SCOPE. Suggest the lookup failed within the explicitly provided SCOPE.
the best meaningful candidates (if any) as a fix-it hint.
Return true iff a suggestion was provided. */
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, suggest_alternative_in_explicit_scope (location_t location, tree name,
tree scope) tree scope)
{ {
/* Something went very wrong; don't suggest anything. */ /* Something went very wrong; don't suggest anything. */
if (name == error_mark_node) if (name == error_mark_node)
return false; return name_hint ();
/* Resolve any namespace aliases. */ /* Resolve any namespace aliases. */
scope = ORIGINAL_NAMESPACE (scope); scope = ORIGINAL_NAMESPACE (scope);
if (maybe_suggest_missing_header (location, name, scope)) name_hint hint = maybe_suggest_missing_header (location, name, scope);
return true; if (hint)
return hint;
cp_binding_level *level = NAMESPACE_LEVEL (scope); 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. */ /* See if we have a good suggesion for the user. */
const char *fuzzy_name = bm.get_best_meaningful_candidate (); const char *fuzzy_name = bm.get_best_meaningful_candidate ();
if (fuzzy_name) if (fuzzy_name)
{ return name_hint (fuzzy_name, NULL);
gcc_rich_location richloc (location);
richloc.add_fixit_replace (fuzzy_name);
inform (&richloc, "suggested alternative: %qs",
fuzzy_name);
return true;
}
return false; return name_hint ();
} }
/* Look up NAME (an IDENTIFIER_NODE) in SCOPE (either a NAMESPACE_DECL /* Look up NAME (an IDENTIFIER_NODE) in SCOPE (either a NAMESPACE_DECL

View File

@ -43,7 +43,7 @@ along with GCC; see the file COPYING3. If not see
#include "context.h" #include "context.h"
#include "gcc-rich-location.h" #include "gcc-rich-location.h"
#include "tree-iterator.h" #include "tree-iterator.h"
#include "c-family/name-hint.h" #include "cp-name-hint.h"
/* The lexer. */ /* The lexer. */
@ -3292,13 +3292,13 @@ cp_parser_diagnose_invalid_type_name (cp_parser *parser, tree id,
name_hint hint; name_hint hint;
if (TREE_CODE (id) == IDENTIFIER_NODE) if (TREE_CODE (id) == IDENTIFIER_NODE)
hint = lookup_name_fuzzy (id, FUZZY_LOOKUP_TYPENAME, location); hint = lookup_name_fuzzy (id, FUZZY_LOOKUP_TYPENAME, location);
if (hint) if (const char *suggestion = hint.suggestion ())
{ {
gcc_rich_location richloc (location); gcc_rich_location richloc (location);
richloc.add_fixit_replace (hint.suggestion ()); richloc.add_fixit_replace (suggestion);
error_at (&richloc, error_at (&richloc,
"%qE does not name a type; did you mean %qs?", "%qE does not name a type; did you mean %qs?",
id, hint.suggestion ()); id, suggestion);
} }
else else
error_at (location, "%qE does not name a type", id); error_at (location, "%qE does not name a type", id);
@ -3364,23 +3364,53 @@ cp_parser_diagnose_invalid_type_name (cp_parser *parser, tree id,
if (TREE_CODE (parser->scope) == NAMESPACE_DECL) if (TREE_CODE (parser->scope) == NAMESPACE_DECL)
{ {
auto_diagnostic_group d; 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)) if (cp_lexer_next_token_is (parser->lexer, CPP_LESS))
error_at (location_of (id), {
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", "%qE in namespace %qE does not name a template type",
id, parser->scope); id, parser->scope);
}
else if (TREE_CODE (id) == TEMPLATE_ID_EXPR) else if (TREE_CODE (id) == TEMPLATE_ID_EXPR)
error_at (location_of (id), {
"%qE in namespace %qE does not name a template type", if (suggestion)
TREE_OPERAND (id, 0), parser->scope); 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 else
error_at (location_of (id), error_at (&richloc,
"%qE in namespace %qE does not name a template"
" type",
TREE_OPERAND (id, 0), parser->scope);
}
else
{
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", "%qE in namespace %qE does not name a type",
id, parser->scope); id, parser->scope);
}
if (DECL_P (decl)) if (DECL_P (decl))
inform (DECL_SOURCE_LOCATION (decl), "%qD declared here", 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) else if (CLASS_TYPE_P (parser->scope)
&& constructor_name_p (id, parser->scope)) && constructor_name_p (id, parser->scope))
@ -18620,12 +18650,25 @@ cp_parser_namespace_name (cp_parser* parser)
if (!cp_parser_uncommitted_to_tentative_parse_p (parser)) if (!cp_parser_uncommitted_to_tentative_parse_p (parser))
{ {
auto_diagnostic_group d; auto_diagnostic_group d;
error_at (token->location, "%qD is not a namespace-name", identifier); name_hint hint;
if (namespace_decl == error_mark_node if (namespace_decl == error_mark_node
&& parser->scope && TREE_CODE (parser->scope) == NAMESPACE_DECL) && parser->scope && TREE_CODE (parser->scope) == NAMESPACE_DECL)
suggest_alternative_in_explicit_scope (token->location, identifier, hint = suggest_alternative_in_explicit_scope (token->location,
identifier,
parser->scope); 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);
}
else
cp_parser_error (parser, "expected namespace-name"); cp_parser_error (parser, "expected namespace-name");
namespace_decl = error_mark_node; namespace_decl = error_mark_node;
} }

View File

@ -1,3 +1,32 @@
2018-10-29 David Malcolm <dmalcolm@redhat.com>
* c-c++-common/spellcheck-reserved.c: Update expected output for
C++ for merger of "did you mean" suggestions into the error
message.
* g++.dg/ext/builtin3.C: Update expected output for merger of "did
you mean" suggestion into the error.
* g++.dg/lookup/error1.C: Likewise.
* g++.dg/lookup/pr77549.C: Likewise.
* g++.dg/lookup/pr80913.C: Likewise.
* g++.dg/lookup/suggestions1.C: Likewise.
* g++.dg/lookup/suggestions2.C: New test.
* g++.dg/overload/koenig1.C: Update expected output as above.
* g++.dg/spellcheck-identifiers-2.C: Likewise.
* g++.dg/spellcheck-identifiers.C: Likewise.
* g++.dg/spellcheck-ns.C: New test.
* g++.dg/spellcheck-pr77829.C: Update expected output as above.
* g++.dg/spellcheck-pr78656.C: Likewise.
* g++.dg/spellcheck-pr79298.C: Likewise, adding
-fdiagnostics-show-caret to options.
* g++.dg/spellcheck-pr80177.C: Likewise.
* g++.dg/spellcheck-single-vs-multiple.C: New test.
* g++.dg/spellcheck-typenames.C: Update expected output as above.
* g++.dg/template/static10.C: Likewise.
* g++.old-deja/g++.mike/ns5.C: Likewise.
* g++.old-deja/g++.mike/ns7.C: Likewise.
* g++.old-deja/g++.ns/koenig5.C: Likewise.
* g++.old-deja/g++.other/lineno5.C: Likewise.
2018-10-29 Paolo Carlini <paolo.carlini@oracle.com> 2018-10-29 Paolo Carlini <paolo.carlini@oracle.com>
* g++.dg/cpp0x/auto24.C: Test location too. * g++.dg/cpp0x/auto24.C: Test location too.

View File

@ -30,8 +30,7 @@ void test (const char *buf, char ch)
{ {
__builtin_strtchr (buf, ch); /* { dg-line misspelled_reserved } */ __builtin_strtchr (buf, ch); /* { dg-line misspelled_reserved } */
/* { dg-warning "did you mean '__builtin_strchr'" "" { target c } misspelled_reserved } */ /* { dg-warning "did you mean '__builtin_strchr'" "" { target c } misspelled_reserved } */
/* { dg-error "not declared" "" { target c++ } misspelled_reserved } */ /* { dg-error "'__builtin_strtchr' was not declared in this scope; did you mean '__builtin_strrchr'\\?" "" { target c++ } misspelled_reserved } */
/* { dg-message "'__builtin_strrchr'" "" { target c++ } misspelled_reserved } */
} }
/* Similarly for a name that begins with a single underscore. */ /* 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 } */ _builtin_strchr (buf, ch); /* { dg-line misspelled_one_underscore } */
/* { dg-warning "did you mean '__builtin_strchr'" "" { target c } 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-error "'_builtin_strchr' was not declared in this scope; did you mean '__builtin_strchr'\\?" "" { target c++ } misspelled_one_underscore } */
/* { dg-message "'__builtin_strchr'" "" { target c++ } misspelled_one_underscore } */
} }
/* Verify that we can correct "__FILE_" to "__FILE__". */ /* Verify that we can correct "__FILE_" to "__FILE__". */
@ -50,6 +48,5 @@ const char * test_3 (void)
{ {
return __FILE_; /* { dg-line misspelled__FILE_ } */ return __FILE_; /* { dg-line misspelled__FILE_ } */
/* { dg-error "did you mean '__FILE__'" "" { target c } misspelled__FILE_ } */ /* { dg-error "did you mean '__FILE__'" "" { target c } misspelled__FILE_ } */
/* { dg-error "not declared" "" { target c++ } misspelled__FILE_ } */ /* { dg-error "'__FILE_' was not declared in this scope; did you mean '__FILE__'\\?" "" { target c++ } misspelled__FILE_ } */
/* { dg-message "'__FILE__'" "" { target c++ } misspelled__FILE_ } */
} }

View File

@ -9,6 +9,5 @@ extern "C" int printf(char*, ...); // { dg-message "std::printf" }
} }
void foo() { void foo() {
printf("abc"); // { dg-error "3:'printf' was not declared" } printf("abc"); // { dg-error "3:'printf' was not declared in this scope; did you mean 'std::printf'\\?" }
// { dg-message "suggested alternative" "suggested alternative" { target *-*-* } .-1 }
} }

View File

@ -3,8 +3,7 @@
// { dg-do compile } // { dg-do compile }
namespace N { int i; } // { dg-message "N::i" } namespace N { int i; } // { dg-message "N::i" }
void foo() { i; } // { dg-error "not declared" } void foo() { i; } // { dg-error "'i' was not declared in this scope; did you mean 'N::i'\\?" }
// { dg-message "suggested alternative" "suggested alternative" { target *-*-* } .-1 }
using namespace N; using namespace N;
void bar() { i; } void bar() { i; }

View File

@ -22,8 +22,8 @@ void
f2 () f2 ()
{ {
using N::bar; using N::bar;
baz++; // { dg-error "'baz' was not declared in this scope" } baz++; // { dg-error "'baz' was not declared in this scope; did you mean 'bar'\\?" }
} // { dg-message "note: suggested alternative: 'bar'" "" { target *-*-* } .-1 } }
int int
bar () bar ()
@ -44,8 +44,8 @@ void
f3 () f3 ()
{ {
using M::bar; using M::bar;
baz (); // { dg-error "'baz' was not declared in this scope" } baz (); // { dg-error "'baz' was not declared in this scope; did you mean 'bar'\\?" }
} // { dg-message "note: suggested alternative: 'bar'" "" { target *-*-* } .-1 } }
namespace O namespace O
{ {
@ -70,7 +70,6 @@ f4 ()
{ {
using O::foo; using O::foo;
using P::bar; using P::bar;
fooo (); // { dg-error "'fooo' was not declared in this scope" } fooo (); // { dg-error "'fooo' was not declared in this scope; did you mean 'foo'\\?" }
// { dg-message "note: suggested alternative: 'foo'" "" { target *-*-* } .-1 } baz (); // { dg-error "'baz' was not declared in this scope; did you mean 'bar'\\?" }
baz (); // { dg-error "'baz' was not declared in this scope" } }
} // { dg-message "note: suggested alternative: 'bar'" "" { target *-*-* } .-1 }

View File

@ -6,6 +6,5 @@ struct meminfo {};
void frob () void frob ()
{ {
meminf (); // { dg-error "not declared" } meminf (); // { dg-error "'meminf' was not declared in this scope; did you mean 'meminfo'\\?" }
// { dg-message "suggested alternative" "" { target *-*-* } .-1 }
} }

View File

@ -1,8 +1,6 @@
// { dg-do compile } // { dg-do compile }
namespace N { namespace M { int foo; } } // { dg-message "N::M::foo" } namespace N { namespace M { int foo; } } // { dg-message "'N::M::foo' declared here" }
int f (void) { return N::foo; } // { dg-error "not a member" } int f (void) { return N::foo; } // { dg-error "'foo' is not a member of 'N'; did you mean 'N::M::foo'\\?" }
// { dg-message "suggested alternative" "missing namespace" { target *-*-* } .-1 }
int g (void) { return ::foo; } // { dg-error "not been declared" } int g (void) { return ::foo; } // { dg-error "'::foo' has not been declared; did you mean 'N::M::foo'\\?" }
// { dg-message "suggested alternative" "omitted namespace" { target *-*-* } .-1 }

View File

@ -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 "" } */
}

View File

@ -13,7 +13,6 @@ void g ()
{ {
B *bp; B *bp;
N::A *ap; N::A *ap;
f (bp); // { dg-error "3:'f' was not declared" } f (bp); // { dg-error "3:'f' was not declared in this scope; did you mean 'N::f'" }
// { dg-message "suggested alternative" "suggested alternative" { target *-*-* } .-1 }
f (ap); f (ap);
} }

View File

@ -9,12 +9,7 @@ int
test_1 (const char *p) test_1 (const char *p)
{ {
int i; int i;
return ssacnf (p, "%d", &i); /* { dg-error "10: .ssacnf. was not declared in this scope" } */ 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);
^~~~~~
{ dg-end-multiline-output "" } */
// { dg-message "10: suggested alternative: 'sscafn'" "" { target *-*-* } 12 }
/* { dg-begin-multiline-output "" } /* { dg-begin-multiline-output "" }
return ssacnf (p, "%d", &i); return ssacnf (p, "%d", &i);
^~~~~~ ^~~~~~
@ -29,12 +24,7 @@ int
test_2 (void) test_2 (void)
{ {
int i; int i;
return sacnf ("%d", &i); /* { dg-error "10: .sacnf. was not declared in this scope" } */ 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);
^~~~~
{ dg-end-multiline-output "" } */
// { dg-message "10: suggested alternative: 'scanf'" "" { target *-*-* } 32 }
/* { dg-begin-multiline-output "" } /* { dg-begin-multiline-output "" }
return sacnf ("%d", &i); return sacnf ("%d", &i);
^~~~~ ^~~~~

View File

@ -9,12 +9,7 @@ extern void gtk_widget_show_all (GtkWidget *w);
void void
test_1 (GtkWidget *w) test_1 (GtkWidget *w)
{ {
gtk_widget_showall (w); // { dg-error "3: 'gtk_widget_showall' was not declared in this scope" } 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);
^~~~~~~~~~~~~~~~~~
{ dg-end-multiline-output "" } */
// { dg-message "3: suggested alternative: 'gtk_widget_show_all'" "" { target *-*-* } 12 }
/* { dg-begin-multiline-output "" } /* { dg-begin-multiline-output "" }
gtk_widget_showall (w); gtk_widget_showall (w);
^~~~~~~~~~~~~~~~~~ ^~~~~~~~~~~~~~~~~~
@ -23,24 +18,14 @@ test_1 (GtkWidget *w)
/* Ensure we don't try to suggest "gtk_widget_showall" for subsequent /* Ensure we don't try to suggest "gtk_widget_showall" for subsequent
corrections. */ corrections. */
gtk_widget_showall_ (w); // { dg-error "3: 'gtk_widget_showall_' was not declared in this scope" } 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);
^~~~~~~~~~~~~~~~~~~
{ dg-end-multiline-output "" } */
// { dg-message "3: suggested alternative: 'gtk_widget_show_all'" "" { target *-*-* } 26 }
/* { dg-begin-multiline-output "" } /* { dg-begin-multiline-output "" }
gtk_widget_showall_ (w); gtk_widget_showall_ (w);
^~~~~~~~~~~~~~~~~~~ ^~~~~~~~~~~~~~~~~~~
gtk_widget_show_all gtk_widget_show_all
{ dg-end-multiline-output "" } */ { dg-end-multiline-output "" } */
GtkWidgetShowAll (w); // { dg-error "3: 'GtkWidgetShowAll' was not declared in this scope" } 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);
^~~~~~~~~~~~~~~~
{ dg-end-multiline-output "" } */
// { dg-message "3: suggested alternative: 'gtk_widget_show_all'" "" { target *-*-* } 38 }
/* { dg-begin-multiline-output "" } /* { dg-begin-multiline-output "" }
GtkWidgetShowAll (w); GtkWidgetShowAll (w);
^~~~~~~~~~~~~~~~ ^~~~~~~~~~~~~~~~
@ -51,12 +36,7 @@ test_1 (GtkWidget *w)
int int
test_2 (int param) test_2 (int param)
{ {
return parma * parma; // { dg-error "10: 'parma' was not declared in this scope" } return parma * parma; // { dg-error "10: 'parma' was not declared in this scope; did you mean 'param'\\?" }
/* { dg-begin-multiline-output "" }
return parma * parma;
^~~~~
{ dg-end-multiline-output "" } */
// { dg-message "10: suggested alternative: 'param'" "" { target *-*-* } 54 }
/* { dg-begin-multiline-output "" } /* { dg-begin-multiline-output "" }
return parma * parma; return parma * parma;
^~~~~ ^~~~~
@ -69,12 +49,7 @@ test_2 (int param)
int int
test_3 (int i) test_3 (int i)
{ {
return MACRAME (i); // { dg-error "10: 'MACRAME' was not declared in this scope" } return MACRAME (i); // { dg-error "10: 'MACRAME' was not declared in this scope; did you mean 'MACRO'\\?" }
/* { dg-begin-multiline-output "" }
return MACRAME (i);
^~~~~~~
{ dg-end-multiline-output "" } */
// { dg-message "10: suggested alternative: 'MACRO'" "" { target *-*-* } 72 }
/* { dg-begin-multiline-output "" } /* { dg-begin-multiline-output "" }
return MACRAME (i); return MACRAME (i);
^~~~~~~ ^~~~~~~
@ -87,12 +62,7 @@ test_3 (int i)
int int
test_4 (int node) test_4 (int node)
{ {
return IDENTIFIER_PTR (node); // { dg-error "10: 'IDENTIFIER_PTR' was not declared in this scope" } 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);
^~~~~~~~~~~~~~
{ dg-end-multiline-output "" } */
// { dg-message "10: suggested alternative: 'IDENTIFIER_POINTER'" "" { target *-*-* } 90 }
/* { dg-begin-multiline-output "" } /* { dg-begin-multiline-output "" }
return IDENTIFIER_PTR (node); return IDENTIFIER_PTR (node);
^~~~~~~~~~~~~~ ^~~~~~~~~~~~~~
@ -104,12 +74,7 @@ test_4 (int node)
int int
test_5 (void) test_5 (void)
{ {
return __LINE_; /* { dg-error "10: '__LINE_' was not declared in this scope" } return __LINE_; /* { dg-error "10: '__LINE_' was not declared in this scope; did you mean '__LINE__'\\?" }
/* { dg-begin-multiline-output "" }
return __LINE_;
^~~~~~~
{ dg-end-multiline-output "" } */
// { dg-message "10: suggested alternative: '__LINE__'" "" { target *-*-* } 107 }
/* { dg-begin-multiline-output "" } /* { dg-begin-multiline-output "" }
return __LINE_; return __LINE_;
^~~~~~~ ^~~~~~~
@ -118,12 +83,7 @@ test_5 (void)
} }
#define MAX_ITEMS 100 #define MAX_ITEMS 100
int array[MAX_ITEM]; // { dg-error "11: 'MAX_ITEM' was not declared in this scope" } 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];
^~~~~~~~
{ dg-end-multiline-output "" } */
// { dg-message "11: suggested alternative: 'MAX_ITEMS'" "" { target *-*-* } 121 }
/* { dg-begin-multiline-output "" } /* { dg-begin-multiline-output "" }
int array[MAX_ITEM]; int array[MAX_ITEM];
^~~~~~~~ ^~~~~~~~
@ -141,26 +101,16 @@ test_6 (enum foo f)
{ {
switch (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; 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 "" } /* { dg-begin-multiline-output "" }
case FOO_FURST: case FOO_FURST:
^~~~~~~~~ ^~~~~~~~~
FOO_FIRST FOO_FIRST
{ dg-end-multiline-output "" } */ { 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; 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 "" } /* { dg-begin-multiline-output "" }
case FOO_SECCOND: case FOO_SECCOND:
^~~~~~~~~~~ ^~~~~~~~~~~
@ -178,12 +128,7 @@ void
test_7 (int i, int j) test_7 (int i, int j)
{ {
int buffer[100]; int buffer[100];
snprint (buffer, 100, "%i of %i", i, j); // { dg-error "3: 'snprint' was not declared in this scope" } 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);
^~~~~~~
{ dg-end-multiline-output "" } */
// { dg-message "3: suggested alternative: 'snprintf'" "" { target *-*-* } 181 }
/* { dg-begin-multiline-output "" } /* { dg-begin-multiline-output "" }
snprint (buffer, 100, "%i of %i", i, j); snprint (buffer, 100, "%i of %i", i, j);
^~~~~~~ ^~~~~~~
@ -196,12 +141,7 @@ test_8 ()
{ {
int local = 42; int local = 42;
return locale; // { dg-error "10: 'locale' was not declared in this scope" } return locale; // { dg-error "10: 'locale' was not declared in this scope; did you mean 'local'\\?" }
/* { dg-begin-multiline-output "" }
return locale;
^~~~~~
{ dg-end-multiline-output "" } */
// { dg-message "10: suggested alternative: 'local'" "" { target *-*-* } 199 }
/* { dg-begin-multiline-output "" } /* { dg-begin-multiline-output "" }
return locale; return locale;
^~~~~~ ^~~~~~
@ -226,12 +166,7 @@ public:
int base::test_method_1 () int base::test_method_1 ()
{ {
return m_food; // { dg-error "10: 'm_food' was not declared in this scope" } 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;
^~~~~~
{ dg-end-multiline-output "" } */
// { dg-message "10: suggested alternative: 'm_foo'" "" { target *-*-* } 229 }
/* { dg-begin-multiline-output "" } /* { dg-begin-multiline-output "" }
return m_food; return m_food;
^~~~~~ ^~~~~~
@ -241,12 +176,7 @@ int base::test_method_1 ()
int sub::test_method_2 () int sub::test_method_2 ()
{ {
return m_food; // { dg-error "10: 'm_food' was not declared in this scope" } 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;
^~~~~~
{ dg-end-multiline-output "" } */
// { dg-message "10: suggested alternative: 'm_foo'" "" { target *-*-* } 244 }
/* { dg-begin-multiline-output "" } /* { dg-begin-multiline-output "" }
return m_food; return m_food;
^~~~~~ ^~~~~~

View File

@ -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 "" } */

View File

@ -18,12 +18,7 @@ namespace detail {
void fn_1_explicit () void fn_1_explicit ()
{ {
detail::some_type i; // { dg-error ".some_type. is not a member of .detail." } detail::some_type i; // { dg-error ".some_type. is not a member of .detail.; did you mean 'some_typedef'\\?" }
// { dg-message "suggested alternative: .some_typedef." "" { target *-*-* } .-1 }
/* { dg-begin-multiline-output "" }
detail::some_type i;
^~~~~~~~~
{ dg-end-multiline-output "" } */
/* { dg-begin-multiline-output "" } /* { dg-begin-multiline-output "" }
detail::some_type i; detail::some_type i;
^~~~~~~~~ ^~~~~~~~~
@ -35,12 +30,7 @@ namespace detail {
void fn_1_implicit () void fn_1_implicit ()
{ {
some_type i; // { dg-error ".some_type. was not declared in this scope" } some_type i; // { dg-error ".some_type. was not declared in this scope; did you mean 'some_typedef'\\?" }
// { dg-message "suggested alternative: .some_typedef." "" { target *-*-* } .-1 }
/* { dg-begin-multiline-output "" }
some_type i;
^~~~~~~~~
{ dg-end-multiline-output "" } */
/* { dg-begin-multiline-output "" } /* { dg-begin-multiline-output "" }
some_type i; some_type i;
^~~~~~~~~ ^~~~~~~~~
@ -54,12 +44,7 @@ void fn_1_implicit ()
/* Tests of lookup of a function. */ /* Tests of lookup of a function. */
void fn_2_explicit (int i) { void fn_2_explicit (int i) {
detail::foo(i); // { dg-error ".foo. is not a member of .detail." } detail::foo(i); // { dg-error ".foo. is not a member of .detail.; did you mean '_foo'\\?" }
// { dg-message "suggested alternative: ._foo." "" { target *-*-* } .-1 }
/* { dg-begin-multiline-output "" }
detail::foo(i);
^~~
{ dg-end-multiline-output "" } */
/* { dg-begin-multiline-output "" } /* { dg-begin-multiline-output "" }
detail::foo(i); detail::foo(i);
^~~ ^~~
@ -70,12 +55,7 @@ void fn_2_explicit (int i) {
namespace detail { namespace detail {
void fn_2_implicit (int i) { void fn_2_implicit (int i) {
foo(i); // { dg-error ".foo. was not declared in this scope" } foo(i); // { dg-error ".foo. was not declared in this scope; did you mean '_foo'\\?" }
// { dg-message "suggested alternative: ._foo." "" { target *-*-* } .-1 }
/* { dg-begin-multiline-output "" }
foo(i);
^~~
{ dg-end-multiline-output "" } */
/* { dg-begin-multiline-output "" } /* { dg-begin-multiline-output "" }
foo(i); foo(i);
^~~ ^~~
@ -89,13 +69,7 @@ void fn_2_implicit (int i) {
/* Examples using a template. */ /* Examples using a template. */
void fn_3_explicit (int i) { void fn_3_explicit (int i) {
detail::something_els(i); // { dg-error ".something_els. is not a member of .detail." } detail::something_els(i); // { dg-error ".something_els. is not a member of .detail.; did you mean 'something_else'\\?" }
// { dg-message "suggested alternative: .something_else." "" { target *-*-* } .-1 }
/* { dg-begin-multiline-output "" }
detail::something_els(i);
^~~~~~~~~~~~~
{ dg-end-multiline-output "" } */
/* { dg-begin-multiline-output "" } /* { dg-begin-multiline-output "" }
detail::something_els(i); detail::something_els(i);
^~~~~~~~~~~~~ ^~~~~~~~~~~~~
@ -106,13 +80,7 @@ void fn_3_explicit (int i) {
namespace detail { namespace detail {
void fn_3_implicit (int i) { void fn_3_implicit (int i) {
something_els(i); // { dg-error ".something_els. was not declared in this scope" } something_els(i); // { dg-error ".something_els. was not declared in this scope; did you mean 'something_else'\\?" }
// { dg-message "suggested alternative: .something_else." "" { target *-*-* } .-1 }
/* { dg-begin-multiline-output "" }
something_els(i);
^~~~~~~~~~~~~
{ dg-end-multiline-output "" } */
/* { dg-begin-multiline-output "" } /* { dg-begin-multiline-output "" }
something_els(i); something_els(i);
^~~~~~~~~~~~~ ^~~~~~~~~~~~~
@ -153,12 +121,7 @@ typedef int another_typedef;
void fn_5 () void fn_5 ()
{ {
::another_type i; // { dg-error ".::another_type. has not been declared" } ::another_type i; // { dg-error ".::another_type. has not been declared; did you mean 'another_typedef'\\?" }
// { dg-message "suggested alternative: .another_typedef." "" { target *-*-* } .-1 }
/* { dg-begin-multiline-output "" }
::another_type i;
^~~~~~~~~~~~
{ dg-end-multiline-output "" } */
/* { dg-begin-multiline-output "" } /* { dg-begin-multiline-output "" }
::another_type i; ::another_type i;
^~~~~~~~~~~~ ^~~~~~~~~~~~

View File

@ -4,12 +4,7 @@
void* allocate(std::size_t n) void* allocate(std::size_t n)
{ {
return std::allocate<char>().allocate(n); // { dg-error ".allocate. is not a member of .std." } return std::allocate<char>().allocate(n); // { dg-error ".allocate. is not a member of .std.; did you mean 'allocator'\\?" }
// { dg-message "suggested alternative: .allocator." "" { target *-*-* } .-1 }
/* { dg-begin-multiline-output "" }
return std::allocate<char>().allocate(n);
^~~~~~~~
{ dg-end-multiline-output "" } */
/* { dg-begin-multiline-output "" } /* { dg-begin-multiline-output "" }
return std::allocate<char>().allocate(n); return std::allocate<char>().allocate(n);
^~~~~~~~ ^~~~~~~~
@ -22,12 +17,7 @@ void* allocate(std::size_t n)
void* test_2(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." } return std::alocator<char>().allocate(n); // { dg-error ".alocator. is not a member of .std.; did you mean 'allocator'\\?" }
// { dg-message "suggested alternative: .allocator." "" { target *-*-* } .-1 }
/* { dg-begin-multiline-output "" }
return std::alocator<char>().allocate(n);
^~~~~~~~
{ dg-end-multiline-output "" } */
/* { dg-begin-multiline-output "" } /* { dg-begin-multiline-output "" }
return std::alocator<char>().allocate(n); return std::alocator<char>().allocate(n);
^~~~~~~~ ^~~~~~~~

View File

@ -1,5 +1,6 @@
// Ensure that we can offer suggestions for misspellings via a // Ensure that we can offer suggestions for misspellings via a
// namespace alias. // namespace alias.
// { dg-options "-fdiagnostics-show-caret" }
namespace N { int x; int color; } namespace N { int x; int color; }
namespace M = N; namespace M = N;
@ -8,10 +9,18 @@ namespace O = M;
int foo () int foo ()
{ {
return M::y; // { dg-error ".y. is not a member of .M." } 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 () int bar ()
{ {
return O::colour; // { dg-error ".colour. is not a member of .O." } return O::colour; // { dg-error ".colour. is not a member of .O.; did you mean 'color'\\?" }
// { dg-message "suggested alternative: .color." "" { target *-*-* } .-1 } /* { dg-begin-multiline-output "" }
return O::colour;
^~~~~~
color
{ dg-end-multiline-output "" } */
} }

View File

@ -1,7 +1,12 @@
// { dg-do compile { target c++11 } } // { dg-do compile { target c++11 } }
// { dg-options "-fdiagnostics-show-caret" }
void pr80177 () void pr80177 ()
{ {
static_assertion (1 == 0, "1 == 0"); // { dg-error "3: 'static_assertion' was not declared in this scope" } static_assertion (1 == 0, "1 == 0"); // { dg-error "3: 'static_assertion' was not declared in this scope; did you mean 'static_assert'\\?" }
// { dg-message "3: suggested alternative: 'static_assert'" "" { target *-*-* } .-1 } /* { dg-begin-multiline-output "" }
static_assertion (1 == 0, "1 == 0");
^~~~~~~~~~~~~~~~
static_assert
{ dg-end-multiline-output "" } */
} }

View File

@ -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 "" } */
}

View File

@ -9,12 +9,7 @@ void test_2 (singed char e); // { dg-error "21: variable or field 'test_2' decla
void test_2 (singed char e); void test_2 (singed char e);
^~~~ ^~~~
{ dg-end-multiline-output "" } */ { dg-end-multiline-output "" } */
// { dg-message "14: 'singed' was not declared in this scope" "" { 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);
^~~~~~
{ dg-end-multiline-output "" } */
// { dg-message "14: suggested alternative: 'signed'" "" { target *-*-* } 7 }
/* { dg-begin-multiline-output "" } /* { dg-begin-multiline-output "" }
void test_2 (singed char e); 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); void test_3 (car e);
^~~ ^~~
{ dg-end-multiline-output "" } */ { dg-end-multiline-output "" } */
// { dg-message "14: 'car' was not declared in this scope" "" { target *-*-* } 24 } // { dg-message "14: 'car' was not declared in this scope; did you mean 'char'\\?" "" { target *-*-* } 19 }
// { dg-message "14: suggested alternative: 'char'" "" { target *-*-* } 24 }
/* { dg-begin-multiline-output "" } /* { dg-begin-multiline-output "" }
void test_3 (car e); void test_3 (car e);
^~~ ^~~

View File

@ -19,6 +19,6 @@ namespace __gnu_debug_def
namespace std namespace std
{ {
template<> void template<> void
vector<int, allocator<int> >::swap(vector<int, allocator<int> >&) { } // { dg-error "" } vector<int, allocator<int> >::swap(vector<int, allocator<int> >&) { } // { dg-error "did you mean 'std::allocator'" }
// { dg-message "suggested alternative" "suggested alternative" { target *-*-* } .-1 } // { dg-error "" "" { target *-*-*} .-1 }
} }

View File

@ -3,5 +3,4 @@ namespace A {
int i = 1; // { dg-message "A::i" } int i = 1; // { dg-message "A::i" }
} }
int j = i; // { dg-error "" } int j = i; // { dg-error "'i' was not declared in this scope; did you mean 'A::i'" }
// { dg-message "suggested alternative" "suggested alternative" { target *-*-* } .-1 }

View File

@ -5,6 +5,5 @@ namespace A {
} }
namespace B { namespace B {
int j = i; // { dg-error "" } int j = i; // { dg-error "'i' was not declared in this scope; did you mean 'A::i'" }
// { dg-message "suggested alternative" "suggested alternative" { target *-*-* } .-1 }
} }

View File

@ -14,6 +14,5 @@ void g()
foo(new X); // ok -- DR 218 says that we find the global foo(new X); // ok -- DR 218 says that we find the global
// foo variable first, and therefore do not // foo variable first, and therefore do not
// perform argument-dependent lookup. // perform argument-dependent lookup.
bar(new X); // { dg-error "3:'bar' was not declared" } bar(new X); // { dg-error "3:'bar' was not declared in this scope; did you mean 'A::bar'" }
// { dg-message "suggested alternative" "suggested alternative" { target *-*-* } .-1 }
} }

View File

@ -15,6 +15,5 @@ namespace tmp {
class A { class A {
public: public:
int kaka(tmp::B = b); // { dg-error "" } no b in scope int kaka(tmp::B = b); // { dg-error "'b' was not declared in this scope; did you mean 'tmp::b'" }
// { dg-message "suggested alternative" "suggested alternative" { target *-*-* } .-1 }
}; };

View File

@ -1,3 +1,8 @@
2018-10-29 David Malcolm <dmalcolm@redhat.com>
* unique-ptr.h (gnu::move): Generalize so it applies to all
lvalue references, rather than just to unique_ptr values.
2018-07-26 Martin Liska <mliska@suse.cz> 2018-07-26 Martin Liska <mliska@suse.cz>
PR lto/86548 PR lto/86548

View File

@ -336,13 +336,13 @@ operator>= (const detail::unique_ptr_base<T, D> &x,
{ return !(x < y); } { return !(x < y); }
/* std::move "emulation". This is as simple as it can be -- no /* std::move "emulation". This is as simple as it can be -- no
attempt is made to emulate rvalue references. Instead relies on attempt is made to emulate rvalue references. This relies on T
the fact that gnu::unique_ptr has move semantics like having move semantics like std::auto_ptr.
std::auto_ptr. I.e., copy/assignment actually moves. */ I.e., copy/assignment actually moves. */
template<typename T, typename D> template<typename T>
unique_ptr<T, D> const T&
move (unique_ptr<T, D> v) move (T& v)
{ {
return v; return v;
} }

View File

@ -1,3 +1,9 @@
2018-10-29 David Malcolm <dmalcolm@redhat.com>
* testsuite/17_intro/using_namespace_std_exp_neg.cc: Remove
"expected namespace-name before" error.
* testsuite/17_intro/using_namespace_std_tr1_neg.cc: Likewise.
2018-10-28 François Dumont <fdumont@gcc.gnu.org> 2018-10-28 François Dumont <fdumont@gcc.gnu.org>
* testsuite/23_containers/deque/48101_neg.cc: Remove dg-prune-output * testsuite/23_containers/deque/48101_neg.cc: Remove dg-prune-output

View File

@ -61,5 +61,3 @@ namespace gnu
{ {
using namespace std::experimental; // { dg-error "is not a namespace-name" } using namespace std::experimental; // { dg-error "is not a namespace-name" }
} }
// { dg-error "expected namespace-name before" "" { target *-*-* } 62 }

View File

@ -64,5 +64,3 @@ namespace gnu
{ {
using namespace std::tr1; // { dg-error "is not a namespace-name" } using namespace std::tr1; // { dg-error "is not a namespace-name" }
} }
// { dg-error "expected namespace-name before" "" { target *-*-* } 65 }