@@ -8177,6 +8177,7 @@ void
c_family_tests (void)
{
c_format_c_tests ();
+ c_spellcheck_cc_tests ();
}
} // namespace selftest
@@ -1450,6 +1450,7 @@ namespace selftest {
/* Declarations for specific families of tests within c-family,
by source file, in alphabetical order. */
extern void c_format_c_tests (void);
+ extern void c_spellcheck_cc_tests (void);
/* The entrypoint for running all of the above tests. */
extern void c_family_tests (void);
@@ -25,6 +25,37 @@ along with GCC; see the file COPYING3. If not see
#include "cpplib.h"
#include "spellcheck-tree.h"
#include "c-family/c-spellcheck.h"
+#include "selftest.h"
+
+/* Return true iff STR begin with an underscore and either an uppercase
+ letter or another underscore, and is thus, for C and C++, reserved for
+ use by the implementation. */
+
+bool
+name_reserved_for_implementation_p (const char *str)
+{
+ if (str[0] != '_')
+ return false;
+ return (str[1] == '_' || ISUPPER(str[1]));
+}
+
+/* Return true iff HASHNODE is a macro that should be offered as a
+ suggestion for a misspelling. */
+
+static bool
+should_suggest_as_macro_p (cpp_hashnode *hashnode)
+{
+ if (hashnode->type != NT_MACRO)
+ return false;
+
+ /* Don't suggest names reserved for the implementation, but do suggest the builtin
+ macros such as __FILE__, __LINE__ etc. */
+ if (name_reserved_for_implementation_p ((const char *)hashnode->ident.str)
+ && !(hashnode->flags & NODE_BUILTIN))
+ return false;
+
+ return true;
+}
/* A callback for cpp_forall_identifiers, for use by best_macro_match's ctor.
Process HASHNODE and update the best_macro_match instance pointed to be
@@ -34,7 +65,7 @@ static int
find_closest_macro_cpp_cb (cpp_reader *, cpp_hashnode *hashnode,
void *user_data)
{
- if (hashnode->type != NT_MACRO)
+ if (!should_suggest_as_macro_p (hashnode))
return 1;
best_macro_match *bmm = (best_macro_match *)user_data;
@@ -55,3 +86,36 @@ best_macro_match::best_macro_match (tree goal,
{
cpp_forall_identifiers (reader, find_closest_macro_cpp_cb, this);
}
+
+#if CHECKING_P
+
+namespace selftest {
+
+/* Selftests. */
+
+/* Verify that name_reserved_for_implementation_p is sane. */
+
+static void
+test_name_reserved_for_implementation_p ()
+{
+ ASSERT_FALSE (name_reserved_for_implementation_p (""));
+ ASSERT_FALSE (name_reserved_for_implementation_p ("foo"));
+ ASSERT_FALSE (name_reserved_for_implementation_p ("_"));
+ ASSERT_FALSE (name_reserved_for_implementation_p ("_foo"));
+ ASSERT_FALSE (name_reserved_for_implementation_p ("_42"));
+ ASSERT_TRUE (name_reserved_for_implementation_p ("_Foo"));
+ ASSERT_TRUE (name_reserved_for_implementation_p ("__"));
+ ASSERT_TRUE (name_reserved_for_implementation_p ("__foo"));
+}
+
+/* Run all of the selftests within this file. */
+
+void
+c_spellcheck_cc_tests ()
+{
+ test_name_reserved_for_implementation_p ();
+}
+
+} // namespace selftest
+
+#endif /* #if CHECKING_P */
@@ -22,6 +22,8 @@ along with GCC; see the file COPYING3. If not see
#include "spellcheck.h"
+extern bool name_reserved_for_implementation_p (const char *str);
+
/* Specialization of edit_distance_traits for preprocessor macros. */
template <>
@@ -4027,6 +4027,9 @@ lookup_name_fuzzy (tree name, enum lookup_name_fuzzy_kind kind, location_t loc)
IDENTIFIER_POINTER (name),
header_hint));
+ bool name_reserved
+ = name_reserved_for_implementation_p (IDENTIFIER_POINTER (name));
+
best_match<tree, tree> bm (name);
/* Look within currently valid scopes. */
@@ -4042,6 +4045,14 @@ lookup_name_fuzzy (tree name, enum lookup_name_fuzzy_kind kind, location_t loc)
if (TREE_CODE (binding->decl) == FUNCTION_DECL)
if (C_DECL_IMPLICIT (binding->decl))
continue;
+ /* Don't suggest names that are reserved for use by the
+ implementation, unless NAME itself is reserved. */
+ if (!name_reserved)
+ {
+ const char *suggestion_str = IDENTIFIER_POINTER (binding->id);
+ if (name_reserved_for_implementation_p (suggestion_str))
+ continue;
+ }
switch (kind)
{
case FUZZY_LOOKUP_TYPENAME:
@@ -5614,6 +5614,9 @@ consider_binding_level (tree name, best_match <tree, const char *> &bm,
bm.consider (IDENTIFIER_POINTER (best_matching_field));
}
+ bool name_reserved
+ = name_reserved_for_implementation_p (IDENTIFIER_POINTER (name));
+
for (tree t = lvl->names; t; t = TREE_CHAIN (t))
{
tree d = t;
@@ -5634,10 +5637,23 @@ consider_binding_level (tree name, best_match <tree, const char *> &bm,
&& DECL_ANTICIPATED (d))
continue;
- if (tree name = DECL_NAME (d))
- /* Ignore internal names with spaces in them. */
- if (!strchr (IDENTIFIER_POINTER (name), ' '))
- bm.consider (IDENTIFIER_POINTER (name));
+ tree suggestion = DECL_NAME (d);
+ if (!suggestion)
+ continue;
+
+ const char *suggestion_str = IDENTIFIER_POINTER (suggestion);
+
+ /* Ignore internal names with spaces in them. */
+ if (strchr (suggestion_str, ' '))
+ continue;
+
+ /* Don't suggest names that are reserved for use by the
+ implementation, unless NAME itself is reserved. */
+ if (name_reserved_for_implementation_p (suggestion_str)
+ && !name_reserved)
+ continue;
+
+ bm.consider (suggestion_str);
}
}
new file mode 100644
@@ -0,0 +1,35 @@
+/* Verify that we don't offer names that are reserved for the
+ implementation (PR c/83236). */
+/* { dg-options "-nostdinc" } */
+
+/* Example of an identifier with a leading double-underscore.
+ We shouldn't offer '__ino_t' as a suggestion for an unknown 'ino_t'. */
+
+typedef unsigned long int __ino_t;
+ino_t inode; /* { dg-error "did you mean 'int'" } */
+
+
+/* Example of a typedef with a leading double-underscore. */
+
+typedef unsigned char __u_char;
+u_char ch; /* { dg-error "did you mean 'char'" } */
+
+
+/* Example of a macro with a leading double-underscore. */
+
+# define __SOME_MACRO int
+
+SOME_MACRO foo; /* { dg-bogus "__SOME_MACRO" } */
+/* { dg-error "'SOME_MACRO'" "" { target *-*-* } .-1 } */
+
+
+/* If the misspelled name itself matches the "reserved" pattern, then
+ it's OK to suggest such names. */
+
+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 "not declared" "" { target c++ } misspelled_reserved } */
+ /* { dg-message "'__builtin_strrchr'" "" { target c++ } misspelled_reserved } */
+}