diff --git a/gcc/cp/name-lookup.c b/gcc/cp/name-lookup.c index 190b56bf4dd..774c4473390 100644 --- a/gcc/cp/name-lookup.c +++ b/gcc/cp/name-lookup.c @@ -6077,6 +6077,9 @@ qualified_namespace_lookup (tree scope, name_lookup *lookup) return found; } +/* If DECL is suitably visible to the user, consider its name for + spelling correction. */ + static void consider_decl (tree decl, best_match &bm, bool consider_impl_names) @@ -6110,6 +6113,65 @@ consider_decl (tree decl, best_match &bm, bm.consider (suggestion_str); } +/* If DECL is suitably visible to the user, add its name to VEC and + return true. Otherwise return false. */ + +static bool +maybe_add_fuzzy_decl (auto_vec &vec, tree decl) +{ + /* Skip compiler-generated variables (e.g. __for_begin/__for_end + within range for). */ + if (TREE_CODE (decl) == VAR_DECL && DECL_ARTIFICIAL (decl)) + return false; + + tree suggestion = DECL_NAME (decl); + if (!suggestion) + return false; + + /* Don't suggest names that are for anonymous aggregate types, as + they are an implementation detail generated by the compiler. */ + if (IDENTIFIER_ANON_P (suggestion)) + return false; + + vec.safe_push (suggestion); + + return true; +} + +/* Examing the namespace binding BINDING, and add at most one instance + of the name, if it contains a visible entity of interest. */ + +void +maybe_add_fuzzy_binding (auto_vec &vec, tree binding, + lookup_name_fuzzy_kind kind) +{ + tree value = NULL_TREE; + + if (STAT_HACK_P (binding)) + { + if (!STAT_TYPE_HIDDEN_P (binding) + && STAT_TYPE (binding)) + { + if (maybe_add_fuzzy_decl (vec, STAT_TYPE (binding))) + return; + } + else if (!STAT_DECL_HIDDEN_P (binding)) + value = STAT_DECL (binding); + } + else + value = binding; + + value = ovl_skip_hidden (value); + if (value) + { + value = OVL_FIRST (value); + if (kind != FUZZY_LOOKUP_TYPENAME + || TREE_CODE (STRIP_TEMPLATE (value)) == TYPE_DECL) + if (maybe_add_fuzzy_decl (vec, value)) + return; + } +} + /* Helper function for lookup_name_fuzzy. Traverse binding level LVL, looking for good name matches for NAME (and BM). */ @@ -6157,38 +6219,46 @@ consider_binding_level (tree name, best_match &bm, } else { - /* Iterate over the namespace hash table, that'll have fewer - entries than the decl list. */ + /* We need to iterate over the namespace hash table, in order to + not mention hidden entities. But hash table iteration is + (essentially) unpredictable, our correction-distance measure + is very granular, and we pick the first of equal distances. + Hence, we need to call the distance-measurer in a predictable + order. So, iterate over the namespace hash, inserting + visible names into a vector. Then sort the vector. Then + determine spelling distance. */ + tree ns = lvl->this_entity; + auto_vec vec; hash_table::iterator end (DECL_NAMESPACE_BINDINGS (ns)->end ()); for (hash_table::iterator iter (DECL_NAMESPACE_BINDINGS (ns)->begin ()); iter != end; ++iter) - { - tree binding = *iter; - tree value = NULL_TREE; + maybe_add_fuzzy_binding (vec, *iter, kind); - if (STAT_HACK_P (binding)) - { - if (!STAT_TYPE_HIDDEN_P (binding) - && STAT_TYPE (binding)) - consider_decl (STAT_TYPE (binding), bm, - consider_implementation_names); - else if (!STAT_DECL_HIDDEN_P (binding)) - value = STAT_DECL (binding); - } - else - value = binding; + vec.qsort ([] (const void *a_, const void *b_) + { + return strcmp (IDENTIFIER_POINTER (*(const tree *)a_), + IDENTIFIER_POINTER (*(const tree *)b_)); + }); + + /* Examine longest to shortest. */ + for (unsigned ix = vec.length (); ix--;) + { + const char *str = IDENTIFIER_POINTER (vec[ix]); + + /* Ignore internal names with spaces in them. */ + if (strchr (str, ' ')) + continue; - value = ovl_skip_hidden (value); - if (value) - { - value = OVL_FIRST (value); - if (!(kind == FUZZY_LOOKUP_TYPENAME - && TREE_CODE (STRIP_TEMPLATE (value)) != TYPE_DECL)) - consider_decl (value, bm, consider_implementation_names); - } + /* Don't suggest names that are reserved for use by the + implementation, unless NAME began with an underscore. */ + if (!consider_implementation_names + && name_reserved_for_implementation_p (str)) + continue; + + bm.consider (str); } } } diff --git a/gcc/testsuite/c-c++-common/spellcheck-reserved.c b/gcc/testsuite/c-c++-common/spellcheck-reserved.c index 175ba4a2e0f..ed292f2bae0 100644 --- a/gcc/testsuite/c-c++-common/spellcheck-reserved.c +++ b/gcc/testsuite/c-c++-common/spellcheck-reserved.c @@ -30,7 +30,7 @@ void test (const char *buf, char ch) { __builtin_strtchr (buf, ch); /* { dg-line misspelled_reserved } */ /* { dg-warning "did you mean '__builtin_strchr'" "" { target c } misspelled_reserved } */ - /* { dg-error "'__builtin_strtchr' was not declared in this scope; did you mean '__builtin_strchr'\\?" "" { target c++ } misspelled_reserved } */ + /* { dg-error "'__builtin_strtchr' was not declared in this scope; did you mean '__builtin_strrchr'\\?" "" { target c++ } misspelled_reserved } */ } /* Similarly for a name that begins with a single underscore. */