aboutsummaryrefslogtreecommitdiff
path: root/gcc
diff options
context:
space:
mode:
authorDavid Malcolm <dmalcolm@redhat.com>2017-01-20 14:36:46 +0000
committerDavid Malcolm <dmalcolm@gcc.gnu.org>2017-01-20 14:36:46 +0000
commitebed71751b2c030de7f1ad9d284b54b34cfe0a20 (patch)
treee9e719aafb0644febd2b61d586b0ac4595d5db90 /gcc
parentd40036b846df9d07f679d593c55f0090f513bb24 (diff)
downloadgcc-ebed71751b2c030de7f1ad9d284b54b34cfe0a20.zip
gcc-ebed71751b2c030de7f1ad9d284b54b34cfe0a20.tar.gz
gcc-ebed71751b2c030de7f1ad9d284b54b34cfe0a20.tar.bz2
C++: fix fix-it hints for misspellings within explicit namespaces
gcc/cp/ChangeLog: PR c++/77829 PR c++/78656 * cp-tree.h (suggest_alternatives_for): Add bool param. (suggest_alternative_in_explicit_scope): New decl. * error.c (qualified_name_lookup_error): When SCOPE is a namespace that isn't the global one, call new function suggest_alternative_in_explicit_scope, only calling suggest_alternatives_for if it fails, and disabling near match searches fort that case. When SCOPE is the global namespace, pass true for new param to suggest_alternatives_for to allow for fuzzy name lookups. * lex.c (unqualified_name_lookup_error): Pass true for new param to suggest_alternatives_for. * name-lookup.c (consider_binding_level): Add forward decl. (suggest_alternatives_for): Add "suggest_misspellings" param, using it to conditionalize the fuzzy name-lookup code. (suggest_alternative_in_explicit_scope): New function. * parser.c (cp_parser_primary_expression): When calling finish_id_expression, pass location of id_expression rather than that of id_expr_token. (cp_parser_id_expression): Convert local "unqualified_id" from tree to cp_expr to avoid implicitly dropping location information. gcc/testsuite/ChangeLog: PR c++/77829 PR c++/78656 * g++.dg/spellcheck-pr77829.C: New test case. * g++.dg/spellcheck-pr78656.C: New test case. From-SVN: r244715
Diffstat (limited to 'gcc')
-rw-r--r--gcc/cp/ChangeLog25
-rw-r--r--gcc/cp/cp-tree.h3
-rw-r--r--gcc/cp/error.c5
-rw-r--r--gcc/cp/lex.c2
-rw-r--r--gcc/cp/name-lookup.c55
-rw-r--r--gcc/cp/parser.c4
-rw-r--r--gcc/testsuite/ChangeLog7
-rw-r--r--gcc/testsuite/g++.dg/spellcheck-pr77829.C167
-rw-r--r--gcc/testsuite/g++.dg/spellcheck-pr78656.C39
9 files changed, 293 insertions, 14 deletions
diff --git a/gcc/cp/ChangeLog b/gcc/cp/ChangeLog
index 6554cb7..9b71c90 100644
--- a/gcc/cp/ChangeLog
+++ b/gcc/cp/ChangeLog
@@ -1,3 +1,28 @@
+2017-01-20 David Malcolm <dmalcolm@redhat.com>
+
+ PR c++/77829
+ PR c++/78656
+ * cp-tree.h (suggest_alternatives_for): Add bool param.
+ (suggest_alternative_in_explicit_scope): New decl.
+ * error.c (qualified_name_lookup_error): When SCOPE is a namespace
+ that isn't the global one, call new function
+ suggest_alternative_in_explicit_scope, only calling
+ suggest_alternatives_for if it fails, and disabling near match
+ searches fort that case. When SCOPE is the global namespace,
+ pass true for new param to suggest_alternatives_for to allow for
+ fuzzy name lookups.
+ * lex.c (unqualified_name_lookup_error): Pass true for new param
+ to suggest_alternatives_for.
+ * name-lookup.c (consider_binding_level): Add forward decl.
+ (suggest_alternatives_for): Add "suggest_misspellings" param,
+ using it to conditionalize the fuzzy name-lookup code.
+ (suggest_alternative_in_explicit_scope): New function.
+ * parser.c (cp_parser_primary_expression): When calling
+ finish_id_expression, pass location of id_expression rather
+ than that of id_expr_token.
+ (cp_parser_id_expression): Convert local "unqualified_id" from
+ tree to cp_expr to avoid implicitly dropping location information.
+
2017-01-20 Marek Polacek <polacek@redhat.com>
PR c/64279
diff --git a/gcc/cp/cp-tree.h b/gcc/cp/cp-tree.h
index f7c7a35..b4c4dfa 100644
--- a/gcc/cp/cp-tree.h
+++ b/gcc/cp/cp-tree.h
@@ -6937,7 +6937,8 @@ extern tree cp_fully_fold (tree);
extern void clear_fold_cache (void);
/* in name-lookup.c */
-extern void suggest_alternatives_for (location_t, tree);
+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);
/* in constraint.cc */
diff --git a/gcc/cp/error.c b/gcc/cp/error.c
index 72044a9..4f4c11d 100644
--- a/gcc/cp/error.c
+++ b/gcc/cp/error.c
@@ -3777,11 +3777,12 @@ qualified_name_lookup_error (tree scope, tree name,
else if (scope != global_namespace)
{
error_at (location, "%qD is not a member of %qD", name, scope);
- suggest_alternatives_for (location, name);
+ if (!suggest_alternative_in_explicit_scope (location, name, scope))
+ suggest_alternatives_for (location, name, false);
}
else
{
error_at (location, "%<::%D%> has not been declared", name);
- suggest_alternatives_for (location, name);
+ suggest_alternatives_for (location, name, true);
}
}
diff --git a/gcc/cp/lex.c b/gcc/cp/lex.c
index 797dd96..60a70e9 100644
--- a/gcc/cp/lex.c
+++ b/gcc/cp/lex.c
@@ -441,7 +441,7 @@ unqualified_name_lookup_error (tree name, location_t loc)
if (!objc_diagnose_private_ivar (name))
{
error_at (loc, "%qD was not declared in this scope", name);
- suggest_alternatives_for (loc, name);
+ suggest_alternatives_for (loc, name, true);
}
/* Prevent repeated error messages by creating a VAR_DECL with
this NAME in the innermost block scope. */
diff --git a/gcc/cp/name-lookup.c b/gcc/cp/name-lookup.c
index 3c7559f..4004640 100644
--- a/gcc/cp/name-lookup.c
+++ b/gcc/cp/name-lookup.c
@@ -48,6 +48,10 @@ static bool lookup_using_namespace (tree, struct scope_binding *, tree,
tree, int);
static bool qualified_lookup_using_namespace (tree, tree,
struct scope_binding *, int);
+static void consider_binding_level (tree name, best_match <tree, tree> &bm,
+ cp_binding_level *lvl,
+ bool look_within_fields,
+ enum lookup_name_fuzzy_kind kind);
static tree lookup_type_current_level (tree);
static tree push_using_directive (tree);
static tree lookup_extern_c_fun_in_all_ns (tree);
@@ -4431,10 +4435,13 @@ remove_hidden_names (tree fns)
/* Suggest alternatives for NAME, an IDENTIFIER_NODE for which name
lookup failed. Search through all available namespaces and print out
- possible candidates. */
+ 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
-suggest_alternatives_for (location_t location, tree name)
+suggest_alternatives_for (location_t location, tree name,
+ bool suggest_misspellings)
{
vec<tree> candidates = vNULL;
vec<tree> namespaces_to_search = vNULL;
@@ -4481,13 +4488,16 @@ suggest_alternatives_for (location_t location, tree name)
or do nothing. */
if (candidates.is_empty ())
{
- const char *fuzzy_name = lookup_name_fuzzy (name, FUZZY_LOOKUP_NAME);
- if (fuzzy_name)
+ if (suggest_misspellings)
{
- gcc_rich_location richloc (location);
- richloc.add_fixit_replace (fuzzy_name);
- inform_at_rich_loc (&richloc, "suggested alternative: %qs",
- fuzzy_name);
+ const char *fuzzy_name = lookup_name_fuzzy (name, FUZZY_LOOKUP_NAME);
+ if (fuzzy_name)
+ {
+ gcc_rich_location richloc (location);
+ richloc.add_fixit_replace (fuzzy_name);
+ inform_at_rich_loc (&richloc, "suggested alternative: %qs",
+ fuzzy_name);
+ }
}
return;
}
@@ -4502,6 +4512,35 @@ suggest_alternatives_for (location_t location, tree name)
candidates.release ();
}
+/* Look for alternatives for NAME, an IDENTIFIER_NODE for which name
+ lookup failed within the explicitly provided SCOPE. Suggest the
+ the best meaningful candidates (if any) as a fix-it hint.
+ Return true iff a suggestion was provided. */
+
+bool
+suggest_alternative_in_explicit_scope (location_t location, tree name,
+ tree scope)
+{
+ cp_binding_level *level = NAMESPACE_LEVEL (scope);
+
+ best_match <tree, tree> bm (name);
+ consider_binding_level (name, bm, level, false, FUZZY_LOOKUP_NAME);
+
+ /* See if we have a good suggesion for the user. */
+ tree best_id = bm.get_best_meaningful_candidate ();
+ if (best_id)
+ {
+ const char *fuzzy_name = IDENTIFIER_POINTER (best_id);
+ gcc_rich_location richloc (location);
+ richloc.add_fixit_replace (fuzzy_name);
+ inform_at_rich_loc (&richloc, "suggested alternative: %qs",
+ fuzzy_name);
+ return true;
+ }
+
+ return false;
+}
+
/* Unscoped lookup of a global: iterate over current namespaces,
considering using-directives. */
diff --git a/gcc/cp/parser.c b/gcc/cp/parser.c
index 29dcfea..4ab0b69 100644
--- a/gcc/cp/parser.c
+++ b/gcc/cp/parser.c
@@ -5332,7 +5332,7 @@ cp_parser_primary_expression (cp_parser *parser,
template_p, done, address_p,
template_arg_p,
&error_msg,
- id_expr_token->location));
+ id_expression.get_location ()));
if (error_msg)
cp_parser_error (parser, error_msg);
decl.set_location (id_expr_token->location);
@@ -5425,7 +5425,7 @@ cp_parser_id_expression (cp_parser *parser,
tree saved_scope;
tree saved_object_scope;
tree saved_qualifying_scope;
- tree unqualified_id;
+ cp_expr unqualified_id;
bool is_template;
/* See if the next token is the `template' keyword. */
diff --git a/gcc/testsuite/ChangeLog b/gcc/testsuite/ChangeLog
index 201395d..fde9328 100644
--- a/gcc/testsuite/ChangeLog
+++ b/gcc/testsuite/ChangeLog
@@ -1,3 +1,10 @@
+2017-01-20 David Malcolm <dmalcolm@redhat.com>
+
+ PR c++/77829
+ PR c++/78656
+ * g++.dg/spellcheck-pr77829.C: New test case.
+ * g++.dg/spellcheck-pr78656.C: New test case.
+
2017-01-20 Marek Polacek <polacek@redhat.com>
PR c/64279
diff --git a/gcc/testsuite/g++.dg/spellcheck-pr77829.C b/gcc/testsuite/g++.dg/spellcheck-pr77829.C
new file mode 100644
index 0000000..2f75779
--- /dev/null
+++ b/gcc/testsuite/g++.dg/spellcheck-pr77829.C
@@ -0,0 +1,167 @@
+// { dg-options "-fdiagnostics-show-caret" }
+
+/* Various tests of name lookup within a namespace, both within an explicitly
+ given namespace, or implicitly. */
+
+namespace detail {
+ /* Various things to look for. */
+
+ typedef int some_typedef;
+
+ int _foo(int i) { return i; }
+
+ template <typename T>
+ T something_else (T i) { return i; }
+}
+
+/* Tests of lookup of a typedef. */
+
+void fn_1_explicit ()
+{
+ detail::some_type i; // { dg-error ".some_type. is not a member of .detail." }
+ // { dg-message "suggested alternative: .some_typedef." "" { target *-*-* } .-1 }
+ /* { dg-begin-multiline-output "" }
+ detail::some_type i;
+ ^~~~~~~~~
+ { dg-end-multiline-output "" } */
+ /* { dg-begin-multiline-output "" }
+ detail::some_type i;
+ ^~~~~~~~~
+ some_typedef
+ { dg-end-multiline-output "" } */
+}
+
+namespace detail {
+
+void fn_1_implicit ()
+{
+ some_type i; // { dg-error ".some_type. was not declared in this scope" }
+ // { dg-message "suggested alternative: .some_typedef." "" { target *-*-* } .-1 }
+ /* { dg-begin-multiline-output "" }
+ some_type i;
+ ^~~~~~~~~
+ { dg-end-multiline-output "" } */
+ /* { dg-begin-multiline-output "" }
+ some_type i;
+ ^~~~~~~~~
+ some_typedef
+ { dg-end-multiline-output "" } */
+}
+
+} // namespace detail
+
+
+/* Tests of lookup of a function. */
+
+void fn_2_explicit (int i) {
+ detail::foo(i); // { dg-error ".foo. is not a member of .detail." }
+ // { dg-message "suggested alternative: ._foo." "" { target *-*-* } .-1 }
+ /* { dg-begin-multiline-output "" }
+ detail::foo(i);
+ ^~~
+ { dg-end-multiline-output "" } */
+ /* { dg-begin-multiline-output "" }
+ detail::foo(i);
+ ^~~
+ _foo
+ { dg-end-multiline-output "" } */
+}
+
+namespace detail {
+
+void fn_2_implicit (int i) {
+ foo(i); // { dg-error ".foo. was not declared in this scope" }
+ // { dg-message "suggested alternative: ._foo." "" { target *-*-* } .-1 }
+ /* { dg-begin-multiline-output "" }
+ foo(i);
+ ^~~
+ { dg-end-multiline-output "" } */
+ /* { dg-begin-multiline-output "" }
+ foo(i);
+ ^~~
+ _foo
+ { dg-end-multiline-output "" } */
+}
+
+} // namespace detail
+
+
+/* Examples using a template. */
+
+void fn_3_explicit (int i) {
+ detail::something_els(i); // { dg-error ".something_els. is not a member of .detail." }
+ // { dg-message "suggested alternative: .something_else." "" { target *-*-* } .-1 }
+ /* { dg-begin-multiline-output "" }
+ detail::something_els(i);
+ ^~~~~~~~~~~~~
+ { dg-end-multiline-output "" } */
+
+ /* { dg-begin-multiline-output "" }
+ detail::something_els(i);
+ ^~~~~~~~~~~~~
+ something_else
+ { dg-end-multiline-output "" } */
+}
+
+namespace detail {
+
+void fn_3_implicit (int i) {
+ something_els(i); // { dg-error ".something_els. was not declared in this scope" }
+ // { dg-message "suggested alternative: .something_else." "" { target *-*-* } .-1 }
+ /* { dg-begin-multiline-output "" }
+ something_els(i);
+ ^~~~~~~~~~~~~
+ { dg-end-multiline-output "" } */
+
+ /* { dg-begin-multiline-output "" }
+ something_els(i);
+ ^~~~~~~~~~~~~
+ something_else
+ { dg-end-multiline-output "" } */
+}
+
+} // namespace detail
+
+
+/* Tests of lookup for which no hint is available. */
+
+void fn_4_explicit (int i) {
+ detail::not_recognized(i); // { dg-error ".not_recognized. is not a member of .detail." }
+ /* { dg-begin-multiline-output "" }
+ detail::not_recognized(i);
+ ^~~~~~~~~~~~~~
+ { dg-end-multiline-output "" } */
+}
+
+namespace detail {
+
+void fn_4_implicit (int i)
+{
+ not_recognized(i); // { dg-error ".not_recognized. was not declared in this scope" }
+ /* { dg-begin-multiline-output "" }
+ not_recognized(i);
+ ^~~~~~~~~~~~~~
+ { dg-end-multiline-output "" } */
+}
+
+} // namespace detail
+
+
+/* Test for failed lookup explicitly within global namespace. */
+
+typedef int another_typedef;
+
+void fn_5 ()
+{
+ ::another_type i; // { dg-error ".::another_type. has not been declared" }
+ // { dg-message "suggested alternative: .another_typedef." "" { target *-*-* } .-1 }
+ /* { dg-begin-multiline-output "" }
+ ::another_type i;
+ ^~~~~~~~~~~~
+ { dg-end-multiline-output "" } */
+ /* { dg-begin-multiline-output "" }
+ ::another_type i;
+ ^~~~~~~~~~~~
+ another_typedef
+ { dg-end-multiline-output "" } */
+}
diff --git a/gcc/testsuite/g++.dg/spellcheck-pr78656.C b/gcc/testsuite/g++.dg/spellcheck-pr78656.C
new file mode 100644
index 0000000..ded4bb6
--- /dev/null
+++ b/gcc/testsuite/g++.dg/spellcheck-pr78656.C
@@ -0,0 +1,39 @@
+// { dg-options "-fdiagnostics-show-caret" }
+
+#include <memory>
+
+void* allocate(std::size_t n)
+{
+ return std::allocate<char>().allocate(n); // { dg-error ".allocate. is not a member of .std." }
+ // { dg-message "suggested alternative: .allocator." "" { target *-*-* } .-1 }
+ /* { dg-begin-multiline-output "" }
+ return std::allocate<char>().allocate(n);
+ ^~~~~~~~
+ { dg-end-multiline-output "" } */
+ /* { dg-begin-multiline-output "" }
+ return std::allocate<char>().allocate(n);
+ ^~~~~~~~
+ allocator
+ { dg-end-multiline-output "" } */
+
+ // Various errors follow that we don't care about; suppress them:
+ // { dg-excess-errors "7: " }
+}
+
+void* test_2(std::size_t n)
+{
+ return std::alocator<char>().allocate(n); // { dg-error ".alocator. is not a member of .std." }
+ // { dg-message "suggested alternative: .allocator." "" { target *-*-* } .-1 }
+ /* { dg-begin-multiline-output "" }
+ return std::alocator<char>().allocate(n);
+ ^~~~~~~~
+ { dg-end-multiline-output "" } */
+ /* { dg-begin-multiline-output "" }
+ return std::alocator<char>().allocate(n);
+ ^~~~~~~~
+ allocator
+ { dg-end-multiline-output "" } */
+
+ // Various errors follow that we don't care about; suppress them:
+ // { dg-excess-errors "25: " }
+}