aboutsummaryrefslogtreecommitdiff
path: root/gcc/c
diff options
context:
space:
mode:
authorDavid Malcolm <dmalcolm@redhat.com>2018-10-29 23:53:50 +0000
committerDavid Malcolm <dmalcolm@gcc.gnu.org>2018-10-29 23:53:50 +0000
commit7e2de6df10b532be4e66025e318f68a0ebf2c408 (patch)
treead3bc9e9751e07705061fb4f0700df96b7158e4a /gcc/c
parentb2bf438c02e885ddcd89e3f372fe88d9c3a58fd9 (diff)
downloadgcc-7e2de6df10b532be4e66025e318f68a0ebf2c408.zip
gcc-7e2de6df10b532be4e66025e318f68a0ebf2c408.tar.gz
gcc-7e2de6df10b532be4e66025e318f68a0ebf2c408.tar.bz2
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
Diffstat (limited to 'gcc/c')
-rw-r--r--gcc/c/ChangeLog8
-rw-r--r--gcc/c/c-decl.c24
-rw-r--r--gcc/c/c-parser.c12
3 files changed, 26 insertions, 18 deletions
diff --git a/gcc/c/ChangeLog b/gcc/c/ChangeLog
index 2c07f2f..708ef5d 100644
--- a/gcc/c/ChangeLog
+++ b/gcc/c/ChangeLog
@@ -1,3 +1,11 @@
+2018-10-29 David Malcolm <dmalcolm@redhat.com>
+
+ * c-decl.c (implicit_decl_warning): Update "is there a suggestion"
+ logic for change to name_hint::operator bool.
+ (undeclared_variable): Likewise.
+ * c-parser.c (c_parser_declaration_or_fndef): Likewise.
+ (c_parser_parameter_declaration): Likewise.
+
2018-10-17 Joseph Myers <joseph@codesourcery.com>
* c-errors.c (pedwarn_c11): New function.
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 ee66ce8..b36fca9 100644
--- a/gcc/c/c-parser.c
+++ b/gcc/c/c-parser.c
@@ -1822,12 +1822,12 @@ c_parser_declaration_or_fndef (c_parser *parser, bool fndef_ok,
auto_diagnostic_group d;
name_hint hint = lookup_name_fuzzy (name, FUZZY_LOOKUP_TYPENAME,
here);
- if (hint)
+ if (const char *suggestion = hint.suggestion ())
{
- richloc.add_fixit_replace (hint.suggestion ());
+ richloc.add_fixit_replace (suggestion);
error_at (&richloc,
"unknown type name %qE; did you mean %qs?",
- name, hint.suggestion ());
+ name, suggestion);
}
else
error_at (here, "unknown type name %qE", name);
@@ -4074,13 +4074,13 @@ c_parser_parameter_declaration (c_parser *parser, tree attrs)
name_hint hint = lookup_name_fuzzy (token->value,
FUZZY_LOOKUP_TYPENAME,
token->location);
- if (hint)
+ if (const char *suggestion = hint.suggestion ())
{
gcc_rich_location richloc (token->location);
- richloc.add_fixit_replace (hint.suggestion ());
+ richloc.add_fixit_replace (suggestion);
error_at (&richloc,
"unknown type name %qE; did you mean %qs?",
- token->value, hint.suggestion ());
+ token->value, suggestion);
}
else
error_at (token->location, "unknown type name %qE", token->value);