Hi!
Here is an untested patch that should fix all of that, ok for trunk
if it passes bootstrap/regtest on {x86_64,i686}-linux?
Notes:
1) seems the C++ FE is even stricter and uses the
builtin_structptr_types[x].str string to verify the pointed type
has the right TYPE_NAME; is that something we want to require
for C also? That would mean we'd warn about
Wbuiltin-declaration-mismatch-6.c etc. too, because it uses:
struct StdioFile;
int fprintf (struct StdioFile*, const char*, ...);
If it was
typedef struct StdioFile FILE;
int fprintf (FILE*, const char*, ...);
that would be accepted then. Also, unlike C++, C has struct tags vs.
typedef tags as separate namespaces, so we'd need to either handle
it specially for struct tm (where the standard prototype is
const struct tm *, not const tm *) vs. the rest, or accept struct
as well as typedef names equal to builtin_structptr_types[x].str,
or don't do anything here (I didn't want to be even stricter than
Martin's patch)
2) it accepts any kind of pointed type and just requires it is the same
later on, so it accepts e.g.
struct StdioFile;
typedef struct StdioFile FILE;
int fprintf (const FILE *, const char *, ...);
and then requires those pointers to be the same in all cases.
Shall we verify the qualifiers on the pointed type before we accept
it into last_structptr_types? If yes, right now it would emit
weird diagnostics (request that the type would be say const void *
instead of struct tm *)
3) for fexcept_t and fenv_t, there are actually 2 types for each,
const {fexcept,fenv}_t * vs. {fexcept,fenv}_t *. No verification
is done that the TYPE_MAIN_VARIANT is the same between both if both
are seen. This only makes sense if 2) is implemented, and would
probably work if both 1) and 2) are implemented without anything
further.
Not planning to work on these myself, all I want to fix is the breakage.
2019-01-26 Jakub Jelinek <[email protected]>
PR c/86125
* c-decl.c (last_fileptr_type): Remove.
(last_structptr_types): New variable.
(match_builtin_function_types): Compare TYPE_MAIN_VARIANT of
{old,new}rettype instead of the types themselves. Assert
last_structptr_types array has the same number of elements
as builtin_structptr_types array. Use TYPE_MAIN_VARIANT for
argument oldtype and newtype. Instead of handling
just fileptr_type_node specially, handle all builtin_structptr_types
pointer nodes. Formatting fix.
* c-common.c (c_common_nodes_and_builtins): Build type variants for
builtin_structptr_types types even for C.
* gcc.dg/Wbuiltin-declaration-mismatch-7.c: Guard testcase for
lp64, ilp32 and llp64 only.
(fputs): Use unsigned long long instead of size_t for return type.
(vfprintf, vfscanf): Accept arbitrary target specific type for
va_list.
--- gcc/c/c-decl.c.jj 2019-01-25 23:46:06.121198286 +0100
+++ gcc/c/c-decl.c 2019-01-26 15:34:02.749450800 +0100
@@ -1632,13 +1632,13 @@ c_bind (location_t loc, tree decl, bool
}
-/* Stores the first FILE* argument type (whatever it is) seen in
- a declaration of a file I/O built-in. Subsequent declarations
- of such built-ins are expected to refer to it rather than to
- fileptr_type_node 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. 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_fileptr_type;
+static GTY(()) tree last_structptr_types[6];
/* Subroutine of compare_decls. Allow harmless mismatches in return
and argument types provided that the type modes match. Set *STRICT
@@ -1660,13 +1660,18 @@ match_builtin_function_types (tree newty
if (TYPE_MODE (oldrettype) != TYPE_MODE (newrettype))
return NULL_TREE;
- if (!comptypes (oldrettype, newrettype))
+ if (!comptypes (TYPE_MAIN_VARIANT (oldrettype),
+ TYPE_MAIN_VARIANT (newrettype)))
*strict = oldrettype;
tree oldargs = TYPE_ARG_TYPES (oldtype);
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])));
for (unsigned i = 1; oldargs || newargs; ++i)
{
if (!oldargs
@@ -1675,8 +1680,8 @@ match_builtin_function_types (tree newty
|| !TREE_VALUE (newargs))
return NULL_TREE;
- tree oldtype = TREE_VALUE (oldargs);
- tree newtype = TREE_VALUE (newargs);
+ tree oldtype = TYPE_MAIN_VARIANT (TREE_VALUE (oldargs));
+ tree newtype = TYPE_MAIN_VARIANT (TREE_VALUE (newargs));
/* Fail for types with incompatible modes/sizes. */
if (TYPE_MODE (TREE_VALUE (oldargs))
@@ -1684,28 +1689,39 @@ match_builtin_function_types (tree newty
return NULL_TREE;
/* Fail for function and object pointer mismatches. */
- if (FUNCTION_POINTER_TYPE_P (oldtype) != FUNCTION_POINTER_TYPE_P
(newtype)
+ if ((FUNCTION_POINTER_TYPE_P (oldtype)
+ != FUNCTION_POINTER_TYPE_P (newtype))
|| POINTER_TYPE_P (oldtype) != POINTER_TYPE_P (newtype))
return NULL_TREE;
- if (oldtype == fileptr_type_node)
- {
- /* Store the first FILE* argument type (whatever it is), and
- expect any subsequent declarations of file I/O built-ins
- to refer to it rather than to fileptr_type_node which is
- just void*. */
- if (last_fileptr_type)
- {
- if (!comptypes (last_fileptr_type, newtype))
- {
- *argno = i;
- *strict = last_fileptr_type;
- }
- }
- else
- last_fileptr_type = newtype;
- }
- else if (!*strict && !comptypes (oldtype, newtype))
+ unsigned j = (sizeof (builtin_structptr_types)
+ / sizeof (builtin_structptr_types[0]));
+ if (POINTER_TYPE_P (oldtype))
+ for (j = 0; j < (sizeof (builtin_structptr_types)
+ / sizeof (builtin_structptr_types[0])); ++j)
+ {
+ if (TREE_VALUE (oldargs) != builtin_structptr_types[j].node)
+ continue;
+ /* Store the first FILE* etc. argument type (whatever it is), and
+ expect any subsequent declarations of file I/O etc. built-ins
+ to refer to it rather than to fileptr_type_node etc. which is
+ just void* (or const void*). */
+ if (last_structptr_types[j])
+ {
+ if (!comptypes (last_structptr_types[j], newtype))
+ {
+ *argno = i;
+ *strict = last_structptr_types[j];
+ }
+ }
+ else
+ last_structptr_types[j] = newtype;
+ break;
+ }
+ if (j == (sizeof (builtin_structptr_types)
+ / sizeof (builtin_structptr_types[0]))
+ && !*strict
+ && !comptypes (oldtype, newtype))
{
*argno = i;
*strict = oldtype;
--- gcc/c-family/c-common.c.jj 2019-01-16 09:35:04.566323056 +0100
+++ gcc/c-family/c-common.c 2019-01-26 14:39:04.909695084 +0100
@@ -4296,18 +4296,13 @@ c_common_nodes_and_builtins (void)
COMPLEX_FLOATN_NX_TYPE_NODE (i)));
}
- if (c_dialect_cxx ())
- {
- /* For C++, make fileptr_type_node a distinct void * type until
- FILE type is defined. Likewise for const struct tm*. */
- for (unsigned i = 0;
- i < sizeof (builtin_structptr_types)
- / sizeof (builtin_structptr_type);
- ++i)
- builtin_structptr_types[i].node =
- build_variant_type_copy (builtin_structptr_types[i].base);
-
- }
+ /* Make fileptr_type_node a distinct void * type until
+ FILE type is defined. Likewise for const struct tm*. */
+ for (unsigned i = 0;
+ i < sizeof (builtin_structptr_types) / sizeof (builtin_structptr_type);
+ ++i)
+ builtin_structptr_types[i].node
+ = build_variant_type_copy (builtin_structptr_types[i].base);
record_builtin_type (RID_VOID, NULL, void_type_node);
--- gcc/testsuite/gcc.dg/Wbuiltin-declaration-mismatch-7.c.jj 2019-01-25
06:08:50.629941283 +0100
+++ gcc/testsuite/gcc.dg/Wbuiltin-declaration-mismatch-7.c 2019-01-26
13:23:18.126323403 +0100
@@ -2,7 +2,7 @@
return type
Verify that a declaration of vfprintf() with withe the wrong last
argument triggers -Wbuiltin-declaration-mismatch even without -Wextra.
- { dg-do compile }
+ { dg-do compile { target { lp64 || ilp32 || llp64 } } }
{ dg-options "-Wbuiltin-declaration-mismatch" } */
struct StdioFile;
@@ -13,14 +13,14 @@ struct StdioFile;
int fprintf (struct StdioFile*, const char*); /* { dg-warning "conflicting
types for built-in function .fprintf.; expected .int\\\(\[a-z_\]+ \\\*, const
char \\\*, \.\.\.\\\)." } */
-int vfprintf (struct StdioFile*, const char*, ...); /* { dg-warning
"conflicting types for built-in function .vfprintf.; expected .int\\\(\[a-z_\]+
\\\*, const char \\\*, \[a-z_\]+ \\\*\\\)." } */
+int vfprintf (struct StdioFile*, const char*, ...); /* { dg-warning
"conflicting types for built-in function .vfprintf.; expected .int\\\(\[a-z_\]+
\\\*, const char \\\*, \[^\n\r,\\\)\]+\\\)." } */
int fputc (char, struct StdioFile*); /* { dg-warning "conflicting types for
built-in function .fputc.; expected .int\\\(int, void \\\*\\\)." } */
-size_t fputs (const char*, struct StdioFile*); /* { dg-warning "conflicting
types for built-in function .fputs.; expected .int\\\(const char \\\*,
\[a-z_\]+ \\\*\\\)." } */
+unsigned long long fputs (const char*, struct StdioFile*); /* { dg-warning
"conflicting types for built-in function .fputs.; expected .int\\\(const char
\\\*, \[a-z_\]+ \\\*\\\)." } */
int fscanf (struct StdioFile*, const char*, size_t, ...); /* { dg-warning
"conflicting types for built-in function .fscanf.; expected .int\\\(\[a-z_\]+
\\\*, const char \\\*, \.\.\.\\\)." } */
-int vfscanf (struct StdioFile*, const char*, ...); /* { dg-warning
"conflicting types for built-in function .vfscanf.; expected .int\\\(\[a-z_\]+
\\\*, const char \\\*, \[a-z_\]+ \\\*\\\)." } */
+int vfscanf (struct StdioFile*, const char*, ...); /* { dg-warning
"conflicting types for built-in function .vfscanf.; expected .int\\\(\[a-z_\]+
\\\*, const char \\\*, \[^\n\r,\\\)\]+\\\)." } */
size_t fwrite (const void*, size_t, size_t, struct StdioFile); /* {
dg-warning "conflicting types for built-in function .fwrite.; expected .\(long
\)?unsigned int\\\(const void \\\*, \(long \)?unsigned int, *\(long \)?unsigned
int, *\[a-z_\]+ \\\*\\\)." } */
--- gcc/testsuite/gcc.dg/Wbuiltin-declaration-mismatch-11.c.jj 2019-01-26
12:31:26.035636194 +0100
+++ gcc/testsuite/gcc.dg/Wbuiltin-declaration-mismatch-11.c 2019-01-26
14:16:38.869483474 +0100
@@ -0,0 +1,21 @@
+/* PR c/86125 */
+/* { dg-do compile } */
+/* { dg-options "-Wbuiltin-declaration-mismatch -Wextra
-Wno-ignored-qualifiers" } */
+
+typedef __SIZE_TYPE__ size_t;
+struct FILE;
+struct tm;
+struct fenv_t;
+struct fexcept_t;
+typedef struct FILE FILE;
+typedef struct fenv_t fenv_t;
+typedef struct fexcept_t fexcept_t;
+typedef const int cint;
+size_t strftime (char *__restrict, const size_t, const char *__restrict,
/* { dg-bogus "mismatch in argument 1 type of built-in function" } */
+ const struct tm *__restrict) __attribute__((nothrow));
+int fprintf (struct FILE *, const char *const, ...);
/* { dg-bogus "mismatch in argument 2 type of built-in function" } */
+cint putc (int, struct FILE *);
/* { dg-bogus "mismatch in return type of built-in function" } */
+cint fegetenv (fenv_t *);
/* { dg-bogus "mismatch in argument 1 type of built-in function" } */
+cint fesetenv (const fenv_t *);
/* { dg-bogus "mismatch in return type of built-in function" } */
+int fegetexceptflag (fexcept_t *, const int);
/* { dg-bogus "mismatch in argument 1 type of built-in function" } */
+int fesetexceptflag (const fexcept_t *, const int);
/* { dg-bogus "mismatch in argument 1 type of built-in function" } */
Jakub