This is the mail archive of the
gcc-patches@gcc.gnu.org
mailing list for the GCC project.
[PATCH,c++] fix PR 45330, suggest alternatives for failed name lookups
- From: Nathan Froyd <froydnj at codesourcery dot com>
- To: gcc-patches at gcc dot gnu dot org
- Cc: jason at redhat dot com
- Date: Wed, 10 Nov 2010 13:13:57 -0500
- Subject: [PATCH,c++] fix PR 45330, suggest alternatives for failed name lookups
The testcase in PR 45330 is:
namespace N
{
int foo;
}
int bar()
{
return foo;
}
and the perceived problem is that GCC should suggest `N::foo' for the
unqualified `foo' in `bar'. The below patch does just that: when name
lookup fails, we grovel through all known namespaces for potential
matches and suggest them to the user.
I put the declaration for the function in cp-tree.h rather than
name-lookup.h because it seemed like a better place than including
name-lookup.h in lex.c. I'm happy to move the declaration to
name-lookup.h and add the include. (Or, more radically, move
unqualified_name_lookup_error and unqualified_fn_lookup_error to
name-lookup.c and adjust includes appropriately.)
The error.c change is to avoid dump_expr complaining (as occurs in
g++.dg/lookup/koenig5.C).
I didn't include a testcase, as the testcase tweaks indicated there are
a number of testcases testing similar things.
(g++.old-deja/g++.mike/ns5.C is almost identical to the testcase in the
PR, for instance).
Tested on x86_64-unknown-linux-gnu. OK to commit?
-Nathan
gcc/cp/
PR c++/45330
* cp-tree.h (suggest_alternatives_for): Declare.
* error.c (dump_expr): Handle TYPE_DECL.
* lex.c (unqualified_name_lookup_error): Call it.
* name-lookup.c (suggest_alternatives_for_1): New function.
(suggest_alternatives_for): New function.
gcc/testsuite/
PR c++/45330
* g++.dg/ext/builtin3.C: Adjust.
* g++.dg/lookup/error1.C: Adjust.
* g++.dg/lookup/koenig5.C: Adjust.
* g++.dg/overload/koenig1.C: Adjust.
* g++.dg/parse/decl-specifier-1.C: Adjust.
* g++.dg/template/static10.C: Adjust.
* g++.old-deja/g++.mike/ns5.C: Adjust.
* g++.old-deja/g++.mike/ns7.C: Adjust.
* g++.old-deja/g++.ns/koenig5.C: Adjust.
* g++.old-deja/g++.ns/koenig9.C: Adjust.
* g++.old-deja/g++.other/lineno5.C: Adjust.
diff --git a/gcc/cp/cp-tree.h b/gcc/cp/cp-tree.h
index 67f4f93..a323501 100644
--- a/gcc/cp/cp-tree.h
+++ b/gcc/cp/cp-tree.h
@@ -5639,6 +5639,9 @@ extern tree cxx_omp_clause_dtor (tree, tree);
extern void cxx_omp_finish_clause (tree);
extern bool cxx_omp_privatize_by_reference (const_tree);
+/* in name-lookup.c */
+extern void suggest_alternatives_for (tree);
+
/* -- end of C++ */
#endif /* ! GCC_CP_TREE_H */
diff --git a/gcc/cp/lex.c b/gcc/cp/lex.c
index c583d7d..9c6be41 100644
--- a/gcc/cp/lex.c
+++ b/gcc/cp/lex.c
@@ -450,7 +450,10 @@ unqualified_name_lookup_error (tree name)
else
{
if (!objc_diagnose_private_ivar (name))
- error ("%qD was not declared in this scope", name);
+ {
+ error ("%qD was not declared in this scope", name);
+ suggest_alternatives_for (name);
+ }
/* Prevent repeated error messages by creating a VAR_DECL with
this NAME in the innermost block scope. */
if (current_function_decl)
diff --git a/gcc/cp/error.c b/gcc/cp/error.c
index 1560fc6..de45efe 100644
--- a/gcc/cp/error.c
+++ b/gcc/cp/error.c
@@ -1700,6 +1700,7 @@ dump_expr (tree t, int flags)
case NAMESPACE_DECL:
case LABEL_DECL:
case OVERLOAD:
+ case TYPE_DECL:
case IDENTIFIER_NODE:
dump_decl (t, (flags & ~TFF_DECL_SPECIFIERS) | TFF_NO_FUNCTION_ARGUMENTS);
break;
diff --git a/gcc/cp/name-lookup.c b/gcc/cp/name-lookup.c
index 0a93da8..1f2f4e5 100644
--- a/gcc/cp/name-lookup.c
+++ b/gcc/cp/name-lookup.c
@@ -30,6 +30,7 @@ along with GCC; see the file COPYING3. If not see
#include "timevar.h"
#include "toplev.h"
#include "diagnostic-core.h"
+#include "intl.h"
#include "debug.h"
#include "c-family/c-pragma.h"
@@ -3919,6 +3920,62 @@ remove_hidden_names (tree fns)
return fns;
}
+/* Helper function for suggest_alternatives_for: lookup NAME in
+ namespace SCOPE and record any matches in CANDIDATES. */
+
+static VEC(tree,heap) *
+suggest_alternatives_for_1 (tree name, tree scope,
+ VEC(tree,heap) *candidates)
+{
+ struct scope_binding binding = EMPTY_SCOPE_BINDING;
+ struct cp_binding_level *level = NAMESPACE_LEVEL (scope);
+ tree t;
+
+ /* Look in this namespace. */
+ qualified_lookup_using_namespace (name, scope, &binding, 0);
+
+ if (binding.value)
+ VEC_safe_push (tree, heap, candidates, binding.value);
+
+ /* Lookup in child namespaces. */
+ for (t = level->namespaces; t; t = DECL_CHAIN (t))
+ candidates = suggest_alternatives_for_1 (name, t, candidates);
+
+ return candidates;
+}
+
+/* Suggest alternatives for NAME, an IDENTIFIER_NODE for which name
+ lookup failed. Search through all available namespaces and print out
+ possible candidates. */
+
+void
+suggest_alternatives_for (tree name)
+{
+ VEC(tree,heap) *candidates
+ = suggest_alternatives_for_1 (name, global_namespace, NULL);
+ const char *str;
+ char *spaces;
+ tree t;
+ unsigned ix;
+
+ /* Nothing useful to report. */
+ if (VEC_empty (tree, candidates))
+ return;
+
+ str = (VEC_length(tree, candidates) > 1
+ ? _("suggested alternatives:")
+ : _("suggested alternative:"));
+ spaces = NULL;
+
+ FOR_EACH_VEC_ELT (tree, candidates, ix, t)
+ {
+ inform (input_location, "%s %qE", (spaces ? spaces : str), t);
+ spaces = spaces ? spaces : get_spaces (str);
+ }
+
+ VEC_free (tree, heap, candidates);
+}
+
/* Unscoped lookup of a global: iterate over current namespaces,
considering using-directives. */
diff --git a/gcc/testsuite/g++.dg/ext/builtin3.C b/gcc/testsuite/g++.dg/ext/builtin3.C
index 3d06dd7..a9ebce0 100644
--- a/gcc/testsuite/g++.dg/ext/builtin3.C
+++ b/gcc/testsuite/g++.dg/ext/builtin3.C
@@ -10,4 +10,5 @@ extern "C" int printf(char*, ...);
void foo() {
printf("abc"); // { dg-error "not declared" }
+ // { dg-message "note" "suggested alternative" { target *-*-* } 12 }
}
diff --git a/gcc/testsuite/g++.dg/lookup/error1.C b/gcc/testsuite/g++.dg/lookup/error1.C
index 2264b23..3b34ee3 100644
--- a/gcc/testsuite/g++.dg/lookup/error1.C
+++ b/gcc/testsuite/g++.dg/lookup/error1.C
@@ -4,6 +4,7 @@
namespace N { int i; }
void foo() { i; } // { dg-error "not declared" }
+ // { dg-message "note" "suggested alternative" { target *-*-* } 6 }
using namespace N;
void bar() { i; }
diff --git a/gcc/testsuite/g++.dg/lookup/koenig5.C b/gcc/testsuite/g++.dg/lookup/koenig5.C
index 6ecc25d..bc1dc8c 100644
--- a/gcc/testsuite/g++.dg/lookup/koenig5.C
+++ b/gcc/testsuite/g++.dg/lookup/koenig5.C
@@ -32,10 +32,12 @@ void g (N::A *a, M::B *b, O::C *c)
One (a); // ok
One (a, b); // ok
One (b); // { dg-error "not declared" }
+ // { dg-message "note" "suggested alternative" { target *-*-* } 34 }
Two (c); // ok
Two (a, c); // ok
Two (a); // { dg-error "not declared" }
+ // { dg-message "note" "suggested alternative" { target *-*-* } 39 }
Two (a, a); // error masked by earlier error
Two (b); // error masked by earlier error
Two (a, b); // error masked by earlier error
@@ -43,4 +45,5 @@ void g (N::A *a, M::B *b, O::C *c)
Three (b); // ok
Three (a, b); // ok
Three (a); // { dg-error "not declared" }
+ // { dg-message "note" "suggested alternative" { target *-*-* } 47 }
}
diff --git a/gcc/testsuite/g++.dg/overload/koenig1.C b/gcc/testsuite/g++.dg/overload/koenig1.C
index 1ed7bce..be0be69 100644
--- a/gcc/testsuite/g++.dg/overload/koenig1.C
+++ b/gcc/testsuite/g++.dg/overload/koenig1.C
@@ -14,5 +14,6 @@ void g ()
B *bp;
N::A *ap;
f (bp); // { dg-error "not declared" }
+ // { dg-message "note" "suggested alternative" { target *-*-* } 16 }
f (ap);
}
diff --git a/gcc/testsuite/g++.dg/parse/decl-specifier-1.C b/gcc/testsuite/g++.dg/parse/decl-specifier-1.C
index e81fbab..48fc7fa 100644
--- a/gcc/testsuite/g++.dg/parse/decl-specifier-1.C
+++ b/gcc/testsuite/g++.dg/parse/decl-specifier-1.C
@@ -13,4 +13,5 @@ N::X X; // { dg-error "" "" }
int main()
{
return sizeof(X); // { dg-error "" "" }
+ // { dg-message "note" "suggested alternative" { target *-*-* } 15 }
}
diff --git a/gcc/testsuite/g++.dg/template/static10.C b/gcc/testsuite/g++.dg/template/static10.C
index ab857bd..2f60f0c 100644
--- a/gcc/testsuite/g++.dg/template/static10.C
+++ b/gcc/testsuite/g++.dg/template/static10.C
@@ -20,4 +20,5 @@ namespace std
{
template<> void
vector<int, allocator<int> >::swap(vector<int, allocator<int> >&) { } // { dg-error "" }
+ // { dg-message "note" "suggested alternative" { target *-*-* } 22 }
}
diff --git a/gcc/testsuite/g++.old-deja/g++.mike/ns5.C b/gcc/testsuite/g++.old-deja/g++.mike/ns5.C
index 9d806ca..f13da04 100644
--- a/gcc/testsuite/g++.old-deja/g++.mike/ns5.C
+++ b/gcc/testsuite/g++.old-deja/g++.mike/ns5.C
@@ -4,3 +4,4 @@ namespace A {
}
int j = i; // { dg-error "" }
+ // { dg-message "note" "suggested alternative" { target *-*-* } 6 }
diff --git a/gcc/testsuite/g++.old-deja/g++.mike/ns7.C b/gcc/testsuite/g++.old-deja/g++.mike/ns7.C
index 57008db..31a71dd 100644
--- a/gcc/testsuite/g++.old-deja/g++.mike/ns7.C
+++ b/gcc/testsuite/g++.old-deja/g++.mike/ns7.C
@@ -6,4 +6,5 @@ namespace A {
namespace B {
int j = i; // { dg-error "" }
+ // { dg-message "note" "suggested alternative" { target *-*-* } 8 }
}
diff --git a/gcc/testsuite/g++.old-deja/g++.ns/koenig5.C b/gcc/testsuite/g++.old-deja/g++.ns/koenig5.C
index 33061ad..67b781d 100644
--- a/gcc/testsuite/g++.old-deja/g++.ns/koenig5.C
+++ b/gcc/testsuite/g++.old-deja/g++.ns/koenig5.C
@@ -15,4 +15,5 @@ void g()
// foo variable first, and therefore do not
// perform argument-dependent lookup.
bar(new X); // { dg-error "not declared" }
+ // { dg-message "note" "suggested alternative" { target *-*-* } 17 }
}
diff --git a/gcc/testsuite/g++.old-deja/g++.ns/koenig9.C b/gcc/testsuite/g++.old-deja/g++.ns/koenig9.C
index 78b0e8b..f246639 100644
--- a/gcc/testsuite/g++.old-deja/g++.ns/koenig9.C
+++ b/gcc/testsuite/g++.old-deja/g++.ns/koenig9.C
@@ -10,4 +10,5 @@ void foo(const char*,...);
inline void
bar() {
foo("",count); // { dg-error "" } multiple overloaded count functions
+ // { dg-message "note" "suggested alternative" { target *-*-* } 12 }
}
diff --git a/gcc/testsuite/g++.old-deja/g++.other/lineno5.C b/gcc/testsuite/g++.old-deja/g++.other/lineno5.C
index d14bd90..20e49bc 100644
--- a/gcc/testsuite/g++.old-deja/g++.other/lineno5.C
+++ b/gcc/testsuite/g++.old-deja/g++.other/lineno5.C
@@ -16,4 +16,5 @@ namespace tmp {
class A {
public:
int kaka(tmp::B = b); // { dg-error "" } no b in scope
+ // { dg-message "note" "suggested alternative" { target *-*-* } 18 }
};