+2020-03-13 Martin Sebor <msebor@redhat.com>
+
+ PR c/94040
+ * c-decl.c (builtin_structptr_type_count): New constant.
+ (match_builtin_function_types): Reject decls that are incompatible
+ in types pointed to by pointers.
+ (diagnose_mismatched_decls): Adjust comments.
+
2020-03-05 Joseph Myers <joseph@codesourcery.com>
PR c/93577
}
\f
-/* Stores the first FILE*, const struct tm* etc. argument type (whatever it
- is) seen in a declaration of a file I/O etc. built-in. Subsequent
- declarations of such built-ins are expected to refer to it rather than to
- fileptr_type_node etc. which is just void* (or to any other type).
+/* Stores the first FILE*, const struct tm* etc. argument type (whatever
+ it is) seen in a declaration of a file I/O etc. built-in, corresponding
+ to the builtin_structptr_types array. Subsequent declarations of such
+ built-ins are expected to refer to it rather than to fileptr_type_node,
+ etc. which is just void* (or to any other type).
Used only by match_builtin_function_types. */
-static GTY(()) tree last_structptr_types[6];
+static const unsigned builtin_structptr_type_count
+ = sizeof builtin_structptr_types / sizeof builtin_structptr_types[0];
+
+static GTY(()) tree last_structptr_types[builtin_structptr_type_count];
/* Returns true if types T1 and T2 representing return types or types
of function arguments are close enough to be considered interchangeable
tree newargs = TYPE_ARG_TYPES (newtype);
tree tryargs = newargs;
- gcc_checking_assert ((sizeof (last_structptr_types)
- / sizeof (last_structptr_types[0]))
- == (sizeof (builtin_structptr_types)
- / sizeof (builtin_structptr_types[0])));
+ const unsigned nlst
+ = sizeof last_structptr_types / sizeof last_structptr_types[0];
+ const unsigned nbst
+ = sizeof builtin_structptr_types / sizeof builtin_structptr_types[0];
+
+ gcc_checking_assert (nlst == nbst);
+
for (unsigned i = 1; oldargs || newargs; ++i)
{
if (!oldargs
if (!types_close_enough_to_match (oldtype, newtype))
return NULL_TREE;
- unsigned j = (sizeof (builtin_structptr_types)
- / sizeof (builtin_structptr_types[0]));
+ unsigned j = nbst;
if (POINTER_TYPE_P (oldtype))
- for (j = 0; j < (sizeof (builtin_structptr_types)
- / sizeof (builtin_structptr_types[0])); ++j)
+ /* Iterate over well-known struct types like FILE (whose types
+ aren't known to us) and compare the pointer to each to
+ the pointer argument. */
+ for (j = 0; j < nbst; ++j)
{
if (TREE_VALUE (oldargs) != builtin_structptr_types[j].node)
continue;
last_structptr_types[j] = newtype;
break;
}
- if (j == (sizeof (builtin_structptr_types)
- / sizeof (builtin_structptr_types[0]))
- && !*strict
- && !comptypes (oldtype, newtype))
+
+ if (j == nbst && !comptypes (oldtype, newtype))
{
- *argno = i;
- *strict = oldtype;
+ if (POINTER_TYPE_P (oldtype))
+ {
+ /* For incompatible pointers, only reject differences in
+ the unqualified variants of the referenced types but
+ consider differences in qualifiers as benign (report
+ those to caller via *STRICT below). */
+ tree oldref = TYPE_MAIN_VARIANT (TREE_TYPE (oldtype));
+ tree newref = TYPE_MAIN_VARIANT (TREE_TYPE (newtype));
+ if (!comptypes (oldref, newref))
+ return NULL_TREE;
+ }
+
+ if (!*strict)
+ {
+ *argno = i;
+ *strict = oldtype;
+ }
}
oldargs = TREE_CHAIN (oldargs);
{
/* Accept "harmless" mismatches in function types such
as missing qualifiers or int vs long when they're the same
- size. However, with -Wextra in effect, diagnose return and
- argument types that are incompatible according to language
- rules. */
+ size. However, diagnose return and argument types that are
+ incompatible according to language rules. */
tree mismatch_expect;
unsigned mismatch_argno;
if (mismatch_expect && extra_warnings)
{
- /* If types match only loosely, print a warning but accept
- the redeclaration. */
location_t newloc = DECL_SOURCE_LOCATION (newdecl);
bool warned = false;
if (mismatch_argno)
+2020-03-13 Martin Sebor <msebor@redhat.com>
+
+ PR c/94040
+ * gcc.dg/Wbuiltin-declaration-mismatch-12.c: Relax test to look
+ for warning name rather than the exact text.
+ * gcc.dg/Wbuiltin-declaration-mismatch-14.c: New test.
+ * gcc.dg/Wbuiltin-declaration-mismatch-15.c: New test.
+ * gcc.dg/pr62090.c: Prune expected warning.
+ * gcc.dg/pr89314.c: Look for warning name rather than text.
+
2020-03-13 Uroš Bizjak <ubizjak@gmail.com>
* gcc.target/i386/pr64409.c: Do not limit compilation to x32 targets.
{ dg-do compile }
{ dg-options "-Wbuiltin-declaration-mismatch -Wextra" } */
-extern void __clear_cache (char*, char*); /* { dg-warning "mismatch in argument 1 type of built-in function .__clear_cache.; expected .void \\\*." } */
+extern void __clear_cache (char*, char*); // { dg-warning "\\\[-Wbuiltin-declaration-mismatch" }
-void __builtin_prefetch (const char *, ...); /* { dg-warning "mismatch in argument 1 type of built-in function .__builtin_prefetch.; expected .const void \\\*." } */
+void __builtin_prefetch (const char *, ...); // { dg-warning "\\\[-Wbuiltin-declaration-mismatch" }
--- /dev/null
+/* PR c/94040 - ICE on a call to an invalid redeclaration of strftime
+ { dg-do compile }
+ { dg-options "-Wall" } */
+
+typedef __SIZE_TYPE__ size_t;
+
+struct tm;
+
+size_t strftime (char *, size_t, int *, struct tm *); // { dg-warning "-Wbuiltin-declaration-mismatch" }
+
+size_t call_strftime (char *d, size_t n, int *f, struct tm *t)
+{
+ size_t r = 0;
+ r += strftime (0, 0, 0, 0);
+ r += strftime (d, 0, 0, 0);
+ r += strftime (d, n, 0, 0);
+ r += strftime (d, n, f, 0);
+ r += strftime (d, n, f, t);
+ return r;
+}
+
+
+char* strchr (char*, char*); // { dg-warning "-Wbuiltin-declaration-mismatch" }
+
+// Verify that missing/extra qualifiers aren't diagnosed without -Wextra.
+
+int strcmp (char*, char*);
+int strncmp (volatile char*, volatile char*, size_t);
+
+// Verify that a difference in pointers is diagnosed.
+
+size_t strlen (const char**);
+// { dg-warning "-Wbuiltin-declaration-mismatch" "pointer" { target *-*-* } .-1 }
+
+ size_t strnlen (const char* const*, size_t);
+// { dg-warning "-Wbuiltin-declaration-mismatch" "pointer" { target *-*-* } .-1 }
+
+
+// Verify that calls to the compatibly-redeclared built-ins are treated
+// as those to the built-ins and diagnosed.
+
+int test_builtin_calls (size_t n)
+{
+ int r = 0;
+ r += strcmp ((char*)0, ""); // { dg-warning "\\\[-Wnonnull]" }
+ r += strcmp ("", (char*)0); // { dg-warning "\\\[-Wnonnull]" }
+
+ r += strncmp ((char*)0, "", n); // { dg-warning "\\\[-Wnonnull]" }
+ r += strncmp ("", (char*)0, n); // { dg-warning "\\\[-Wnonnull]" }
+
+ return r;
+}
+
+
+// Verify that calls to the incompatibly-redeclared built-ins are not
+// treated as those to the built-ins by the middle-end. It doesn't
+// matter if the front-end diagnoses them but the middle-end should
+// not because it shouldn't recognize them as built-ins.
+
+#pragma GCC optimize "2"
+
+size_t test_nonbuiltin_calls (char *s, int c)
+{
+ void *null = 0;
+
+ char *r;
+ r = strchr ((char*)null, s);
+ r = strchr (r, (char*)null);
+ *s = *r; // use the result
+
+ size_t n = 0;
+ n += strftime (0, 0, 0, 0);
+ n += strlen ((const char**)null);
+ n += strnlen ((const char**)null, n);
+
+ return n;
+}
--- /dev/null
+/* PR c/94040 - ICE on a call to an invalid redeclaration of strftime
+ { dg-do compile }
+ { dg-options "-Wall -Wextra" } */
+
+typedef __SIZE_TYPE__ size_t;
+
+struct tm;
+
+size_t strftime (const char *, size_t, char *, struct tm *);
+// { dg-warning "-Wbuiltin-declaration-mismatch" "arg 1" { target *-*-* } .-1 }
+
+// Verify that missing/extra qualifiers are diagnosed with -Wextra.
+
+int strcmp (char*, const char*);
+// { dg-warning "-Wbuiltin-declaration-mismatch" "arg 1" { target *-*-* } .-1 }
+
+int strncmp (const char*, volatile char*, size_t);
+// { dg-warning "-Wbuiltin-declaration-mismatch" "arg 2" { target *-*-* } .-1 }
+
+size_t strlen (char*);
+// { dg-warning "-Wbuiltin-declaration-mismatch" "arg 1" { target *-*-* } .-1 }
+
+
+// Verify that calls to built-ins declared with missing/extra qualifiers
+// are still treated as those to built-ins by the front-end.
+
+int test_builtin_calls_fe (size_t n)
+{
+ int r = 0;
+ r += strcmp ((char*)0, ""); // { dg-warning "\\\[-Wnonnull]" }
+ r += strcmp ("", (char*)0); // { dg-warning "\\\[-Wnonnull]" }
+
+ r += strncmp ((char*)0, "", n); // { dg-warning "\\\[-Wnonnull]" }
+ r += strncmp ("", (char*)0, n); // { dg-warning "\\\[-Wnonnull]" }
+
+ r += strlen ((char*)0); // { dg-warning "\\\[-Wnonnull]" }
+ return r;
+}
+
+
+// Ditto but by the middle-end.
+
+#pragma GCC optimize "2"
+
+int test_builtin_calls_me (void)
+{
+ char *null1 = 0;
+ char *null2 = null1;
+ char *null3 = null2;
+
+ int r = 0;
+ r += strcmp (null1, "123"); // { dg-warning "\\\[-Wnonnull]" }
+ r += strncmp ("2345", null2, 4); // { dg-warning "\\\[-Wnonnull]" }
+ r += strlen (null3); // { dg-warning "\\\[-Wnonnull]" }
+ return r;
+}
{
b += sprintf (0, "foo");
}
+
+/* { dg-prune-output "\\\[-Wbuiltin-declaration-mismatch]" } */
/* { dg-do compile } */
/* { dg-options "-O2 -Wbuiltin-declaration-mismatch -Wextra" } */
-extern __SIZE_TYPE__ strlen (const float *); /* { dg-warning "mismatch in argument 1 type of built-in function" } */
+extern __SIZE_TYPE__ strlen (const float *); /* { dg-warning "\\\[-Wbuiltin-declaration-mismatch" } */
void bar (void);
void