diagnostics: Consistently add fixit hint for implicit builtin declaration

Message ID 20200528231609.10361-1-mark@klomp.org
State New
Headers show
Series
  • diagnostics: Consistently add fixit hint for implicit builtin declaration
Related show

Commit Message

Mark Wielaard May 28, 2020, 11:16 p.m.
There are two warnings that might trigger when a builtin function is
used but not declared yet. Both called through implicitly_declare in
c-decl. The first in implicit_decl_warning does warn for builtins,
but does not add a fixit hint for them (only for non-builtins when
a header is suggested through lookup_name_fuzzy). This warning is
guarded by -Wimplicit-function-declaration. The second warning, which
does include a fixit hint if possible, is given when the implicit
builtin declaration has an incompatible signature. This second warning
cannot be disabled.

This setup means that you only get a fixit-hint for usage of builtin
functions where the implicit signature is different than the actual
signature of the builtin. No fixit hints with header suggestions
are ever generated for builtins like abs, isdigit or putchar.

It seems more consistent to always generate a fixit-hint if possible
for the -Wimplicit-function-declaration warning. And for the second
warning to make it depend on -Wbuiltin-declaration-mismatch like
other warnings about builtin declaration mismatches.

Include a new test to show we get fixit-hints for abs, isdigit and
putchar now. And some small tweaks to existing tests to show the
effect of -Wno-builtin-declaration-mismatch with this change.

A nice follow-up would be to merge the built-in missing headers table
from header_for_builtin_fn in c/c-decl.c with the known headers in
c-family/known-headers.cc so that they can also be used in the C++
frontend unqualified_name_lookup_error through suggest_alternatives_for.

gcc/c/ChangeLog:

	* c-decl.c (implicit_decl_warning): When warned and olddecl is
	an undeclared builtin, then add a fixit header hint, if found.
	(implicitly_declare): Add OPT_Wbuiltin_declaration_mismatch to
	warning_at about implicit builtin declaration type mismatch.

gcc/testsuite/ChangeLog:

	* gcc.dg/missing-header-fixit-4.c: Add
	-Wno-implicit-function-declaration.
	* gcc.dg/missing-header-fixit-4.c: Add new expected output.
	* gcc.dg/missing-header-fixit-5.c: New testcase.
---
 gcc/c/c-decl.c                                | 30 ++++++++++++++--
 gcc/testsuite/gcc.dg/missing-header-fixit-3.c |  2 +-
 gcc/testsuite/gcc.dg/missing-header-fixit-4.c |  4 +++
 gcc/testsuite/gcc.dg/missing-header-fixit-5.c | 36 +++++++++++++++++++
 4 files changed, 68 insertions(+), 4 deletions(-)
 create mode 100644 gcc/testsuite/gcc.dg/missing-header-fixit-5.c

-- 
2.18.4

Comments

Kewen.Lin via Gcc-patches May 29, 2020, 12:21 a.m. | #1
On 5/28/20 5:16 PM, Mark Wielaard wrote:
> There are two warnings that might trigger when a builtin function is

> used but not declared yet. Both called through implicitly_declare in

> c-decl. The first in implicit_decl_warning does warn for builtins,

> but does not add a fixit hint for them (only for non-builtins when

> a header is suggested through lookup_name_fuzzy). This warning is

> guarded by -Wimplicit-function-declaration. The second warning, which

> does include a fixit hint if possible, is given when the implicit

> builtin declaration has an incompatible signature. This second warning

> cannot be disabled.

> 

> This setup means that you only get a fixit-hint for usage of builtin

> functions where the implicit signature is different than the actual

> signature of the builtin. No fixit hints with header suggestions

> are ever generated for builtins like abs, isdigit or putchar.

> 

> It seems more consistent to always generate a fixit-hint if possible

> for the -Wimplicit-function-declaration warning. And for the second

> warning to make it depend on -Wbuiltin-declaration-mismatch like

> other warnings about builtin declaration mismatches.

> 

> Include a new test to show we get fixit-hints for abs, isdigit and

> putchar now. And some small tweaks to existing tests to show the

> effect of -Wno-builtin-declaration-mismatch with this change.

> 

> A nice follow-up would be to merge the built-in missing headers table

> from header_for_builtin_fn in c/c-decl.c with the known headers in

> c-family/known-headers.cc so that they can also be used in the C++

> frontend unqualified_name_lookup_error through suggest_alternatives_for.


This is much more in David's domain than mine but since I promised
to look at it let me just say it seems like a nice improvement :)

Although few tests bother with it, since you add an option for
the existing warning where there was none before, an even more
exhaustive test than the one you added would also verify the same
option can be used to suppress it (e.g., via #pragma GCC diagnostic
ignored).

Martin

> 

> gcc/c/ChangeLog:

> 

> 	* c-decl.c (implicit_decl_warning): When warned and olddecl is

> 	an undeclared builtin, then add a fixit header hint, if found.

> 	(implicitly_declare): Add OPT_Wbuiltin_declaration_mismatch to

> 	warning_at about implicit builtin declaration type mismatch.

> 

> gcc/testsuite/ChangeLog:

> 

> 	* gcc.dg/missing-header-fixit-4.c: Add

> 	-Wno-implicit-function-declaration.

> 	* gcc.dg/missing-header-fixit-4.c: Add new expected output.

> 	* gcc.dg/missing-header-fixit-5.c: New testcase.

> ---

>   gcc/c/c-decl.c                                | 30 ++++++++++++++--

>   gcc/testsuite/gcc.dg/missing-header-fixit-3.c |  2 +-

>   gcc/testsuite/gcc.dg/missing-header-fixit-4.c |  4 +++

>   gcc/testsuite/gcc.dg/missing-header-fixit-5.c | 36 +++++++++++++++++++

>   4 files changed, 68 insertions(+), 4 deletions(-)

>   create mode 100644 gcc/testsuite/gcc.dg/missing-header-fixit-5.c

> 

> diff --git a/gcc/c/c-decl.c b/gcc/c/c-decl.c

> index b3e05be0af87..81bd2ee94f02 100644

> --- a/gcc/c/c-decl.c

> +++ b/gcc/c/c-decl.c

> @@ -3368,8 +3368,30 @@ implicit_decl_warning (location_t loc, tree id, tree olddecl)

>       warned = warning_at (loc, OPT_Wimplicit_function_declaration,

>   			 G_("implicit declaration of function %qE"), id);

>   

> -  if (olddecl && warned)

> -    locate_old_decl (olddecl);

> +  if (warned)

> +    {

> +      /* Whether the olddecl is an undeclared builtin function.

> +	 locate_old_decl will not generate a diagnostic for those,

> +	 so in that case we want to look elsewhere.  */

> +      bool undeclared_builtin = (olddecl

> +				 && TREE_CODE (olddecl) == FUNCTION_DECL

> +				 && fndecl_built_in_p (olddecl)

> +				 && !C_DECL_DECLARED_BUILTIN (olddecl));

> +      if (undeclared_builtin)

> +	{

> +	  const char *header = header_for_builtin_fn (olddecl);

> +	  if (header)

> +	    {

> +	      rich_location richloc (line_table, loc);

> +	      maybe_add_include_fixit (&richloc, header, true);

> +	      inform (&richloc,

> +		      "include %qs or provide a declaration of %qE",

> +		      header, id);

> +	    }

> +	}

> +      else if (olddecl)

> +	locate_old_decl (olddecl);

> +    }

>   

>     if (!warned)

>       hint.suppress ();

> @@ -3631,7 +3653,9 @@ implicitly_declare (location_t loc, tree functionid)

>   						      (TREE_TYPE (decl)));

>   	      if (!comptypes (newtype, TREE_TYPE (decl)))

>   		{

> -		  bool warned = warning_at (loc, 0, "incompatible implicit "

> +		  bool warned = warning_at (loc,

> +					    OPT_Wbuiltin_declaration_mismatch,

> +					    "incompatible implicit "

>   					    "declaration of built-in "

>   					    "function %qD", decl);

>   		  /* See if we can hint which header to include.  */

> diff --git a/gcc/testsuite/gcc.dg/missing-header-fixit-3.c b/gcc/testsuite/gcc.dg/missing-header-fixit-3.c

> index dd53bf65d3c8..8394010c1ac1 100644

> --- a/gcc/testsuite/gcc.dg/missing-header-fixit-3.c

> +++ b/gcc/testsuite/gcc.dg/missing-header-fixit-3.c

> @@ -2,7 +2,7 @@

>      adding them to the top of the file, given that there is no

>      pre-existing #include.  */

>   

> -/* { dg-options "-fdiagnostics-show-caret -fdiagnostics-show-line-numbers" } */

> +/* { dg-options "-fdiagnostics-show-caret -fdiagnostics-show-line-numbers -Wno-implicit-function-declaration" } */

>   

>   void test (int i, int j)

>   {

> diff --git a/gcc/testsuite/gcc.dg/missing-header-fixit-4.c b/gcc/testsuite/gcc.dg/missing-header-fixit-4.c

> index 942897d8c79f..b6680563dc13 100644

> --- a/gcc/testsuite/gcc.dg/missing-header-fixit-4.c

> +++ b/gcc/testsuite/gcc.dg/missing-header-fixit-4.c

> @@ -9,6 +9,10 @@ void test (int i, int j)

>   {

>     printf ("%i of %i\n", i, j); /* { dg-line printf } */

>     /* { dg-warning "implicit declaration of function" "" { target *-*-* } printf } */

> +  /* { dg-begin-multiline-output "" }

> +   10 |   printf ("%i of %i\n", i, j);

> +      |   ^~~~~~

> +   { dg-end-multiline-output "" } */

>     /* { dg-warning "incompatible implicit declaration" "" { target *-*-* } printf } */

>     /* { dg-begin-multiline-output "" }

>      10 |   printf ("%i of %i\n", i, j);

> diff --git a/gcc/testsuite/gcc.dg/missing-header-fixit-5.c b/gcc/testsuite/gcc.dg/missing-header-fixit-5.c

> new file mode 100644

> index 000000000000..916033c689c9

> --- /dev/null

> +++ b/gcc/testsuite/gcc.dg/missing-header-fixit-5.c

> @@ -0,0 +1,36 @@

> +

> +/* Forget to include any standard headers, all for built-in functions.

> +   Rely on -Wimplicit-function-declaration for fixit hints, not on

> +   -Wbuiltin-declaration-mismatch (which misses abs, isdigit, putchar).  */

> +

> +/* { dg-options "-fdiagnostics-show-caret -fdiagnostics-show-line-numbers -Wimplicit-function-declaration -Wno-builtin-declaration-mismatch" } */

> +

> +int

> +foo (char *m, int i)

> +{

> +  if (isdigit (m[0])) /* { dg-warning "implicit declaration of function" } */

> +  /* { dg-begin-multiline-output "" }

> +   11 |   if (isdigit (m[0]))

> +      |       ^~~~~~~

> +  +++ |+#include <ctype.h>

> +    1 |

> +     { dg-end-multiline-output "" } */

> +    {

> +      return abs (i); /* { dg-warning "implicit declaration of function" } */

> +  /* { dg-begin-multiline-output "" }

> +   19 |       return abs (i);

> +      |              ^~~

> +  +++ |+#include <stdlib.h>

> +    1 |

> +     { dg-end-multiline-output "" } */

> +    }

> +  else

> +    putchar (m[0]); /* { dg-warning "implicit declaration of function" } */

> +  /* { dg-begin-multiline-output "" }

> +   28 |     putchar (m[0]);

> +      |     ^~~~~~~

> +  +++ |+#include <stdio.h>

> +    1 |

> +     { dg-end-multiline-output "" } */

> +  return i;

> +}

>
Mark Wielaard May 29, 2020, 1:13 a.m. | #2
Hi Martin,

On Thu, May 28, 2020 at 06:21:39PM -0600, Martin Sebor wrote:
> Although few tests bother with it, since you add an option for

> the existing warning where there was none before, an even more

> exhaustive test than the one you added would also verify the same

> option can be used to suppress it (e.g., via #pragma GCC diagnostic

> ignored).


OK. How about this variant with an extra
Wbuiltin-declaration-mismatch-ignore.c test?
It FAILS with (test for excess errors) before the patch.
It PASSes with the patch.

Thanks,

Mark
From a35979eee900c57ebf5c60f2eea7f8e4eb6d0464 Mon Sep 17 00:00:00 2001
From: Mark Wielaard <mark@klomp.org>

Date: Thu, 28 May 2020 02:55:36 +0200
Subject: [PATCH] diagnostics: Consistently add fixit hint for implicit builtin
 declaration

There are two warnings that might trigger when a builtin function is
used but not declared yet. Both called through implicitly_declare in
c-decl. The first in implicit_decl_warning does warn for builtins,
but does not add a fixit hint for them (only for non-builtins when
a header is suggested through lookup_name_fuzzy). This warning is
guarded by -Wimplicit-function-declaration. The second warning, which
does include a fixit hint if possible, is given when the implicit
builtin declaration has an incompatible signature. This second warning
cannot be disabled.

This setup means that you only get a fixit-hint for usage of builtin
functions where the implicit signature is different than the actual
signature of the builtin. No fixit hints with header suggestions
are ever generated for builtins like abs, isdigit or putchar.

It seems more consistent to always generate a fixit-hint if possible
for the -Wimplicit-function-declaration warning. And for the second
warning to make it depend on -Wbuiltin-declaration-mismatch like
other warnings about builtin declaration mismatches.

Include a new test to show we get fixit-hints for abs, isdigit and
putchar now. Some small tweaks to existing tests to show the
effect of -Wno-builtin-declaration-mismatch with this change. And
a testcase to show that #pragma GCC diagnostic ignored now works.

gcc/c/ChangeLog:

	* c-decl.c (implicit_decl_warning): When warned and olddecl is
	an undeclared builtin, then add a fixit header hint, if found.
	(implicitly_declare): Add OPT_Wbuiltin_declaration_mismatch to
	warning_at about implicit builtin declaration type mismatch.

gcc/testsuite/ChangeLog:

	* gcc.dg/missing-header-fixit-4.c: Add
	-Wno-implicit-function-declaration.
	* gcc.dg/missing-header-fixit-4.c: Add new expected output.
	* gcc.dg/missing-header-fixit-5.c: New testcase.
	* gcc.dg/Wbuiltin-declaration-mismatch-ignore.c: Likewise.
---
 gcc/c/c-decl.c                                | 30 ++++++++++++++--
 .../Wbuiltin-declaration-mismatch-ignore.c    | 11 ++++++
 gcc/testsuite/gcc.dg/missing-header-fixit-3.c |  2 +-
 gcc/testsuite/gcc.dg/missing-header-fixit-4.c |  4 +++
 gcc/testsuite/gcc.dg/missing-header-fixit-5.c | 36 +++++++++++++++++++
 5 files changed, 79 insertions(+), 4 deletions(-)
 create mode 100644 gcc/testsuite/gcc.dg/Wbuiltin-declaration-mismatch-ignore.c
 create mode 100644 gcc/testsuite/gcc.dg/missing-header-fixit-5.c

diff --git a/gcc/c/c-decl.c b/gcc/c/c-decl.c
index b3e05be0af87..81bd2ee94f02 100644
--- a/gcc/c/c-decl.c
+++ b/gcc/c/c-decl.c
@@ -3368,8 +3368,30 @@ implicit_decl_warning (location_t loc, tree id, tree olddecl)
     warned = warning_at (loc, OPT_Wimplicit_function_declaration,
 			 G_("implicit declaration of function %qE"), id);
 
-  if (olddecl && warned)
-    locate_old_decl (olddecl);
+  if (warned)
+    {
+      /* Whether the olddecl is an undeclared builtin function.
+	 locate_old_decl will not generate a diagnostic for those,
+	 so in that case we want to look elsewhere.  */
+      bool undeclared_builtin = (olddecl
+				 && TREE_CODE (olddecl) == FUNCTION_DECL
+				 && fndecl_built_in_p (olddecl)
+				 && !C_DECL_DECLARED_BUILTIN (olddecl));
+      if (undeclared_builtin)
+	{
+	  const char *header = header_for_builtin_fn (olddecl);
+	  if (header)
+	    {
+	      rich_location richloc (line_table, loc);
+	      maybe_add_include_fixit (&richloc, header, true);
+	      inform (&richloc,
+		      "include %qs or provide a declaration of %qE",
+		      header, id);
+	    }
+	}
+      else if (olddecl)
+	locate_old_decl (olddecl);
+    }
 
   if (!warned)
     hint.suppress ();
@@ -3631,7 +3653,9 @@ implicitly_declare (location_t loc, tree functionid)
 						      (TREE_TYPE (decl)));
 	      if (!comptypes (newtype, TREE_TYPE (decl)))
 		{
-		  bool warned = warning_at (loc, 0, "incompatible implicit "
+		  bool warned = warning_at (loc,
+					    OPT_Wbuiltin_declaration_mismatch,
+					    "incompatible implicit "
 					    "declaration of built-in "
 					    "function %qD", decl);
 		  /* See if we can hint which header to include.  */
diff --git a/gcc/testsuite/gcc.dg/Wbuiltin-declaration-mismatch-ignore.c b/gcc/testsuite/gcc.dg/Wbuiltin-declaration-mismatch-ignore.c
new file mode 100644
index 000000000000..4af35d772115
--- /dev/null
+++ b/gcc/testsuite/gcc.dg/Wbuiltin-declaration-mismatch-ignore.c
@@ -0,0 +1,11 @@
+/* Check -Wbuiltin-declaration-mismatch can be ignored with pragma.  */
+/* { dg-do compile }
+   { dg-options "-Wno-implicit-function-declaration -Wno-int-conversion -Wbuiltin-declaration-mismatch" } */
+
+#pragma GCC diagnostic ignored "-Wbuiltin-declaration-mismatch"
+int foo (const char *str)
+{
+  int i;
+  sscanf (str, "%d", &i);
+  return i;
+}
diff --git a/gcc/testsuite/gcc.dg/missing-header-fixit-3.c b/gcc/testsuite/gcc.dg/missing-header-fixit-3.c
index dd53bf65d3c8..8394010c1ac1 100644
--- a/gcc/testsuite/gcc.dg/missing-header-fixit-3.c
+++ b/gcc/testsuite/gcc.dg/missing-header-fixit-3.c
@@ -2,7 +2,7 @@
    adding them to the top of the file, given that there is no
    pre-existing #include.  */
 
-/* { dg-options "-fdiagnostics-show-caret -fdiagnostics-show-line-numbers" } */
+/* { dg-options "-fdiagnostics-show-caret -fdiagnostics-show-line-numbers -Wno-implicit-function-declaration" } */
 
 void test (int i, int j)
 {
diff --git a/gcc/testsuite/gcc.dg/missing-header-fixit-4.c b/gcc/testsuite/gcc.dg/missing-header-fixit-4.c
index 942897d8c79f..b6680563dc13 100644
--- a/gcc/testsuite/gcc.dg/missing-header-fixit-4.c
+++ b/gcc/testsuite/gcc.dg/missing-header-fixit-4.c
@@ -9,6 +9,10 @@ void test (int i, int j)
 {
   printf ("%i of %i\n", i, j); /* { dg-line printf } */
   /* { dg-warning "implicit declaration of function" "" { target *-*-* } printf } */
+  /* { dg-begin-multiline-output "" }
+   10 |   printf ("%i of %i\n", i, j);
+      |   ^~~~~~
+   { dg-end-multiline-output "" } */
   /* { dg-warning "incompatible implicit declaration" "" { target *-*-* } printf } */
   /* { dg-begin-multiline-output "" }
    10 |   printf ("%i of %i\n", i, j);
diff --git a/gcc/testsuite/gcc.dg/missing-header-fixit-5.c b/gcc/testsuite/gcc.dg/missing-header-fixit-5.c
new file mode 100644
index 000000000000..916033c689c9
--- /dev/null
+++ b/gcc/testsuite/gcc.dg/missing-header-fixit-5.c
@@ -0,0 +1,36 @@
+
+/* Forget to include any standard headers, all for built-in functions.
+   Rely on -Wimplicit-function-declaration for fixit hints, not on
+   -Wbuiltin-declaration-mismatch (which misses abs, isdigit, putchar).  */
+
+/* { dg-options "-fdiagnostics-show-caret -fdiagnostics-show-line-numbers -Wimplicit-function-declaration -Wno-builtin-declaration-mismatch" } */
+
+int
+foo (char *m, int i)
+{
+  if (isdigit (m[0])) /* { dg-warning "implicit declaration of function" } */
+  /* { dg-begin-multiline-output "" }
+   11 |   if (isdigit (m[0]))
+      |       ^~~~~~~
+  +++ |+#include <ctype.h>
+    1 | 
+     { dg-end-multiline-output "" } */
+    {
+      return abs (i); /* { dg-warning "implicit declaration of function" } */
+  /* { dg-begin-multiline-output "" }
+   19 |       return abs (i);
+      |              ^~~
+  +++ |+#include <stdlib.h>
+    1 | 
+     { dg-end-multiline-output "" } */
+    }
+  else
+    putchar (m[0]); /* { dg-warning "implicit declaration of function" } */
+  /* { dg-begin-multiline-output "" }
+   28 |     putchar (m[0]);
+      |     ^~~~~~~
+  +++ |+#include <stdio.h>
+    1 | 
+     { dg-end-multiline-output "" } */
+  return i;
+}
-- 
2.18.4
Kewen.Lin via Gcc-patches May 29, 2020, 3:13 p.m. | #3
On 5/28/20 7:13 PM, Mark Wielaard wrote:
> Hi Martin,

> 

> On Thu, May 28, 2020 at 06:21:39PM -0600, Martin Sebor wrote:

>> Although few tests bother with it, since you add an option for

>> the existing warning where there was none before, an even more

>> exhaustive test than the one you added would also verify the same

>> option can be used to suppress it (e.g., via #pragma GCC diagnostic

>> ignored).

> 

> OK. How about this variant with an extra

> Wbuiltin-declaration-mismatch-ignore.c test?

> It FAILS with (test for excess errors) before the patch.

> It PASSes with the patch.


It looks good to me but I can't formally approve it.

Martin

> 

> Thanks,

> 

> Mark

>
Mark Wielaard June 4, 2020, 10:16 p.m. | #4
Hi,

On Fri, 2020-05-29 at 09:13 -0600, Martin Sebor wrote:
> On 5/28/20 7:13 PM, Mark Wielaard wrote:

> > On Thu, May 28, 2020 at 06:21:39PM -0600, Martin Sebor wrote:

> > > Although few tests bother with it, since you add an option for

> > > the existing warning where there was none before, an even more

> > > exhaustive test than the one you added would also verify the same

> > > option can be used to suppress it (e.g., via #pragma GCC

> > > diagnostic

> > > ignored).

> > 

> > OK. How about this variant with an extra

> > Wbuiltin-declaration-mismatch-ignore.c test?

> > It FAILS with (test for excess errors) before the patch.

> > It PASSes with the patch.

> 

> It looks good to me but I can't formally approve it.


Thanks. Rebased patch attached.
David, would you be able to approve it?
Or do we need to bribe a C frontend maintainer?

Cheers,

Mark
From 719b174233176fae49716936fa4ab9ead54f95cb Mon Sep 17 00:00:00 2001
From: Mark Wielaard <mark@klomp.org>
Date: Thu, 28 May 2020 02:55:36 +0200
Subject: [PATCH] diagnostics: Consistently add fixit hint for implicit builtin
 declaration

There are two warnings that might trigger when a builtin function is
used but not declared yet. Both called through implicitly_declare in
c-decl. The first in implicit_decl_warning does warn for builtins,
but does not add a fixit hint for them (only for non-builtins when
a header is suggested through lookup_name_fuzzy). This warning is
guarded by -Wimplicit-function-declaration. The second warning, which
does include a fixit hint if possible, is given when the implicit
builtin declaration has an incompatible signature. This second warning
cannot be disabled.

This setup means that you only get a fixit-hint for usage of builtin
functions where the implicit signature is different than the actual
signature of the builtin. No fixit hints with header suggestions
are ever generated for builtins like abs, isdigit or putchar.

It seems more consistent to always generate a fixit-hint if possible
for the -Wimplicit-function-declaration warning. And for the second
warning to make it depend on -Wbuiltin-declaration-mismatch like
other warnings about builtin declaration mismatches.

Include a new test to show we get fixit-hints for abs, isdigit and
putchar now. Some small tweaks to existing tests to show the
effect of -Wno-builtin-declaration-mismatch with this change. And
a testcase to show that #pragma GCC diagnostic ignored now works.

gcc/c/ChangeLog:

	* c-decl.c (implicit_decl_warning): When warned and olddecl is
	an undeclared builtin, then add a fixit header hint, if found.
	(implicitly_declare): Add OPT_Wbuiltin_declaration_mismatch to
	warning_at about implicit builtin declaration type mismatch.

gcc/testsuite/ChangeLog:

	* gcc.dg/missing-header-fixit-4.c: Add
	-Wno-implicit-function-declaration.
	* gcc.dg/missing-header-fixit-4.c: Add new expected output.
	* gcc.dg/missing-header-fixit-5.c: New testcase.
	* gcc.dg/Wbuiltin-declaration-mismatch-ignore.c: Likewise.
---
 gcc/c/c-decl.c                                | 30 ++++++++++++++--
 .../Wbuiltin-declaration-mismatch-ignore.c    | 11 ++++++
 gcc/testsuite/gcc.dg/missing-header-fixit-3.c |  2 +-
 gcc/testsuite/gcc.dg/missing-header-fixit-4.c |  4 +++
 gcc/testsuite/gcc.dg/missing-header-fixit-5.c | 36 +++++++++++++++++++
 5 files changed, 79 insertions(+), 4 deletions(-)
 create mode 100644 gcc/testsuite/gcc.dg/Wbuiltin-declaration-mismatch-ignore.c
 create mode 100644 gcc/testsuite/gcc.dg/missing-header-fixit-5.c

diff --git a/gcc/c/c-decl.c b/gcc/c/c-decl.c
index b3e05be0af87..81bd2ee94f02 100644
--- a/gcc/c/c-decl.c
+++ b/gcc/c/c-decl.c
@@ -3368,8 +3368,30 @@ implicit_decl_warning (location_t loc, tree id, tree olddecl)
     warned = warning_at (loc, OPT_Wimplicit_function_declaration,
 			 G_("implicit declaration of function %qE"), id);
 
-  if (olddecl && warned)
-    locate_old_decl (olddecl);
+  if (warned)
+    {
+      /* Whether the olddecl is an undeclared builtin function.
+	 locate_old_decl will not generate a diagnostic for those,
+	 so in that case we want to look elsewhere.  */
+      bool undeclared_builtin = (olddecl
+				 && TREE_CODE (olddecl) == FUNCTION_DECL
+				 && fndecl_built_in_p (olddecl)
+				 && !C_DECL_DECLARED_BUILTIN (olddecl));
+      if (undeclared_builtin)
+	{
+	  const char *header = header_for_builtin_fn (olddecl);
+	  if (header)
+	    {
+	      rich_location richloc (line_table, loc);
+	      maybe_add_include_fixit (&richloc, header, true);
+	      inform (&richloc,
+		      "include %qs or provide a declaration of %qE",
+		      header, id);
+	    }
+	}
+      else if (olddecl)
+	locate_old_decl (olddecl);
+    }
 
   if (!warned)
     hint.suppress ();
@@ -3631,7 +3653,9 @@ implicitly_declare (location_t loc, tree functionid)
 						      (TREE_TYPE (decl)));
 	      if (!comptypes (newtype, TREE_TYPE (decl)))
 		{
-		  bool warned = warning_at (loc, 0, "incompatible implicit "
+		  bool warned = warning_at (loc,
+					    OPT_Wbuiltin_declaration_mismatch,
+					    "incompatible implicit "
 					    "declaration of built-in "
 					    "function %qD", decl);
 		  /* See if we can hint which header to include.  */
diff --git a/gcc/testsuite/gcc.dg/Wbuiltin-declaration-mismatch-ignore.c b/gcc/testsuite/gcc.dg/Wbuiltin-declaration-mismatch-ignore.c
new file mode 100644
index 000000000000..732c23f91b10
--- /dev/null
+++ b/gcc/testsuite/gcc.dg/Wbuiltin-declaration-mismatch-ignore.c
@@ -0,0 +1,11 @@
+/* Check -Wbuiltin-declaration-mismatch can be ignored with pragma.  */
+/* { dg-do compile }
+   { dg-options "-Wno-implicit-function-declaration -Wno-int-conversion -Wbuiltin-declaration-mismatch" } */
+
+#pragma GCC diagnostic ignored "-Wbuiltin-declaration-mismatch"
+int foo (const char *str)
+{
+  int i;
+  sscanf (str, "%d", &i);
+  return i;
+}
diff --git a/gcc/testsuite/gcc.dg/missing-header-fixit-3.c b/gcc/testsuite/gcc.dg/missing-header-fixit-3.c
index dd53bf65d3c8..8394010c1ac1 100644
--- a/gcc/testsuite/gcc.dg/missing-header-fixit-3.c
+++ b/gcc/testsuite/gcc.dg/missing-header-fixit-3.c
@@ -2,7 +2,7 @@
    adding them to the top of the file, given that there is no
    pre-existing #include.  */
 
-/* { dg-options "-fdiagnostics-show-caret -fdiagnostics-show-line-numbers" } */
+/* { dg-options "-fdiagnostics-show-caret -fdiagnostics-show-line-numbers -Wno-implicit-function-declaration" } */
 
 void test (int i, int j)
 {
diff --git a/gcc/testsuite/gcc.dg/missing-header-fixit-4.c b/gcc/testsuite/gcc.dg/missing-header-fixit-4.c
index 942897d8c79f..b6680563dc13 100644
--- a/gcc/testsuite/gcc.dg/missing-header-fixit-4.c
+++ b/gcc/testsuite/gcc.dg/missing-header-fixit-4.c
@@ -9,6 +9,10 @@ void test (int i, int j)
 {
   printf ("%i of %i\n", i, j); /* { dg-line printf } */
   /* { dg-warning "implicit declaration of function" "" { target *-*-* } printf } */
+  /* { dg-begin-multiline-output "" }
+   10 |   printf ("%i of %i\n", i, j);
+      |   ^~~~~~
+   { dg-end-multiline-output "" } */
   /* { dg-warning "incompatible implicit declaration" "" { target *-*-* } printf } */
   /* { dg-begin-multiline-output "" }
    10 |   printf ("%i of %i\n", i, j);
diff --git a/gcc/testsuite/gcc.dg/missing-header-fixit-5.c b/gcc/testsuite/gcc.dg/missing-header-fixit-5.c
new file mode 100644
index 000000000000..916033c689c9
--- /dev/null
+++ b/gcc/testsuite/gcc.dg/missing-header-fixit-5.c
@@ -0,0 +1,36 @@
+
+/* Forget to include any standard headers, all for built-in functions.
+   Rely on -Wimplicit-function-declaration for fixit hints, not on
+   -Wbuiltin-declaration-mismatch (which misses abs, isdigit, putchar).  */
+
+/* { dg-options "-fdiagnostics-show-caret -fdiagnostics-show-line-numbers -Wimplicit-function-declaration -Wno-builtin-declaration-mismatch" } */
+
+int
+foo (char *m, int i)
+{
+  if (isdigit (m[0])) /* { dg-warning "implicit declaration of function" } */
+  /* { dg-begin-multiline-output "" }
+   11 |   if (isdigit (m[0]))
+      |       ^~~~~~~
+  +++ |+#include <ctype.h>
+    1 | 
+     { dg-end-multiline-output "" } */
+    {
+      return abs (i); /* { dg-warning "implicit declaration of function" } */
+  /* { dg-begin-multiline-output "" }
+   19 |       return abs (i);
+      |              ^~~
+  +++ |+#include <stdlib.h>
+    1 | 
+     { dg-end-multiline-output "" } */
+    }
+  else
+    putchar (m[0]); /* { dg-warning "implicit declaration of function" } */
+  /* { dg-begin-multiline-output "" }
+   28 |     putchar (m[0]);
+      |     ^~~~~~~
+  +++ |+#include <stdio.h>
+    1 | 
+     { dg-end-multiline-output "" } */
+  return i;
+}
Joseph Myers June 5, 2020, 2:44 p.m. | #5
This patch is OK.

-- 
Joseph S. Myers
joseph@codesourcery.com

Patch

diff --git a/gcc/c/c-decl.c b/gcc/c/c-decl.c
index b3e05be0af87..81bd2ee94f02 100644
--- a/gcc/c/c-decl.c
+++ b/gcc/c/c-decl.c
@@ -3368,8 +3368,30 @@  implicit_decl_warning (location_t loc, tree id, tree olddecl)
     warned = warning_at (loc, OPT_Wimplicit_function_declaration,
 			 G_("implicit declaration of function %qE"), id);
 
-  if (olddecl && warned)
-    locate_old_decl (olddecl);
+  if (warned)
+    {
+      /* Whether the olddecl is an undeclared builtin function.
+	 locate_old_decl will not generate a diagnostic for those,
+	 so in that case we want to look elsewhere.  */
+      bool undeclared_builtin = (olddecl
+				 && TREE_CODE (olddecl) == FUNCTION_DECL
+				 && fndecl_built_in_p (olddecl)
+				 && !C_DECL_DECLARED_BUILTIN (olddecl));
+      if (undeclared_builtin)
+	{
+	  const char *header = header_for_builtin_fn (olddecl);
+	  if (header)
+	    {
+	      rich_location richloc (line_table, loc);
+	      maybe_add_include_fixit (&richloc, header, true);
+	      inform (&richloc,
+		      "include %qs or provide a declaration of %qE",
+		      header, id);
+	    }
+	}
+      else if (olddecl)
+	locate_old_decl (olddecl);
+    }
 
   if (!warned)
     hint.suppress ();
@@ -3631,7 +3653,9 @@  implicitly_declare (location_t loc, tree functionid)
 						      (TREE_TYPE (decl)));
 	      if (!comptypes (newtype, TREE_TYPE (decl)))
 		{
-		  bool warned = warning_at (loc, 0, "incompatible implicit "
+		  bool warned = warning_at (loc,
+					    OPT_Wbuiltin_declaration_mismatch,
+					    "incompatible implicit "
 					    "declaration of built-in "
 					    "function %qD", decl);
 		  /* See if we can hint which header to include.  */
diff --git a/gcc/testsuite/gcc.dg/missing-header-fixit-3.c b/gcc/testsuite/gcc.dg/missing-header-fixit-3.c
index dd53bf65d3c8..8394010c1ac1 100644
--- a/gcc/testsuite/gcc.dg/missing-header-fixit-3.c
+++ b/gcc/testsuite/gcc.dg/missing-header-fixit-3.c
@@ -2,7 +2,7 @@ 
    adding them to the top of the file, given that there is no
    pre-existing #include.  */
 
-/* { dg-options "-fdiagnostics-show-caret -fdiagnostics-show-line-numbers" } */
+/* { dg-options "-fdiagnostics-show-caret -fdiagnostics-show-line-numbers -Wno-implicit-function-declaration" } */
 
 void test (int i, int j)
 {
diff --git a/gcc/testsuite/gcc.dg/missing-header-fixit-4.c b/gcc/testsuite/gcc.dg/missing-header-fixit-4.c
index 942897d8c79f..b6680563dc13 100644
--- a/gcc/testsuite/gcc.dg/missing-header-fixit-4.c
+++ b/gcc/testsuite/gcc.dg/missing-header-fixit-4.c
@@ -9,6 +9,10 @@  void test (int i, int j)
 {
   printf ("%i of %i\n", i, j); /* { dg-line printf } */
   /* { dg-warning "implicit declaration of function" "" { target *-*-* } printf } */
+  /* { dg-begin-multiline-output "" }
+   10 |   printf ("%i of %i\n", i, j);
+      |   ^~~~~~
+   { dg-end-multiline-output "" } */
   /* { dg-warning "incompatible implicit declaration" "" { target *-*-* } printf } */
   /* { dg-begin-multiline-output "" }
    10 |   printf ("%i of %i\n", i, j);
diff --git a/gcc/testsuite/gcc.dg/missing-header-fixit-5.c b/gcc/testsuite/gcc.dg/missing-header-fixit-5.c
new file mode 100644
index 000000000000..916033c689c9
--- /dev/null
+++ b/gcc/testsuite/gcc.dg/missing-header-fixit-5.c
@@ -0,0 +1,36 @@ 
+
+/* Forget to include any standard headers, all for built-in functions.
+   Rely on -Wimplicit-function-declaration for fixit hints, not on
+   -Wbuiltin-declaration-mismatch (which misses abs, isdigit, putchar).  */
+
+/* { dg-options "-fdiagnostics-show-caret -fdiagnostics-show-line-numbers -Wimplicit-function-declaration -Wno-builtin-declaration-mismatch" } */
+
+int
+foo (char *m, int i)
+{
+  if (isdigit (m[0])) /* { dg-warning "implicit declaration of function" } */
+  /* { dg-begin-multiline-output "" }
+   11 |   if (isdigit (m[0]))
+      |       ^~~~~~~
+  +++ |+#include <ctype.h>
+    1 | 
+     { dg-end-multiline-output "" } */
+    {
+      return abs (i); /* { dg-warning "implicit declaration of function" } */
+  /* { dg-begin-multiline-output "" }
+   19 |       return abs (i);
+      |              ^~~
+  +++ |+#include <stdlib.h>
+    1 | 
+     { dg-end-multiline-output "" } */
+    }
+  else
+    putchar (m[0]); /* { dg-warning "implicit declaration of function" } */
+  /* { dg-begin-multiline-output "" }
+   28 |     putchar (m[0]);
+      |     ^~~~~~~
+  +++ |+#include <stdio.h>
+    1 | 
+     { dg-end-multiline-output "" } */
+  return i;
+}