Commit f2e9fe5f by Martin Sebor

PR c/94040 - ICE on a call to an invalid redeclaration of strftime

gcc/c/ChangeLog:

	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.

gcc/testsuite/ChangeLog:

	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.
parent 9ae8bc02
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> 2020-03-05 Joseph Myers <joseph@codesourcery.com>
PR c/93577 PR c/93577
......
...@@ -1641,13 +1641,17 @@ c_bind (location_t loc, tree decl, bool is_global) ...@@ -1641,13 +1641,17 @@ c_bind (location_t loc, tree decl, bool is_global)
} }
/* Stores the first FILE*, const struct tm* etc. argument type (whatever it /* Stores the first FILE*, const struct tm* etc. argument type (whatever
is) seen in a declaration of a file I/O etc. built-in. Subsequent it is) seen in a declaration of a file I/O etc. built-in, corresponding
declarations of such built-ins are expected to refer to it rather than to to the builtin_structptr_types array. Subsequent declarations of such
fileptr_type_node etc. which is just void* (or to any other type). 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. */ 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 /* Returns true if types T1 and T2 representing return types or types
of function arguments are close enough to be considered interchangeable of function arguments are close enough to be considered interchangeable
...@@ -1692,10 +1696,13 @@ match_builtin_function_types (tree newtype, tree oldtype, ...@@ -1692,10 +1696,13 @@ match_builtin_function_types (tree newtype, tree oldtype,
tree newargs = TYPE_ARG_TYPES (newtype); tree newargs = TYPE_ARG_TYPES (newtype);
tree tryargs = newargs; tree tryargs = newargs;
gcc_checking_assert ((sizeof (last_structptr_types) const unsigned nlst
/ sizeof (last_structptr_types[0])) = sizeof last_structptr_types / sizeof last_structptr_types[0];
== (sizeof (builtin_structptr_types) const unsigned nbst
/ sizeof (builtin_structptr_types[0]))); = sizeof builtin_structptr_types / sizeof builtin_structptr_types[0];
gcc_checking_assert (nlst == nbst);
for (unsigned i = 1; oldargs || newargs; ++i) for (unsigned i = 1; oldargs || newargs; ++i)
{ {
if (!oldargs if (!oldargs
...@@ -1710,11 +1717,12 @@ match_builtin_function_types (tree newtype, tree oldtype, ...@@ -1710,11 +1717,12 @@ match_builtin_function_types (tree newtype, tree oldtype,
if (!types_close_enough_to_match (oldtype, newtype)) if (!types_close_enough_to_match (oldtype, newtype))
return NULL_TREE; return NULL_TREE;
unsigned j = (sizeof (builtin_structptr_types) unsigned j = nbst;
/ sizeof (builtin_structptr_types[0]));
if (POINTER_TYPE_P (oldtype)) if (POINTER_TYPE_P (oldtype))
for (j = 0; j < (sizeof (builtin_structptr_types) /* Iterate over well-known struct types like FILE (whose types
/ sizeof (builtin_structptr_types[0])); ++j) 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) if (TREE_VALUE (oldargs) != builtin_structptr_types[j].node)
continue; continue;
...@@ -1734,13 +1742,26 @@ match_builtin_function_types (tree newtype, tree oldtype, ...@@ -1734,13 +1742,26 @@ match_builtin_function_types (tree newtype, tree oldtype,
last_structptr_types[j] = newtype; last_structptr_types[j] = newtype;
break; break;
} }
if (j == (sizeof (builtin_structptr_types)
/ sizeof (builtin_structptr_types[0])) if (j == nbst && !comptypes (oldtype, newtype))
&& !*strict
&& !comptypes (oldtype, newtype))
{ {
*argno = i; if (POINTER_TYPE_P (oldtype))
*strict = 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); oldargs = TREE_CHAIN (oldargs);
...@@ -1965,9 +1986,8 @@ diagnose_mismatched_decls (tree newdecl, tree olddecl, ...@@ -1965,9 +1986,8 @@ diagnose_mismatched_decls (tree newdecl, tree olddecl,
{ {
/* Accept "harmless" mismatches in function types such /* Accept "harmless" mismatches in function types such
as missing qualifiers or int vs long when they're the same as missing qualifiers or int vs long when they're the same
size. However, with -Wextra in effect, diagnose return and size. However, diagnose return and argument types that are
argument types that are incompatible according to language incompatible according to language rules. */
rules. */
tree mismatch_expect; tree mismatch_expect;
unsigned mismatch_argno; unsigned mismatch_argno;
...@@ -2002,8 +2022,6 @@ diagnose_mismatched_decls (tree newdecl, tree olddecl, ...@@ -2002,8 +2022,6 @@ diagnose_mismatched_decls (tree newdecl, tree olddecl,
if (mismatch_expect && extra_warnings) if (mismatch_expect && extra_warnings)
{ {
/* If types match only loosely, print a warning but accept
the redeclaration. */
location_t newloc = DECL_SOURCE_LOCATION (newdecl); location_t newloc = DECL_SOURCE_LOCATION (newdecl);
bool warned = false; bool warned = false;
if (mismatch_argno) 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> 2020-03-13 Uroš Bizjak <ubizjak@gmail.com>
* gcc.target/i386/pr64409.c: Do not limit compilation to x32 targets. * gcc.target/i386/pr64409.c: Do not limit compilation to x32 targets.
......
...@@ -3,6 +3,6 @@ ...@@ -3,6 +3,6 @@
{ dg-do compile } { dg-do compile }
{ dg-options "-Wbuiltin-declaration-mismatch -Wextra" } */ { 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" }
/* 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;
}
/* 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;
}
...@@ -15,3 +15,5 @@ log_bad_request () ...@@ -15,3 +15,5 @@ log_bad_request ()
{ {
b += sprintf (0, "foo"); b += sprintf (0, "foo");
} }
/* { dg-prune-output "\\\[-Wbuiltin-declaration-mismatch]" } */
...@@ -2,7 +2,7 @@ ...@@ -2,7 +2,7 @@
/* { dg-do compile } */ /* { dg-do compile } */
/* { dg-options "-O2 -Wbuiltin-declaration-mismatch -Wextra" } */ /* { 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 bar (void);
void void
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment