@@ -3113,7 +3113,19 @@ implicit_decl_warning (location_t loc, tree id, tree olddecl)
bool warned;
name_hint hint;
- if (!olddecl)
+ if (olddecl)
+ {
+ /* It might be due to a missing header.
+ Provide a hint, without looking for misspellings. */
+ const char *header_hint
+ = get_c_stdlib_header_for_name (IDENTIFIER_POINTER (id));
+ if (header_hint)
+ hint = name_hint (NULL,
+ new suggest_missing_header (loc,
+ IDENTIFIER_POINTER (id),
+ header_hint));
+ }
+ else
hint = lookup_name_fuzzy (id, FUZZY_LOOKUP_FUNCTION_NAME, loc);
if (flag_isoc99)
new file mode 100644
@@ -0,0 +1,38 @@
+/* Test coverage for header suggestions for common names in the stdlib
+ for which -Wimplicit-function-declaration only emits one message. */
+
+/* { dg-options "-Wimplicit-function-declaration" } */
+
+/* Missing <stdio.h>. */
+
+void test_stdio_h (void)
+{
+ fopen ("test.txt"); /* { dg-warning "implicit declaration" } */
+ /* { dg-message "'#include <stdio.h>'" "" { target *-*-* } .-1 } */
+
+ getchar (); /* { dg-warning "implicit declaration" } */
+ /* { dg-message "'#include <stdio.h>'" "" { target *-*-* } .-1 } */
+}
+
+/* Missing <string.h>. */
+
+void test_string_h (char *dest, char *src)
+{
+ char buf[16];
+ memcmp(dest, src, 4); /* { dg-warning "implicit declaration" } */
+ /* { dg-message "'#include <string.h>'" "" { target *-*-* } .-1 } */
+ strcmp(dest, "test"); /* { dg-warning "implicit declaration" } */
+ /* { dg-message "'#include <string.h>'" "" { target *-*-* } .-1 } */
+ strncmp(dest, "test", 3); /* { dg-warning "implicit declaration" } */
+ /* { dg-message "'#include <string.h>'" "" { target *-*-* } .-1 } */
+ snprintf (buf, 16, "test\n"); /* { dg-warning "implicit declaration" } */
+ /* { dg-message "include '<stdio.h>'" "" { target *-*-* } .-1 } */
+}
+
+/* Missing <assert.h>. */
+
+void test (int a, int b)
+{
+ assert (a == b); /* { dg-warning "implicit declaration" } */
+ // { dg-message "'#include <assert.h>'" "" { target *-*-* } .-1 }
+}
new file mode 100644
@@ -0,0 +1,16 @@
+/* Test coverage for header suggestions for common names in the stdlib
+ for which -Wimplicit-function-declaration leads to two messages
+ being emitted. */
+
+/* { dg-options "-Wimplicit-function-declaration" } */
+
+/* Missing <stdio.h>. */
+
+void test_stdio_h (void)
+{
+ char buf[16];
+ sprintf (buf, "test\n"); /* { dg-warning "implicit declaration of function 'sprintf'" } */
+ /* { dg-message "'sprintf' is defined in header '<stdio.h>'; did you forget to '#include <stdio.h>'." "" { target *-*-* } .-1 } */
+ /* { dg-warning "incompatible implicit declaration of built-in function 'sprintf'" "" { target *-*-* } .-2 } */
+ /* { dg-message "include '<stdio.h>' or provide a declaration of 'sprintf'" "" { target *-*-* } .-3 } */
+}
@@ -36,6 +36,12 @@ void test_stdio_h (void)
EOF; /* { dg-error "'EOF' undeclared" } */
/* { dg-message "'EOF' is defined in header '<stdio.h>'; did you forget to '#include <stdio.h>'?" "" { target *-*-* } .-1 } */
+
+ printf ("test\n"); /* { dg-warning "incompatible implicit declaration" } */
+ /* { dg-message "include '<stdio.h>'" "" { target *-*-* } .-1 } */
+
+ sprintf (buf, "test\n"); /* { dg-warning "incompatible implicit declaration" } */
+ /* { dg-message "include '<stdio.h>'" "" { target *-*-* } .-1 } */
}
/* Missing <errno.h>. */
@@ -62,3 +68,47 @@ int test_INT_MAX (void)
/* { dg-bogus "__INT_MAX__" "" { target *-*-* } INT_MAX_line } */
/* { dg-message "'INT_MAX' is defined in header '<limits.h>'; did you forget to '#include <limits.h>'?" "" { target *-*-* } INT_MAX_line } */
}
+
+/* Missing <string.h>. */
+
+void test_string_h (char *dest, char *src)
+{
+ memchr(dest, 'a', 4); /* { dg-warning "incompatible implicit declaration" } */
+ /* { dg-message "include '<string.h>'" "" { target *-*-* } .-1 } */
+ memcpy(dest, src, 4); /* { dg-warning "incompatible implicit declaration" } */
+ /* { dg-message "include '<string.h>'" "" { target *-*-* } .-1 } */
+ memmove(dest, src, 4); /* { dg-warning "incompatible implicit declaration" } */
+ /* { dg-message "include '<string.h>'" "" { target *-*-* } .-1 } */
+ memset(dest, 'a', 4); /* { dg-warning "incompatible implicit declaration" } */
+ /* { dg-message "include '<string.h>'" "" { target *-*-* } .-1 } */
+ strcat(dest, "test"); /* { dg-warning "incompatible implicit declaration" } */
+ /* { dg-message "include '<string.h>'" "" { target *-*-* } .-1 } */
+ strchr("test", 'e'); /* { dg-warning "incompatible implicit declaration" } */
+ /* { dg-message "include '<string.h>'" "" { target *-*-* } .-1 } */
+ strcpy(dest, "test"); /* { dg-warning "incompatible implicit declaration" } */
+ /* { dg-message "include '<string.h>'" "" { target *-*-* } .-1 } */
+ strlen("test"); /* { dg-warning "incompatible implicit declaration" } */
+ /* { dg-message "include '<string.h>'" "" { target *-*-* } .-1 } */
+ strncat(dest, "test", 3); /* { dg-warning "incompatible implicit declaration" } */
+ /* { dg-message "include '<string.h>'" "" { target *-*-* } .-1 } */
+ strncpy(dest, "test", 3); /* { dg-warning "incompatible implicit declaration" } */
+ /* { dg-message "include '<string.h>'" "" { target *-*-* } .-1 } */
+ strrchr("test", 'e'); /* { dg-warning "incompatible implicit declaration" } */
+ /* { dg-message "include '<string.h>'" "" { target *-*-* } .-1 } */
+ strspn(dest, "test"); /* { dg-warning "incompatible implicit declaration" } */
+ /* { dg-message "include '<string.h>'" "" { target *-*-* } .-1 } */
+ strstr(dest, "test"); /* { dg-warning "incompatible implicit declaration" } */
+ /* { dg-message "include '<string.h>'" "" { target *-*-* } .-1 } */
+}
+
+/* Missing <stdlib.h>. */
+
+void test_stdlib_h (void *q)
+{
+ void *ptr = malloc (64); /* { dg-warning "incompatible implicit declaration" } */
+ /* { dg-message "include '<stdlib.h>'" "" { target *-*-* } .-1 } */
+ free (ptr); /* { dg-warning "incompatible implicit declaration" } */
+ /* { dg-message "include '<stdlib.h>'" "" { target *-*-* } .-1 } */
+ q = realloc (q, 1024); /* { dg-warning "incompatible implicit declaration" } */
+ /* { dg-message "include '<stdlib.h>'" "" { target *-*-* } .-1 } */
+}