diff mbox

[C] Print header hints (PR c/59717)

Message ID 20141007125339.GE3503@redhat.com
State New
Headers show

Commit Message

Marek Polacek Oct. 7, 2014, 12:53 p.m. UTC
PR59717 is a request for hints which header to include if the compiler warns
about incompatible implicit declarations.  E.g., if one uses abort
without declaring it first, we now say
note: include ‘<stdlib.h>’ or provide a declaration of ‘abort’
I've added hints only for standard functions which means we won't display
the hint for functions such as mempcpy.

The implementation is based on a function that just maps built_in_function
codes to header names.

Two remarks:
* header_for_builtin_fn is long and I don't want to unnecessarily
  inflate already big c-decl.c file, so it might make sense to move
  the function into c-errors.c;
* we don't issue "incompatible implicit declaration of built-in function"
  warning for functions that return int and whose parameter types don't need
  default promotions - for instance putc, fputs, ilogb, strcmp, vprintf, isnan,
  isalpha, ...  Therefore for such functions we don't print the hint neither.
  header_for_builtin_fn is ready for them, though.  (The cases for <ctype.h>
  and <wctype.h> could be removed.)

Bootstrapped/regtested on x86_64-linux, ok for trunk?

2014-10-07  Marek Polacek  <polacek@redhat.com>

	PR c/59717
	* c-decl.c (header_for_builtin_fn): New function.
	(implicitly_declare): Suggest which header to include.

	* gcc.dg/pr59717.c: New test.


	Marek

Comments

Richard Biener Oct. 7, 2014, 2:39 p.m. UTC | #1
On Tue, Oct 7, 2014 at 2:53 PM, Marek Polacek <polacek@redhat.com> wrote:
> PR59717 is a request for hints which header to include if the compiler warns
> about incompatible implicit declarations.  E.g., if one uses abort
> without declaring it first, we now say
> note: include ‘<stdlib.h>’ or provide a declaration of ‘abort’
> I've added hints only for standard functions which means we won't display
> the hint for functions such as mempcpy.
>
> The implementation is based on a function that just maps built_in_function
> codes to header names.
>
> Two remarks:
> * header_for_builtin_fn is long and I don't want to unnecessarily
>   inflate already big c-decl.c file, so it might make sense to move
>   the function into c-errors.c;
> * we don't issue "incompatible implicit declaration of built-in function"
>   warning for functions that return int and whose parameter types don't need
>   default promotions - for instance putc, fputs, ilogb, strcmp, vprintf, isnan,
>   isalpha, ...  Therefore for such functions we don't print the hint neither.
>   header_for_builtin_fn is ready for them, though.  (The cases for <ctype.h>
>   and <wctype.h> could be removed.)
>
> Bootstrapped/regtested on x86_64-linux, ok for trunk?

Why not annotate builtins.def with the info?

Richard.

> 2014-10-07  Marek Polacek  <polacek@redhat.com>
>
>         PR c/59717
>         * c-decl.c (header_for_builtin_fn): New function.
>         (implicitly_declare): Suggest which header to include.
>
>         * gcc.dg/pr59717.c: New test.
>
> diff --git gcc/c/c-decl.c gcc/c/c-decl.c
> index ce5a8de..e23284a 100644
> --- gcc/c/c-decl.c
> +++ gcc/c/c-decl.c
> @@ -2968,6 +2968,189 @@ implicit_decl_warning (location_t loc, tree id, tree olddecl)
>      }
>  }
>
> +/* This function represents mapping of a function code FCODE
> +   to its respective header.  */
> +
> +static const char *
> +header_for_builtin_fn (enum built_in_function fcode)
> +{
> +  switch (fcode)
> +    {
> +    CASE_FLT_FN (BUILT_IN_ACOS):
> +    CASE_FLT_FN (BUILT_IN_ACOSH):
> +    CASE_FLT_FN (BUILT_IN_ASIN):
> +    CASE_FLT_FN (BUILT_IN_ASINH):
> +    CASE_FLT_FN (BUILT_IN_ATAN):
> +    CASE_FLT_FN (BUILT_IN_ATANH):
> +    CASE_FLT_FN (BUILT_IN_ATAN2):
> +    CASE_FLT_FN (BUILT_IN_CBRT):
> +    CASE_FLT_FN (BUILT_IN_CEIL):
> +    CASE_FLT_FN (BUILT_IN_COPYSIGN):
> +    CASE_FLT_FN (BUILT_IN_COS):
> +    CASE_FLT_FN (BUILT_IN_COSH):
> +    CASE_FLT_FN (BUILT_IN_ERF):
> +    CASE_FLT_FN (BUILT_IN_ERFC):
> +    CASE_FLT_FN (BUILT_IN_EXP):
> +    CASE_FLT_FN (BUILT_IN_EXP2):
> +    CASE_FLT_FN (BUILT_IN_EXPM1):
> +    CASE_FLT_FN (BUILT_IN_FABS):
> +    CASE_FLT_FN (BUILT_IN_FDIM):
> +    CASE_FLT_FN (BUILT_IN_FLOOR):
> +    CASE_FLT_FN (BUILT_IN_FMA):
> +    CASE_FLT_FN (BUILT_IN_FMAX):
> +    CASE_FLT_FN (BUILT_IN_FMIN):
> +    CASE_FLT_FN (BUILT_IN_FMOD):
> +    CASE_FLT_FN (BUILT_IN_FREXP):
> +    CASE_FLT_FN (BUILT_IN_HYPOT):
> +    CASE_FLT_FN (BUILT_IN_ILOGB):
> +    CASE_FLT_FN (BUILT_IN_LDEXP):
> +    CASE_FLT_FN (BUILT_IN_LGAMMA):
> +    CASE_FLT_FN (BUILT_IN_LLRINT):
> +    CASE_FLT_FN (BUILT_IN_LLROUND):
> +    CASE_FLT_FN (BUILT_IN_LOG):
> +    CASE_FLT_FN (BUILT_IN_LOG10):
> +    CASE_FLT_FN (BUILT_IN_LOG1P):
> +    CASE_FLT_FN (BUILT_IN_LOG2):
> +    CASE_FLT_FN (BUILT_IN_LOGB):
> +    CASE_FLT_FN (BUILT_IN_LRINT):
> +    CASE_FLT_FN (BUILT_IN_LROUND):
> +    CASE_FLT_FN (BUILT_IN_MODF):
> +    CASE_FLT_FN (BUILT_IN_NAN):
> +    CASE_FLT_FN (BUILT_IN_NEARBYINT):
> +    CASE_FLT_FN (BUILT_IN_NEXTAFTER):
> +    CASE_FLT_FN (BUILT_IN_NEXTTOWARD):
> +    CASE_FLT_FN (BUILT_IN_POW):
> +    CASE_FLT_FN (BUILT_IN_REMAINDER):
> +    CASE_FLT_FN (BUILT_IN_REMQUO):
> +    CASE_FLT_FN (BUILT_IN_RINT):
> +    CASE_FLT_FN (BUILT_IN_ROUND):
> +    CASE_FLT_FN (BUILT_IN_SCALBLN):
> +    CASE_FLT_FN (BUILT_IN_SCALBN):
> +    CASE_FLT_FN (BUILT_IN_SIN):
> +    CASE_FLT_FN (BUILT_IN_SINH):
> +    CASE_FLT_FN (BUILT_IN_SINCOS):
> +    CASE_FLT_FN (BUILT_IN_SQRT):
> +    CASE_FLT_FN (BUILT_IN_TAN):
> +    CASE_FLT_FN (BUILT_IN_TANH):
> +    CASE_FLT_FN (BUILT_IN_TGAMMA):
> +    CASE_FLT_FN (BUILT_IN_TRUNC):
> +    case BUILT_IN_ISINF:
> +    case BUILT_IN_ISNAN:
> +      return "<math.h>";
> +    CASE_FLT_FN (BUILT_IN_CABS):
> +    CASE_FLT_FN (BUILT_IN_CACOS):
> +    CASE_FLT_FN (BUILT_IN_CACOSH):
> +    CASE_FLT_FN (BUILT_IN_CARG):
> +    CASE_FLT_FN (BUILT_IN_CASIN):
> +    CASE_FLT_FN (BUILT_IN_CASINH):
> +    CASE_FLT_FN (BUILT_IN_CATAN):
> +    CASE_FLT_FN (BUILT_IN_CATANH):
> +    CASE_FLT_FN (BUILT_IN_CCOS):
> +    CASE_FLT_FN (BUILT_IN_CCOSH):
> +    CASE_FLT_FN (BUILT_IN_CEXP):
> +    CASE_FLT_FN (BUILT_IN_CIMAG):
> +    CASE_FLT_FN (BUILT_IN_CLOG):
> +    CASE_FLT_FN (BUILT_IN_CONJ):
> +    CASE_FLT_FN (BUILT_IN_CPOW):
> +    CASE_FLT_FN (BUILT_IN_CPROJ):
> +    CASE_FLT_FN (BUILT_IN_CREAL):
> +    CASE_FLT_FN (BUILT_IN_CSIN):
> +    CASE_FLT_FN (BUILT_IN_CSINH):
> +    CASE_FLT_FN (BUILT_IN_CSQRT):
> +    CASE_FLT_FN (BUILT_IN_CTAN):
> +    CASE_FLT_FN (BUILT_IN_CTANH):
> +      return "<complex.h>";
> +    case BUILT_IN_MEMCHR:
> +    case BUILT_IN_MEMCMP:
> +    case BUILT_IN_MEMCPY:
> +    case BUILT_IN_MEMMOVE:
> +    case BUILT_IN_MEMSET:
> +    case BUILT_IN_STRCAT:
> +    case BUILT_IN_STRCHR:
> +    case BUILT_IN_STRCMP:
> +    case BUILT_IN_STRCPY:
> +    case BUILT_IN_STRCSPN:
> +    case BUILT_IN_STRLEN:
> +    case BUILT_IN_STRNCAT:
> +    case BUILT_IN_STRNCMP:
> +    case BUILT_IN_STRNCPY:
> +    case BUILT_IN_STRPBRK:
> +    case BUILT_IN_STRRCHR:
> +    case BUILT_IN_STRSPN:
> +    case BUILT_IN_STRSTR:
> +      return "<string.h>";
> +    case BUILT_IN_FPRINTF:
> +    case BUILT_IN_PUTC:
> +    case BUILT_IN_FPUTC:
> +    case BUILT_IN_FPUTS:
> +    case BUILT_IN_FSCANF:
> +    case BUILT_IN_FWRITE:
> +    case BUILT_IN_PRINTF:
> +    case BUILT_IN_PUTCHAR:
> +    case BUILT_IN_PUTS:
> +    case BUILT_IN_SCANF:
> +    case BUILT_IN_SNPRINTF:
> +    case BUILT_IN_SPRINTF:
> +    case BUILT_IN_SSCANF:
> +    case BUILT_IN_VFPRINTF:
> +    case BUILT_IN_VFSCANF:
> +    case BUILT_IN_VPRINTF:
> +    case BUILT_IN_VSCANF:
> +    case BUILT_IN_VSNPRINTF:
> +    case BUILT_IN_VSPRINTF:
> +    case BUILT_IN_VSSCANF:
> +      return "<stdio.h>";
> +    case BUILT_IN_ISALNUM:
> +    case BUILT_IN_ISALPHA:
> +    case BUILT_IN_ISBLANK:
> +    case BUILT_IN_ISCNTRL:
> +    case BUILT_IN_ISDIGIT:
> +    case BUILT_IN_ISGRAPH:
> +    case BUILT_IN_ISLOWER:
> +    case BUILT_IN_ISPRINT:
> +    case BUILT_IN_ISPUNCT:
> +    case BUILT_IN_ISSPACE:
> +    case BUILT_IN_ISUPPER:
> +    case BUILT_IN_ISXDIGIT:
> +    case BUILT_IN_TOLOWER:
> +    case BUILT_IN_TOUPPER:
> +      return "<ctype.h>";
> +    case BUILT_IN_ISWALNUM:
> +    case BUILT_IN_ISWALPHA:
> +    case BUILT_IN_ISWBLANK:
> +    case BUILT_IN_ISWCNTRL:
> +    case BUILT_IN_ISWDIGIT:
> +    case BUILT_IN_ISWGRAPH:
> +    case BUILT_IN_ISWLOWER:
> +    case BUILT_IN_ISWPRINT:
> +    case BUILT_IN_ISWPUNCT:
> +    case BUILT_IN_ISWSPACE:
> +    case BUILT_IN_ISWUPPER:
> +    case BUILT_IN_ISWXDIGIT:
> +    case BUILT_IN_TOWLOWER:
> +    case BUILT_IN_TOWUPPER:
> +      return "<wctype.h>";
> +    case BUILT_IN_ABORT:
> +    case BUILT_IN_ABS:
> +    case BUILT_IN_CALLOC:
> +    case BUILT_IN_EXIT:
> +    case BUILT_IN_FREE:
> +    case BUILT_IN_LABS:
> +    case BUILT_IN_LLABS:
> +    case BUILT_IN_MALLOC:
> +    case BUILT_IN_REALLOC:
> +    case BUILT_IN__EXIT2:
> +    case BUILT_IN_ALIGNED_ALLOC:
> +      return "<stdlib.h>";
> +    case BUILT_IN_IMAXABS:
> +      return "<inttypes.h>";
> +    case BUILT_IN_STRFTIME:
> +      return "<time.h>";
> +    default:
> +      return NULL;
> +    }
> +}
> +
>  /* Generate an implicit declaration for identifier FUNCTIONID at LOC as a
>     function of type int ().  */
>
> @@ -3025,8 +3208,15 @@ implicitly_declare (location_t loc, tree functionid)
>                                                       (TREE_TYPE (decl)));
>               if (!comptypes (newtype, TREE_TYPE (decl)))
>                 {
> -                 warning_at (loc, 0, "incompatible implicit declaration of "
> -                             "built-in function %qD", decl);
> +                 bool warned = warning_at (loc, 0, "incompatible implicit "
> +                                           "declaration of built-in "
> +                                           "function %qD", decl);
> +                 /* See if we can hint which header to include.  */
> +                 const char *header
> +                   = header_for_builtin_fn (DECL_FUNCTION_CODE (decl));
> +                 if (header != NULL && warned)
> +                   inform (loc, "include %qs or provide a declaration of %qD",
> +                           header, decl);
>                   newtype = TREE_TYPE (decl);
>                 }
>             }
> @@ -3034,7 +3224,8 @@ implicitly_declare (location_t loc, tree functionid)
>             {
>               if (!comptypes (newtype, TREE_TYPE (decl)))
>                 {
> -                 error_at (loc, "incompatible implicit declaration of function %qD", decl);
> +                 error_at (loc, "incompatible implicit declaration of "
> +                           "function %qD", decl);
>                   locate_old_decl (decl);
>                 }
>             }
> diff --git gcc/testsuite/gcc.dg/pr59717.c gcc/testsuite/gcc.dg/pr59717.c
> index e69de29..948180c 100644
> --- gcc/testsuite/gcc.dg/pr59717.c
> +++ gcc/testsuite/gcc.dg/pr59717.c
> @@ -0,0 +1,277 @@
> +/* PR c/59717 */
> +/* { dg-do compile } */
> +/* { dg-options "-std=gnu11 -Wno-implicit-function-declaration" } */
> +
> +void
> +math (double d, int *ex, double *dp)
> +{
> +  acos (d); /* { dg-warning "incompatible implicit" } */
> +  /* { dg-message "include ..math.h.." "" { target *-*-* } 8 } */
> +  acosh (d); /* { dg-warning "incompatible implicit" } */
> +  /* { dg-message "include ..math.h.." "" { target *-*-* } 10 } */
> +  asin (d); /* { dg-warning "incompatible implicit" } */
> +  /* { dg-message "include ..math.h.." "" { target *-*-* } 12 } */
> +  asinh (d); /* { dg-warning "incompatible implicit" } */
> +  /* { dg-message "include ..math.h.." "" { target *-*-* } 14 } */
> +  atan (d); /* { dg-warning "incompatible implicit" } */
> +  /* { dg-message "include ..math.h.." "" { target *-*-* } 16 } */
> +  atanh (d); /* { dg-warning "incompatible implicit" } */
> +  /* { dg-message "include ..math.h.." "" { target *-*-* } 18 } */
> +  atan2 (d, d); /* { dg-warning "incompatible implicit" } */
> +  /* { dg-message "include ..math.h.." "" { target *-*-* } 20 } */
> +  cbrt (d); /* { dg-warning "incompatible implicit" } */
> +  /* { dg-message "include ..math.h.." "" { target *-*-* } 22 } */
> +  ceil (d); /* { dg-warning "incompatible implicit" } */
> +  /* { dg-message "include ..math.h.." "" { target *-*-* } 24 } */
> +  copysign (d, d); /* { dg-warning "incompatible implicit" } */
> +  /* { dg-message "include ..math.h.." "" { target *-*-* } 26 } */
> +  cos (d); /* { dg-warning "incompatible implicit" } */
> +  /* { dg-message "include ..math.h.." "" { target *-*-* } 28 } */
> +  cosh (d); /* { dg-warning "incompatible implicit" } */
> +  /* { dg-message "include ..math.h.." "" { target *-*-* } 30 } */
> +  erf (d); /* { dg-warning "incompatible implicit" } */
> +  /* { dg-message "include ..math.h.." "" { target *-*-* } 32 } */
> +  erfc (d); /* { dg-warning "incompatible implicit" } */
> +  /* { dg-message "include ..math.h.." "" { target *-*-* } 34 } */
> +  exp (d); /* { dg-warning "incompatible implicit" } */
> +  /* { dg-message "include ..math.h.." "" { target *-*-* } 36 } */
> +  exp2 (d); /* { dg-warning "incompatible implicit" } */
> +  /* { dg-message "include ..math.h.." "" { target *-*-* } 38 } */
> +  expm1 (d); /* { dg-warning "incompatible implicit" } */
> +  /* { dg-message "include ..math.h.." "" { target *-*-* } 40 } */
> +  fabs (d); /* { dg-warning "incompatible implicit" } */
> +  /* { dg-message "include ..math.h.." "" { target *-*-* } 42 } */
> +  fdim (d, d); /* { dg-warning "incompatible implicit" } */
> +  /* { dg-message "include ..math.h.." "" { target *-*-* } 44 } */
> +  floor (d); /* { dg-warning "incompatible implicit" } */
> +  /* { dg-message "include ..math.h.." "" { target *-*-* } 46 } */
> +  fma (d, d, d); /* { dg-warning "incompatible implicit" } */
> +  /* { dg-message "include ..math.h.." "" { target *-*-* } 48 } */
> +  fmax (d, d); /* { dg-warning "incompatible implicit" } */
> +  /* { dg-message "include ..math.h.." "" { target *-*-* } 50 } */
> +  fmin (d, d); /* { dg-warning "incompatible implicit" } */
> +  /* { dg-message "include ..math.h.." "" { target *-*-* } 52 } */
> +  fmod (d, d); /* { dg-warning "incompatible implicit" } */
> +  /* { dg-message "include ..math.h.." "" { target *-*-* } 54 } */
> +  frexp (d, ex); /* { dg-warning "incompatible implicit" } */
> +  /* { dg-message "include ..math.h.." "" { target *-*-* } 56 } */
> +  hypot (d, d); /* { dg-warning "incompatible implicit" } */
> +  /* { dg-message "include ..math.h.." "" { target *-*-* } 58 } */
> +  /* We don't generate the warning for ilogb.  */
> +  ilogb (d);
> +  ldexp (d, *ex); /* { dg-warning "incompatible implicit" } */
> +  /* { dg-message "include ..math.h.." "" { target *-*-* } 62 } */
> +  lgamma (d); /* { dg-warning "incompatible implicit" } */
> +  /* { dg-message "include ..math.h.." "" { target *-*-* } 64 } */
> +  llrint (d); /* { dg-warning "incompatible implicit" } */
> +  /* { dg-message "include ..math.h.." "" { target *-*-* } 66 } */
> +  llround (d); /* { dg-warning "incompatible implicit" } */
> +  /* { dg-message "include ..math.h.." "" { target *-*-* } 68 } */
> +  log (d); /* { dg-warning "incompatible implicit" } */
> +  /* { dg-message "include ..math.h.." "" { target *-*-* } 70 } */
> +  log10 (d); /* { dg-warning "incompatible implicit" } */
> +  /* { dg-message "include ..math.h.." "" { target *-*-* } 72 } */
> +  log1p (d); /* { dg-warning "incompatible implicit" } */
> +  /* { dg-message "include ..math.h.." "" { target *-*-* } 74 } */
> +  log2 (d); /* { dg-warning "incompatible implicit" } */
> +  /* { dg-message "include ..math.h.." "" { target *-*-* } 76 } */
> +  logb (d); /* { dg-warning "incompatible implicit" } */
> +  /* { dg-message "include ..math.h.." "" { target *-*-* } 78 } */
> +  lrint (d); /* { dg-warning "incompatible implicit" } */
> +  /* { dg-message "include ..math.h.." "" { target *-*-* } 80 } */
> +  lround (d); /* { dg-warning "incompatible implicit" } */
> +  /* { dg-message "include ..math.h.." "" { target *-*-* } 82 } */
> +  modf (d, dp); /* { dg-warning "incompatible implicit" } */
> +  /* { dg-message "include ..math.h.." "" { target *-*-* } 84 } */
> +  nan (""); /* { dg-warning "incompatible implicit" } */
> +  /* { dg-message "include ..math.h.." "" { target *-*-* } 86 } */
> +  nearbyint (d); /* { dg-warning "incompatible implicit" } */
> +  /* { dg-message "include ..math.h.." "" { target *-*-* } 88 } */
> +  nextafter (d, d); /* { dg-warning "incompatible implicit" } */
> +  /* { dg-message "include ..math.h.." "" { target *-*-* } 90 } */
> +  nexttoward (d, 20.0L); /* { dg-warning "incompatible implicit" } */
> +  /* { dg-message "include ..math.h.." "" { target *-*-* } 92 } */
> +  pow (d, d); /* { dg-warning "incompatible implicit" } */
> +  /* { dg-message "include ..math.h.." "" { target *-*-* } 94 } */
> +  remainder (d, d); /* { dg-warning "incompatible implicit" } */
> +  /* { dg-message "include ..math.h.." "" { target *-*-* } 96 } */
> +  remquo (d, d, ex); /* { dg-warning "incompatible implicit" } */
> +  /* { dg-message "include ..math.h.." "" { target *-*-* } 98 } */
> +  rint (d); /* { dg-warning "incompatible implicit" } */
> +  /* { dg-message "include ..math.h.." "" { target *-*-* } 100 } */
> +  round (d); /* { dg-warning "incompatible implicit" } */
> +  /* { dg-message "include ..math.h.." "" { target *-*-* } 102 } */
> +  scalbln (d, 100L); /* { dg-warning "incompatible implicit" } */
> +  /* { dg-message "include ..math.h.." "" { target *-*-* } 104 } */
> +  scalbn (d, 100); /* { dg-warning "incompatible implicit" } */
> +  /* { dg-message "include ..math.h.." "" { target *-*-* } 106 } */
> +  sin (d); /* { dg-warning "incompatible implicit" } */
> +  /* { dg-message "include ..math.h.." "" { target *-*-* } 108 } */
> +  sinh (d); /* { dg-warning "incompatible implicit" } */
> +  /* { dg-message "include ..math.h.." "" { target *-*-* } 110 } */
> +  sincos (d, dp, dp); /* { dg-warning "incompatible implicit" } */
> +  /* { dg-message "include ..math.h.." "" { target *-*-* } 112 } */
> +  sqrt (d); /* { dg-warning "incompatible implicit" } */
> +  /* { dg-message "include ..math.h.." "" { target *-*-* } 114 } */
> +  tan (d); /* { dg-warning "incompatible implicit" } */
> +  /* { dg-message "include ..math.h.." "" { target *-*-* } 116 } */
> +  tanh (d); /* { dg-warning "incompatible implicit" } */
> +  /* { dg-message "include ..math.h.." "" { target *-*-* } 118 } */
> +  tgamma (d); /* { dg-warning "incompatible implicit" } */
> +  /* { dg-message "include ..math.h.." "" { target *-*-* } 120 } */
> +  trunc (d); /* { dg-warning "incompatible implicit" } */
> +  /* { dg-message "include ..math.h.." "" { target *-*-* } 122 } */
> +}
> +
> +void
> +cmplx (double _Complex z)
> +{
> +  cabs (z); /* { dg-warning "incompatible implicit" } */
> +  /* { dg-message "include ..complex.h.." "" { target *-*-* } 129 } */
> +  cacos (z); /* { dg-warning "incompatible implicit" } */
> +  /* { dg-message "include ..complex.h.." "" { target *-*-* } 131 } */
> +  cacosh (z); /* { dg-warning "incompatible implicit" } */
> +  /* { dg-message "include ..complex.h.." "" { target *-*-* } 133 } */
> +  carg (z); /* { dg-warning "incompatible implicit" } */
> +  /* { dg-message "include ..complex.h.." "" { target *-*-* } 135 } */
> +  casin (z); /* { dg-warning "incompatible implicit" } */
> +  /* { dg-message "include ..complex.h.." "" { target *-*-* } 137 } */
> +  casinh (z); /* { dg-warning "incompatible implicit" } */
> +  /* { dg-message "include ..complex.h.." "" { target *-*-* } 139 } */
> +  catan (z); /* { dg-warning "incompatible implicit" } */
> +  /* { dg-message "include ..complex.h.." "" { target *-*-* } 141 } */
> +  catanh (z); /* { dg-warning "incompatible implicit" } */
> +  /* { dg-message "include ..complex.h.." "" { target *-*-* } 143 } */
> +  ccos (z); /* { dg-warning "incompatible implicit" } */
> +  /* { dg-message "include ..complex.h.." "" { target *-*-* } 145 } */
> +  ccosh (z); /* { dg-warning "incompatible implicit" } */
> +  /* { dg-message "include ..complex.h.." "" { target *-*-* } 147 } */
> +  cexp (z); /* { dg-warning "incompatible implicit" } */
> +  /* { dg-message "include ..complex.h.." "" { target *-*-* } 149 } */
> +  cimag (z); /* { dg-warning "incompatible implicit" } */
> +  /* { dg-message "include ..complex.h.." "" { target *-*-* } 151 } */
> +  clog (z); /* { dg-warning "incompatible implicit" } */
> +  /* { dg-message "include ..complex.h.." "" { target *-*-* } 153 } */
> +  conj (z); /* { dg-warning "incompatible implicit" } */
> +  /* { dg-message "include ..complex.h.." "" { target *-*-* } 155 } */
> +  cpow (z, z); /* { dg-warning "incompatible implicit" } */
> +  /* { dg-message "include ..complex.h.." "" { target *-*-* } 157 } */
> +  cproj (z); /* { dg-warning "incompatible implicit" } */
> +  /* { dg-message "include ..complex.h.." "" { target *-*-* } 159 } */
> +  creal (z); /* { dg-warning "incompatible implicit" } */
> +  /* { dg-message "include ..complex.h.." "" { target *-*-* } 161 } */
> +  csin (z); /* { dg-warning "incompatible implicit" } */
> +  /* { dg-message "include ..complex.h.." "" { target *-*-* } 163 } */
> +  csinh (z); /* { dg-warning "incompatible implicit" } */
> +  /* { dg-message "include ..complex.h.." "" { target *-*-* } 165 } */
> +  csqrt (z); /* { dg-warning "incompatible implicit" } */
> +  /* { dg-message "include ..complex.h.." "" { target *-*-* } 167 } */
> +  ctan (z); /* { dg-warning "incompatible implicit" } */
> +  /* { dg-message "include ..complex.h.." "" { target *-*-* } 169 } */
> +  ctanh (z); /* { dg-warning "incompatible implicit" } */
> +  /* { dg-message "include ..complex.h.." "" { target *-*-* } 171 } */
> +}
> +
> +void
> +string (void *p, void *q, __SIZE_TYPE__ sz)
> +{
> +  memchr (p, 2, sz); /* { dg-warning "incompatible implicit" } */
> +  /* { dg-message "include ..string.h.." "" { target *-*-* } 178 } */
> +  /* We don't generate the warning for memcmp.  */
> +  memcmp (p, q, sz);
> +  memcpy (p, q, sz); /* { dg-warning "incompatible implicit" } */
> +  /* { dg-message "include ..string.h.." "" { target *-*-* } 182 } */
> +  memmove (p, q, sz); /* { dg-warning "incompatible implicit" } */
> +  /* { dg-message "include ..string.h.." "" { target *-*-* } 184 } */
> +  memset (p, 0, sz); /* { dg-warning "incompatible implicit" } */
> +  /* { dg-message "include ..string.h.." "" { target *-*-* } 186 } */
> +  strcat (p, q); /* { dg-warning "incompatible implicit" } */
> +  /* { dg-message "include ..string.h.." "" { target *-*-* } 188 } */
> +  strchr (p, 'a'); /* { dg-warning "incompatible implicit" } */
> +  /* { dg-message "include ..string.h.." "" { target *-*-* } 190 } */
> +  /* We don't generate the warning for strcmp.  */
> +  strcmp (p, q);
> +  strcpy (p, q); /* { dg-warning "incompatible implicit" } */
> +  /* { dg-message "include ..string.h.." "" { target *-*-* } 194 } */
> +  strcspn (p, q); /* { dg-warning "incompatible implicit" } */
> +  /* { dg-message "include ..string.h.." "" { target *-*-* } 196 } */
> +  strlen (p); /* { dg-warning "incompatible implicit" } */
> +  /* { dg-message "include ..string.h.." "" { target *-*-* } 198 } */
> +  strncat (p, q, sz); /* { dg-warning "incompatible implicit" } */
> +  /* { dg-message "include ..string.h.." "" { target *-*-* } 200 } */
> +  /* We don't generate the warning for strncmp.  */
> +  strncmp (p, q, sz);
> +  strncpy (p, q, sz); /* { dg-warning "incompatible implicit" } */
> +  /* { dg-message "include ..string.h.." "" { target *-*-* } 204 } */
> +  strpbrk (p, q); /* { dg-warning "incompatible implicit" } */
> +  /* { dg-message "include ..string.h.." "" { target *-*-* } 206 } */
> +  strrchr (p, 'q'); /* { dg-warning "incompatible implicit" } */
> +  /* { dg-message "include ..string.h.." "" { target *-*-* } 208 } */
> +  strspn (p, q); /* { dg-warning "incompatible implicit" } */
> +  /* { dg-message "include ..string.h.." "" { target *-*-* } 210 } */
> +  strstr (p, q); /* { dg-warning "incompatible implicit" } */
> +  /* { dg-message "include ..string.h.." "" { target *-*-* } 212 } */
> +}
> +
> +/* Fake FILE.  */
> +typedef struct { int i; } FILE;
> +
> +void
> +stdio (FILE *fp, void *p, __SIZE_TYPE__ sz)
> +{
> +  fprintf (fp, ""); /* { dg-warning "incompatible implicit" } */
> +  /* { dg-message "include ..stdio.h.." "" { target *-*-* } 222 } */
> +  fscanf (fp, ""); /* { dg-warning "incompatible implicit" } */
> +  /* { dg-message "include ..stdio.h.." "" { target *-*-* } 224 } */
> +  fwrite (p, sz, sz, fp); /* { dg-warning "incompatible implicit" } */
> +  /* { dg-message "include ..stdio.h.." "" { target *-*-* } 226 } */
> +  printf (""); /* { dg-warning "incompatible implicit" } */
> +  /* { dg-message "include ..stdio.h.." "" { target *-*-* } 228 } */
> +  scanf (""); /* { dg-warning "incompatible implicit" } */
> +  /* { dg-message "include ..stdio.h.." "" { target *-*-* } 230 } */
> +  snprintf ("", sz, ""); /* { dg-warning "incompatible implicit" } */
> +  /* { dg-message "include ..stdio.h.." "" { target *-*-* } 232 } */
> +  sprintf ("", ""); /* { dg-warning "incompatible implicit" } */
> +  /* { dg-message "include ..stdio.h.." "" { target *-*-* } 234 } */
> +  sscanf ("", ""); /* { dg-warning "incompatible implicit" } */
> +  /* { dg-message "include ..stdio.h.." "" { target *-*-* } 236 } */
> +}
> +
> +void
> +stdlib (void *p, void *q, __SIZE_TYPE__ sz)
> +{
> +  abort (); /* { dg-warning "incompatible implicit" } */
> +  /* { dg-message "include ..stdlib.h.." "" { target *-*-* } 243 } */
> +  calloc (sz, 1); /* { dg-warning "incompatible implicit" } */
> +  /* { dg-message "include ..stdlib.h.." "" { target *-*-* } 245 } */
> +  exit (1); /* { dg-warning "incompatible implicit" } */
> +  /* { dg-message "include ..stdlib.h.." "" { target *-*-* } 247 } */
> +  free (p); /* { dg-warning "incompatible implicit" } */
> +  /* { dg-message "include ..stdlib.h.." "" { target *-*-* } 249 } */
> +  labs (1L); /* { dg-warning "incompatible implicit" } */
> +  /* { dg-message "include ..stdlib.h.." "" { target *-*-* } 251 } */
> +  llabs (1LL); /* { dg-warning "incompatible implicit" } */
> +  /* { dg-message "include ..stdlib.h.." "" { target *-*-* } 253 } */
> +  malloc (sz); /* { dg-warning "incompatible implicit" } */
> +  /* { dg-message "include ..stdlib.h.." "" { target *-*-* } 255 } */
> +  realloc (p, sz); /* { dg-warning "incompatible implicit" } */
> +  /* { dg-message "include ..stdlib.h.." "" { target *-*-* } 257 } */
> +  aligned_alloc (sz, sz); /* { dg-warning "incompatible implicit" } */
> +  /* { dg-message "include ..stdlib.h.." "" { target *-*-* } 259 } */
> +}
> +
> +void
> +inttypes (__INTMAX_TYPE__ j)
> +{
> +  imaxabs (j); /* { dg-warning "incompatible implicit" } */
> +  /* { dg-message "include ..inttypes.h.." "" { target *-*-* } 266 } */
> +}
> +
> +struct tm;
> +
> +void
> +timeh (char *s, __SIZE_TYPE__ sz, struct tm *tm)
> +{
> +  strftime (s, sz, "", tm); /* { dg-warning "incompatible implicit" } */
> +  /* { dg-message "include ..time.h.." "" { target *-*-* } 275 } */
> +}
>
>         Marek
Marek Polacek Oct. 7, 2014, 2:51 p.m. UTC | #2
On Tue, Oct 07, 2014 at 04:39:55PM +0200, Richard Biener wrote:
> Why not annotate builtins.def with the info?

Because I think that would be more hairy, I'd have to change DEF_BUILTIN
and all the builtins.  That seemed superfluous given that this hint is
only for a C FE...

	Marek
Jakub Jelinek Oct. 7, 2014, 3 p.m. UTC | #3
On Tue, Oct 07, 2014 at 04:51:31PM +0200, Marek Polacek wrote:
> On Tue, Oct 07, 2014 at 04:39:55PM +0200, Richard Biener wrote:
> > Why not annotate builtins.def with the info?
> 
> Because I think that would be more hairy, I'd have to change DEF_BUILTIN
> and all the builtins.  That seemed superfluous given that this hint is
> only for a C FE...

Guess it depends on how many DEF_*_BUILTIN classes would this affect,
if just a couple, you could add DEF_*_BUILTIN_WITH_C_HINT, with an extra
arg.  But as the builtins.def info already has quite long lines, making them
even longer might not be best.  So perhaps the switch is good enough.

	Jakub
Richard Biener Oct. 7, 2014, 3 p.m. UTC | #4
On Tue, Oct 7, 2014 at 4:51 PM, Marek Polacek <polacek@redhat.com> wrote:
> On Tue, Oct 07, 2014 at 04:39:55PM +0200, Richard Biener wrote:
>> Why not annotate builtins.def with the info?
>
> Because I think that would be more hairy, I'd have to change DEF_BUILTIN
> and all the builtins.  That seemed superfluous given that this hint is
> only for a C FE...

All C family frontends, no?  And builtins.def is used by (and only by)
all C family frontends...

Well - just a suggestion ;)

I'd like to see some easier to grok specification of the number of arguments
expected to the builtins for example (for the match-and-simplify work).

Richard.

>         Marek
Jakub Jelinek Oct. 7, 2014, 3:04 p.m. UTC | #5
On Tue, Oct 07, 2014 at 05:00:26PM +0200, Richard Biener wrote:
> On Tue, Oct 7, 2014 at 4:51 PM, Marek Polacek <polacek@redhat.com> wrote:
> > On Tue, Oct 07, 2014 at 04:39:55PM +0200, Richard Biener wrote:
> >> Why not annotate builtins.def with the info?
> >
> > Because I think that would be more hairy, I'd have to change DEF_BUILTIN
> > and all the builtins.  That seemed superfluous given that this hint is
> > only for a C FE...
> 
> All C family frontends, no?  And builtins.def is used by (and only by)
> all C family frontends...

Well, the C++ FE on say:
void
bar (void)
{
  abort ();
}

just errors out:
/tmp/a.c: In function ‘void bar()’:
/tmp/a.c:4:10: error: ‘abort’ was not declared in this scope
   abort ();
          ^
adding a hint in this case is less obvious than in the C case, because,
what if this wasn't supposed to be ::abort (), but std::abort (), or
some other namespace abort, or some class abort () method etc.?

	Jakub
Marek Polacek Oct. 7, 2014, 3:09 p.m. UTC | #6
On Tue, Oct 07, 2014 at 05:00:05PM +0200, Jakub Jelinek wrote:
> On Tue, Oct 07, 2014 at 04:51:31PM +0200, Marek Polacek wrote:
> > On Tue, Oct 07, 2014 at 04:39:55PM +0200, Richard Biener wrote:
> > > Why not annotate builtins.def with the info?
> > 
> > Because I think that would be more hairy, I'd have to change DEF_BUILTIN
> > and all the builtins.  That seemed superfluous given that this hint is
> > only for a C FE...
> 
> Guess it depends on how many DEF_*_BUILTIN classes would this affect,

At least the following:
DEF_LIB_BUILTIN
DEF_C94_BUILTIN
DEF_C99_BUILTIN
DEF_C11_BUILTIN
DEF_C99_COMPL_BUILTIN
DEF_C99_C90RES_BUILTIN
I think that is quite a lot.

> if just a couple, you could add DEF_*_BUILTIN_WITH_C_HINT, with an extra
> arg.  But as the builtins.def info already has quite long lines, making them
> even longer might not be best.  So perhaps the switch is good enough.

Yeah, that the lines are long enough already was one of the things
that discouraged me from tweaking builtins.def.

	Marek
Marek Polacek Oct. 7, 2014, 3:13 p.m. UTC | #7
On Tue, Oct 07, 2014 at 05:00:26PM +0200, Richard Biener wrote:
> On Tue, Oct 7, 2014 at 4:51 PM, Marek Polacek <polacek@redhat.com> wrote:
> > On Tue, Oct 07, 2014 at 04:39:55PM +0200, Richard Biener wrote:
> >> Why not annotate builtins.def with the info?
> >
> > Because I think that would be more hairy, I'd have to change DEF_BUILTIN
> > and all the builtins.  That seemed superfluous given that this hint is
> > only for a C FE...
> 
> All C family frontends, no?  And builtins.def is used by (and only by)
> all C family frontends...

As Jakub pointed out, only C and ObjC for now.
 
> Well - just a suggestion ;)

Thanks - builtins.def was where I originally started.

	Marek
Joseph Myers Oct. 7, 2014, 5:41 p.m. UTC | #8
On Tue, 7 Oct 2014, Marek Polacek wrote:

> 2014-10-07  Marek Polacek  <polacek@redhat.com>
> 
> 	PR c/59717
> 	* c-decl.c (header_for_builtin_fn): New function.
> 	(implicitly_declare): Suggest which header to include.
> 
> 	* gcc.dg/pr59717.c: New test.

OK.
Jason Merrill Oct. 7, 2014, 5:57 p.m. UTC | #9
On 10/07/2014 11:04 AM, Jakub Jelinek wrote:
> adding a hint in this case is less obvious than in the C case, because,
> what if this wasn't supposed to be ::abort (), but std::abort (), or
> some other namespace abort, or some class abort () method etc.?

It still seems reasonable to offer a hint if no declaration was found.

Jason
diff mbox

Patch

diff --git gcc/c/c-decl.c gcc/c/c-decl.c
index ce5a8de..e23284a 100644
--- gcc/c/c-decl.c
+++ gcc/c/c-decl.c
@@ -2968,6 +2968,189 @@  implicit_decl_warning (location_t loc, tree id, tree olddecl)
     }
 }
 
+/* This function represents mapping of a function code FCODE
+   to its respective header.  */
+
+static const char *
+header_for_builtin_fn (enum built_in_function fcode)
+{
+  switch (fcode)
+    {
+    CASE_FLT_FN (BUILT_IN_ACOS):
+    CASE_FLT_FN (BUILT_IN_ACOSH):
+    CASE_FLT_FN (BUILT_IN_ASIN):
+    CASE_FLT_FN (BUILT_IN_ASINH):
+    CASE_FLT_FN (BUILT_IN_ATAN):
+    CASE_FLT_FN (BUILT_IN_ATANH):
+    CASE_FLT_FN (BUILT_IN_ATAN2):
+    CASE_FLT_FN (BUILT_IN_CBRT):
+    CASE_FLT_FN (BUILT_IN_CEIL):
+    CASE_FLT_FN (BUILT_IN_COPYSIGN):
+    CASE_FLT_FN (BUILT_IN_COS):
+    CASE_FLT_FN (BUILT_IN_COSH):
+    CASE_FLT_FN (BUILT_IN_ERF):
+    CASE_FLT_FN (BUILT_IN_ERFC):
+    CASE_FLT_FN (BUILT_IN_EXP):
+    CASE_FLT_FN (BUILT_IN_EXP2):
+    CASE_FLT_FN (BUILT_IN_EXPM1):
+    CASE_FLT_FN (BUILT_IN_FABS):
+    CASE_FLT_FN (BUILT_IN_FDIM):
+    CASE_FLT_FN (BUILT_IN_FLOOR):
+    CASE_FLT_FN (BUILT_IN_FMA):
+    CASE_FLT_FN (BUILT_IN_FMAX):
+    CASE_FLT_FN (BUILT_IN_FMIN):
+    CASE_FLT_FN (BUILT_IN_FMOD):
+    CASE_FLT_FN (BUILT_IN_FREXP):
+    CASE_FLT_FN (BUILT_IN_HYPOT):
+    CASE_FLT_FN (BUILT_IN_ILOGB):
+    CASE_FLT_FN (BUILT_IN_LDEXP):
+    CASE_FLT_FN (BUILT_IN_LGAMMA):
+    CASE_FLT_FN (BUILT_IN_LLRINT):
+    CASE_FLT_FN (BUILT_IN_LLROUND):
+    CASE_FLT_FN (BUILT_IN_LOG):
+    CASE_FLT_FN (BUILT_IN_LOG10):
+    CASE_FLT_FN (BUILT_IN_LOG1P):
+    CASE_FLT_FN (BUILT_IN_LOG2):
+    CASE_FLT_FN (BUILT_IN_LOGB):
+    CASE_FLT_FN (BUILT_IN_LRINT):
+    CASE_FLT_FN (BUILT_IN_LROUND):
+    CASE_FLT_FN (BUILT_IN_MODF):
+    CASE_FLT_FN (BUILT_IN_NAN):
+    CASE_FLT_FN (BUILT_IN_NEARBYINT):
+    CASE_FLT_FN (BUILT_IN_NEXTAFTER):
+    CASE_FLT_FN (BUILT_IN_NEXTTOWARD):
+    CASE_FLT_FN (BUILT_IN_POW):
+    CASE_FLT_FN (BUILT_IN_REMAINDER):
+    CASE_FLT_FN (BUILT_IN_REMQUO):
+    CASE_FLT_FN (BUILT_IN_RINT):
+    CASE_FLT_FN (BUILT_IN_ROUND):
+    CASE_FLT_FN (BUILT_IN_SCALBLN):
+    CASE_FLT_FN (BUILT_IN_SCALBN):
+    CASE_FLT_FN (BUILT_IN_SIN):
+    CASE_FLT_FN (BUILT_IN_SINH):
+    CASE_FLT_FN (BUILT_IN_SINCOS):
+    CASE_FLT_FN (BUILT_IN_SQRT):
+    CASE_FLT_FN (BUILT_IN_TAN):
+    CASE_FLT_FN (BUILT_IN_TANH):
+    CASE_FLT_FN (BUILT_IN_TGAMMA):
+    CASE_FLT_FN (BUILT_IN_TRUNC):
+    case BUILT_IN_ISINF:
+    case BUILT_IN_ISNAN:
+      return "<math.h>";
+    CASE_FLT_FN (BUILT_IN_CABS):
+    CASE_FLT_FN (BUILT_IN_CACOS):
+    CASE_FLT_FN (BUILT_IN_CACOSH):
+    CASE_FLT_FN (BUILT_IN_CARG):
+    CASE_FLT_FN (BUILT_IN_CASIN):
+    CASE_FLT_FN (BUILT_IN_CASINH):
+    CASE_FLT_FN (BUILT_IN_CATAN):
+    CASE_FLT_FN (BUILT_IN_CATANH):
+    CASE_FLT_FN (BUILT_IN_CCOS):
+    CASE_FLT_FN (BUILT_IN_CCOSH):
+    CASE_FLT_FN (BUILT_IN_CEXP):
+    CASE_FLT_FN (BUILT_IN_CIMAG):
+    CASE_FLT_FN (BUILT_IN_CLOG):
+    CASE_FLT_FN (BUILT_IN_CONJ):
+    CASE_FLT_FN (BUILT_IN_CPOW):
+    CASE_FLT_FN (BUILT_IN_CPROJ):
+    CASE_FLT_FN (BUILT_IN_CREAL):
+    CASE_FLT_FN (BUILT_IN_CSIN):
+    CASE_FLT_FN (BUILT_IN_CSINH):
+    CASE_FLT_FN (BUILT_IN_CSQRT):
+    CASE_FLT_FN (BUILT_IN_CTAN):
+    CASE_FLT_FN (BUILT_IN_CTANH):
+      return "<complex.h>";
+    case BUILT_IN_MEMCHR:
+    case BUILT_IN_MEMCMP:
+    case BUILT_IN_MEMCPY:
+    case BUILT_IN_MEMMOVE:
+    case BUILT_IN_MEMSET:
+    case BUILT_IN_STRCAT:
+    case BUILT_IN_STRCHR:
+    case BUILT_IN_STRCMP:
+    case BUILT_IN_STRCPY:
+    case BUILT_IN_STRCSPN:
+    case BUILT_IN_STRLEN:
+    case BUILT_IN_STRNCAT:
+    case BUILT_IN_STRNCMP:
+    case BUILT_IN_STRNCPY:
+    case BUILT_IN_STRPBRK:
+    case BUILT_IN_STRRCHR:
+    case BUILT_IN_STRSPN:
+    case BUILT_IN_STRSTR:
+      return "<string.h>";
+    case BUILT_IN_FPRINTF:
+    case BUILT_IN_PUTC:
+    case BUILT_IN_FPUTC:
+    case BUILT_IN_FPUTS:
+    case BUILT_IN_FSCANF:
+    case BUILT_IN_FWRITE:
+    case BUILT_IN_PRINTF:
+    case BUILT_IN_PUTCHAR:
+    case BUILT_IN_PUTS:
+    case BUILT_IN_SCANF:
+    case BUILT_IN_SNPRINTF:
+    case BUILT_IN_SPRINTF:
+    case BUILT_IN_SSCANF:
+    case BUILT_IN_VFPRINTF:
+    case BUILT_IN_VFSCANF:
+    case BUILT_IN_VPRINTF:
+    case BUILT_IN_VSCANF:
+    case BUILT_IN_VSNPRINTF:
+    case BUILT_IN_VSPRINTF:
+    case BUILT_IN_VSSCANF:
+      return "<stdio.h>";
+    case BUILT_IN_ISALNUM:
+    case BUILT_IN_ISALPHA:
+    case BUILT_IN_ISBLANK:
+    case BUILT_IN_ISCNTRL:
+    case BUILT_IN_ISDIGIT:
+    case BUILT_IN_ISGRAPH:
+    case BUILT_IN_ISLOWER:
+    case BUILT_IN_ISPRINT:
+    case BUILT_IN_ISPUNCT:
+    case BUILT_IN_ISSPACE:
+    case BUILT_IN_ISUPPER:
+    case BUILT_IN_ISXDIGIT:
+    case BUILT_IN_TOLOWER:
+    case BUILT_IN_TOUPPER:
+      return "<ctype.h>";
+    case BUILT_IN_ISWALNUM:
+    case BUILT_IN_ISWALPHA:
+    case BUILT_IN_ISWBLANK:
+    case BUILT_IN_ISWCNTRL:
+    case BUILT_IN_ISWDIGIT:
+    case BUILT_IN_ISWGRAPH:
+    case BUILT_IN_ISWLOWER:
+    case BUILT_IN_ISWPRINT:
+    case BUILT_IN_ISWPUNCT:
+    case BUILT_IN_ISWSPACE:
+    case BUILT_IN_ISWUPPER:
+    case BUILT_IN_ISWXDIGIT:
+    case BUILT_IN_TOWLOWER:
+    case BUILT_IN_TOWUPPER:
+      return "<wctype.h>";
+    case BUILT_IN_ABORT:
+    case BUILT_IN_ABS:
+    case BUILT_IN_CALLOC:
+    case BUILT_IN_EXIT:
+    case BUILT_IN_FREE:
+    case BUILT_IN_LABS:
+    case BUILT_IN_LLABS:
+    case BUILT_IN_MALLOC:
+    case BUILT_IN_REALLOC:
+    case BUILT_IN__EXIT2:
+    case BUILT_IN_ALIGNED_ALLOC:
+      return "<stdlib.h>";
+    case BUILT_IN_IMAXABS:
+      return "<inttypes.h>";
+    case BUILT_IN_STRFTIME:
+      return "<time.h>";
+    default:
+      return NULL;
+    }
+}
+
 /* Generate an implicit declaration for identifier FUNCTIONID at LOC as a
    function of type int ().  */
 
@@ -3025,8 +3208,15 @@  implicitly_declare (location_t loc, tree functionid)
 						      (TREE_TYPE (decl)));
 	      if (!comptypes (newtype, TREE_TYPE (decl)))
 		{
-		  warning_at (loc, 0, "incompatible implicit declaration of "
-			      "built-in function %qD", decl);
+		  bool warned = warning_at (loc, 0, "incompatible implicit "
+					    "declaration of built-in "
+					    "function %qD", decl);
+		  /* See if we can hint which header to include.  */
+		  const char *header
+		    = header_for_builtin_fn (DECL_FUNCTION_CODE (decl));
+		  if (header != NULL && warned)
+		    inform (loc, "include %qs or provide a declaration of %qD",
+			    header, decl);
 		  newtype = TREE_TYPE (decl);
 		}
 	    }
@@ -3034,7 +3224,8 @@  implicitly_declare (location_t loc, tree functionid)
 	    {
 	      if (!comptypes (newtype, TREE_TYPE (decl)))
 		{
-		  error_at (loc, "incompatible implicit declaration of function %qD", decl);
+		  error_at (loc, "incompatible implicit declaration of "
+			    "function %qD", decl);
 		  locate_old_decl (decl);
 		}
 	    }
diff --git gcc/testsuite/gcc.dg/pr59717.c gcc/testsuite/gcc.dg/pr59717.c
index e69de29..948180c 100644
--- gcc/testsuite/gcc.dg/pr59717.c
+++ gcc/testsuite/gcc.dg/pr59717.c
@@ -0,0 +1,277 @@ 
+/* PR c/59717 */
+/* { dg-do compile } */
+/* { dg-options "-std=gnu11 -Wno-implicit-function-declaration" } */
+
+void
+math (double d, int *ex, double *dp)
+{
+  acos (d); /* { dg-warning "incompatible implicit" } */
+  /* { dg-message "include ..math.h.." "" { target *-*-* } 8 } */
+  acosh (d); /* { dg-warning "incompatible implicit" } */
+  /* { dg-message "include ..math.h.." "" { target *-*-* } 10 } */
+  asin (d); /* { dg-warning "incompatible implicit" } */
+  /* { dg-message "include ..math.h.." "" { target *-*-* } 12 } */
+  asinh (d); /* { dg-warning "incompatible implicit" } */
+  /* { dg-message "include ..math.h.." "" { target *-*-* } 14 } */
+  atan (d); /* { dg-warning "incompatible implicit" } */
+  /* { dg-message "include ..math.h.." "" { target *-*-* } 16 } */
+  atanh (d); /* { dg-warning "incompatible implicit" } */
+  /* { dg-message "include ..math.h.." "" { target *-*-* } 18 } */
+  atan2 (d, d); /* { dg-warning "incompatible implicit" } */
+  /* { dg-message "include ..math.h.." "" { target *-*-* } 20 } */
+  cbrt (d); /* { dg-warning "incompatible implicit" } */
+  /* { dg-message "include ..math.h.." "" { target *-*-* } 22 } */
+  ceil (d); /* { dg-warning "incompatible implicit" } */
+  /* { dg-message "include ..math.h.." "" { target *-*-* } 24 } */
+  copysign (d, d); /* { dg-warning "incompatible implicit" } */
+  /* { dg-message "include ..math.h.." "" { target *-*-* } 26 } */
+  cos (d); /* { dg-warning "incompatible implicit" } */
+  /* { dg-message "include ..math.h.." "" { target *-*-* } 28 } */
+  cosh (d); /* { dg-warning "incompatible implicit" } */
+  /* { dg-message "include ..math.h.." "" { target *-*-* } 30 } */
+  erf (d); /* { dg-warning "incompatible implicit" } */
+  /* { dg-message "include ..math.h.." "" { target *-*-* } 32 } */
+  erfc (d); /* { dg-warning "incompatible implicit" } */
+  /* { dg-message "include ..math.h.." "" { target *-*-* } 34 } */
+  exp (d); /* { dg-warning "incompatible implicit" } */
+  /* { dg-message "include ..math.h.." "" { target *-*-* } 36 } */
+  exp2 (d); /* { dg-warning "incompatible implicit" } */
+  /* { dg-message "include ..math.h.." "" { target *-*-* } 38 } */
+  expm1 (d); /* { dg-warning "incompatible implicit" } */
+  /* { dg-message "include ..math.h.." "" { target *-*-* } 40 } */
+  fabs (d); /* { dg-warning "incompatible implicit" } */
+  /* { dg-message "include ..math.h.." "" { target *-*-* } 42 } */
+  fdim (d, d); /* { dg-warning "incompatible implicit" } */
+  /* { dg-message "include ..math.h.." "" { target *-*-* } 44 } */
+  floor (d); /* { dg-warning "incompatible implicit" } */
+  /* { dg-message "include ..math.h.." "" { target *-*-* } 46 } */
+  fma (d, d, d); /* { dg-warning "incompatible implicit" } */
+  /* { dg-message "include ..math.h.." "" { target *-*-* } 48 } */
+  fmax (d, d); /* { dg-warning "incompatible implicit" } */
+  /* { dg-message "include ..math.h.." "" { target *-*-* } 50 } */
+  fmin (d, d); /* { dg-warning "incompatible implicit" } */
+  /* { dg-message "include ..math.h.." "" { target *-*-* } 52 } */
+  fmod (d, d); /* { dg-warning "incompatible implicit" } */
+  /* { dg-message "include ..math.h.." "" { target *-*-* } 54 } */
+  frexp (d, ex); /* { dg-warning "incompatible implicit" } */
+  /* { dg-message "include ..math.h.." "" { target *-*-* } 56 } */
+  hypot (d, d); /* { dg-warning "incompatible implicit" } */
+  /* { dg-message "include ..math.h.." "" { target *-*-* } 58 } */
+  /* We don't generate the warning for ilogb.  */
+  ilogb (d);
+  ldexp (d, *ex); /* { dg-warning "incompatible implicit" } */
+  /* { dg-message "include ..math.h.." "" { target *-*-* } 62 } */
+  lgamma (d); /* { dg-warning "incompatible implicit" } */
+  /* { dg-message "include ..math.h.." "" { target *-*-* } 64 } */
+  llrint (d); /* { dg-warning "incompatible implicit" } */
+  /* { dg-message "include ..math.h.." "" { target *-*-* } 66 } */
+  llround (d); /* { dg-warning "incompatible implicit" } */
+  /* { dg-message "include ..math.h.." "" { target *-*-* } 68 } */
+  log (d); /* { dg-warning "incompatible implicit" } */
+  /* { dg-message "include ..math.h.." "" { target *-*-* } 70 } */
+  log10 (d); /* { dg-warning "incompatible implicit" } */
+  /* { dg-message "include ..math.h.." "" { target *-*-* } 72 } */
+  log1p (d); /* { dg-warning "incompatible implicit" } */
+  /* { dg-message "include ..math.h.." "" { target *-*-* } 74 } */
+  log2 (d); /* { dg-warning "incompatible implicit" } */
+  /* { dg-message "include ..math.h.." "" { target *-*-* } 76 } */
+  logb (d); /* { dg-warning "incompatible implicit" } */
+  /* { dg-message "include ..math.h.." "" { target *-*-* } 78 } */
+  lrint (d); /* { dg-warning "incompatible implicit" } */
+  /* { dg-message "include ..math.h.." "" { target *-*-* } 80 } */
+  lround (d); /* { dg-warning "incompatible implicit" } */
+  /* { dg-message "include ..math.h.." "" { target *-*-* } 82 } */
+  modf (d, dp); /* { dg-warning "incompatible implicit" } */
+  /* { dg-message "include ..math.h.." "" { target *-*-* } 84 } */
+  nan (""); /* { dg-warning "incompatible implicit" } */
+  /* { dg-message "include ..math.h.." "" { target *-*-* } 86 } */
+  nearbyint (d); /* { dg-warning "incompatible implicit" } */
+  /* { dg-message "include ..math.h.." "" { target *-*-* } 88 } */
+  nextafter (d, d); /* { dg-warning "incompatible implicit" } */
+  /* { dg-message "include ..math.h.." "" { target *-*-* } 90 } */
+  nexttoward (d, 20.0L); /* { dg-warning "incompatible implicit" } */
+  /* { dg-message "include ..math.h.." "" { target *-*-* } 92 } */
+  pow (d, d); /* { dg-warning "incompatible implicit" } */
+  /* { dg-message "include ..math.h.." "" { target *-*-* } 94 } */
+  remainder (d, d); /* { dg-warning "incompatible implicit" } */
+  /* { dg-message "include ..math.h.." "" { target *-*-* } 96 } */
+  remquo (d, d, ex); /* { dg-warning "incompatible implicit" } */
+  /* { dg-message "include ..math.h.." "" { target *-*-* } 98 } */
+  rint (d); /* { dg-warning "incompatible implicit" } */
+  /* { dg-message "include ..math.h.." "" { target *-*-* } 100 } */
+  round (d); /* { dg-warning "incompatible implicit" } */
+  /* { dg-message "include ..math.h.." "" { target *-*-* } 102 } */
+  scalbln (d, 100L); /* { dg-warning "incompatible implicit" } */
+  /* { dg-message "include ..math.h.." "" { target *-*-* } 104 } */
+  scalbn (d, 100); /* { dg-warning "incompatible implicit" } */
+  /* { dg-message "include ..math.h.." "" { target *-*-* } 106 } */
+  sin (d); /* { dg-warning "incompatible implicit" } */
+  /* { dg-message "include ..math.h.." "" { target *-*-* } 108 } */
+  sinh (d); /* { dg-warning "incompatible implicit" } */
+  /* { dg-message "include ..math.h.." "" { target *-*-* } 110 } */
+  sincos (d, dp, dp); /* { dg-warning "incompatible implicit" } */
+  /* { dg-message "include ..math.h.." "" { target *-*-* } 112 } */
+  sqrt (d); /* { dg-warning "incompatible implicit" } */
+  /* { dg-message "include ..math.h.." "" { target *-*-* } 114 } */
+  tan (d); /* { dg-warning "incompatible implicit" } */
+  /* { dg-message "include ..math.h.." "" { target *-*-* } 116 } */
+  tanh (d); /* { dg-warning "incompatible implicit" } */
+  /* { dg-message "include ..math.h.." "" { target *-*-* } 118 } */
+  tgamma (d); /* { dg-warning "incompatible implicit" } */
+  /* { dg-message "include ..math.h.." "" { target *-*-* } 120 } */
+  trunc (d); /* { dg-warning "incompatible implicit" } */
+  /* { dg-message "include ..math.h.." "" { target *-*-* } 122 } */
+}
+
+void
+cmplx (double _Complex z)
+{
+  cabs (z); /* { dg-warning "incompatible implicit" } */
+  /* { dg-message "include ..complex.h.." "" { target *-*-* } 129 } */
+  cacos (z); /* { dg-warning "incompatible implicit" } */
+  /* { dg-message "include ..complex.h.." "" { target *-*-* } 131 } */
+  cacosh (z); /* { dg-warning "incompatible implicit" } */
+  /* { dg-message "include ..complex.h.." "" { target *-*-* } 133 } */
+  carg (z); /* { dg-warning "incompatible implicit" } */
+  /* { dg-message "include ..complex.h.." "" { target *-*-* } 135 } */
+  casin (z); /* { dg-warning "incompatible implicit" } */
+  /* { dg-message "include ..complex.h.." "" { target *-*-* } 137 } */
+  casinh (z); /* { dg-warning "incompatible implicit" } */
+  /* { dg-message "include ..complex.h.." "" { target *-*-* } 139 } */
+  catan (z); /* { dg-warning "incompatible implicit" } */
+  /* { dg-message "include ..complex.h.." "" { target *-*-* } 141 } */
+  catanh (z); /* { dg-warning "incompatible implicit" } */
+  /* { dg-message "include ..complex.h.." "" { target *-*-* } 143 } */
+  ccos (z); /* { dg-warning "incompatible implicit" } */
+  /* { dg-message "include ..complex.h.." "" { target *-*-* } 145 } */
+  ccosh (z); /* { dg-warning "incompatible implicit" } */
+  /* { dg-message "include ..complex.h.." "" { target *-*-* } 147 } */
+  cexp (z); /* { dg-warning "incompatible implicit" } */
+  /* { dg-message "include ..complex.h.." "" { target *-*-* } 149 } */
+  cimag (z); /* { dg-warning "incompatible implicit" } */
+  /* { dg-message "include ..complex.h.." "" { target *-*-* } 151 } */
+  clog (z); /* { dg-warning "incompatible implicit" } */
+  /* { dg-message "include ..complex.h.." "" { target *-*-* } 153 } */
+  conj (z); /* { dg-warning "incompatible implicit" } */
+  /* { dg-message "include ..complex.h.." "" { target *-*-* } 155 } */
+  cpow (z, z); /* { dg-warning "incompatible implicit" } */
+  /* { dg-message "include ..complex.h.." "" { target *-*-* } 157 } */
+  cproj (z); /* { dg-warning "incompatible implicit" } */
+  /* { dg-message "include ..complex.h.." "" { target *-*-* } 159 } */
+  creal (z); /* { dg-warning "incompatible implicit" } */
+  /* { dg-message "include ..complex.h.." "" { target *-*-* } 161 } */
+  csin (z); /* { dg-warning "incompatible implicit" } */
+  /* { dg-message "include ..complex.h.." "" { target *-*-* } 163 } */
+  csinh (z); /* { dg-warning "incompatible implicit" } */
+  /* { dg-message "include ..complex.h.." "" { target *-*-* } 165 } */
+  csqrt (z); /* { dg-warning "incompatible implicit" } */
+  /* { dg-message "include ..complex.h.." "" { target *-*-* } 167 } */
+  ctan (z); /* { dg-warning "incompatible implicit" } */
+  /* { dg-message "include ..complex.h.." "" { target *-*-* } 169 } */
+  ctanh (z); /* { dg-warning "incompatible implicit" } */
+  /* { dg-message "include ..complex.h.." "" { target *-*-* } 171 } */
+}
+
+void
+string (void *p, void *q, __SIZE_TYPE__ sz)
+{
+  memchr (p, 2, sz); /* { dg-warning "incompatible implicit" } */
+  /* { dg-message "include ..string.h.." "" { target *-*-* } 178 } */
+  /* We don't generate the warning for memcmp.  */
+  memcmp (p, q, sz);
+  memcpy (p, q, sz); /* { dg-warning "incompatible implicit" } */
+  /* { dg-message "include ..string.h.." "" { target *-*-* } 182 } */
+  memmove (p, q, sz); /* { dg-warning "incompatible implicit" } */
+  /* { dg-message "include ..string.h.." "" { target *-*-* } 184 } */
+  memset (p, 0, sz); /* { dg-warning "incompatible implicit" } */
+  /* { dg-message "include ..string.h.." "" { target *-*-* } 186 } */
+  strcat (p, q); /* { dg-warning "incompatible implicit" } */
+  /* { dg-message "include ..string.h.." "" { target *-*-* } 188 } */
+  strchr (p, 'a'); /* { dg-warning "incompatible implicit" } */
+  /* { dg-message "include ..string.h.." "" { target *-*-* } 190 } */
+  /* We don't generate the warning for strcmp.  */
+  strcmp (p, q);
+  strcpy (p, q); /* { dg-warning "incompatible implicit" } */
+  /* { dg-message "include ..string.h.." "" { target *-*-* } 194 } */
+  strcspn (p, q); /* { dg-warning "incompatible implicit" } */
+  /* { dg-message "include ..string.h.." "" { target *-*-* } 196 } */
+  strlen (p); /* { dg-warning "incompatible implicit" } */
+  /* { dg-message "include ..string.h.." "" { target *-*-* } 198 } */
+  strncat (p, q, sz); /* { dg-warning "incompatible implicit" } */
+  /* { dg-message "include ..string.h.." "" { target *-*-* } 200 } */
+  /* We don't generate the warning for strncmp.  */
+  strncmp (p, q, sz);
+  strncpy (p, q, sz); /* { dg-warning "incompatible implicit" } */
+  /* { dg-message "include ..string.h.." "" { target *-*-* } 204 } */
+  strpbrk (p, q); /* { dg-warning "incompatible implicit" } */
+  /* { dg-message "include ..string.h.." "" { target *-*-* } 206 } */
+  strrchr (p, 'q'); /* { dg-warning "incompatible implicit" } */
+  /* { dg-message "include ..string.h.." "" { target *-*-* } 208 } */
+  strspn (p, q); /* { dg-warning "incompatible implicit" } */
+  /* { dg-message "include ..string.h.." "" { target *-*-* } 210 } */
+  strstr (p, q); /* { dg-warning "incompatible implicit" } */
+  /* { dg-message "include ..string.h.." "" { target *-*-* } 212 } */
+}
+
+/* Fake FILE.  */
+typedef struct { int i; } FILE;
+
+void
+stdio (FILE *fp, void *p, __SIZE_TYPE__ sz)
+{
+  fprintf (fp, ""); /* { dg-warning "incompatible implicit" } */
+  /* { dg-message "include ..stdio.h.." "" { target *-*-* } 222 } */
+  fscanf (fp, ""); /* { dg-warning "incompatible implicit" } */
+  /* { dg-message "include ..stdio.h.." "" { target *-*-* } 224 } */
+  fwrite (p, sz, sz, fp); /* { dg-warning "incompatible implicit" } */
+  /* { dg-message "include ..stdio.h.." "" { target *-*-* } 226 } */
+  printf (""); /* { dg-warning "incompatible implicit" } */
+  /* { dg-message "include ..stdio.h.." "" { target *-*-* } 228 } */
+  scanf (""); /* { dg-warning "incompatible implicit" } */
+  /* { dg-message "include ..stdio.h.." "" { target *-*-* } 230 } */
+  snprintf ("", sz, ""); /* { dg-warning "incompatible implicit" } */
+  /* { dg-message "include ..stdio.h.." "" { target *-*-* } 232 } */
+  sprintf ("", ""); /* { dg-warning "incompatible implicit" } */
+  /* { dg-message "include ..stdio.h.." "" { target *-*-* } 234 } */
+  sscanf ("", ""); /* { dg-warning "incompatible implicit" } */
+  /* { dg-message "include ..stdio.h.." "" { target *-*-* } 236 } */
+}
+
+void
+stdlib (void *p, void *q, __SIZE_TYPE__ sz)
+{
+  abort (); /* { dg-warning "incompatible implicit" } */
+  /* { dg-message "include ..stdlib.h.." "" { target *-*-* } 243 } */
+  calloc (sz, 1); /* { dg-warning "incompatible implicit" } */
+  /* { dg-message "include ..stdlib.h.." "" { target *-*-* } 245 } */
+  exit (1); /* { dg-warning "incompatible implicit" } */
+  /* { dg-message "include ..stdlib.h.." "" { target *-*-* } 247 } */
+  free (p); /* { dg-warning "incompatible implicit" } */
+  /* { dg-message "include ..stdlib.h.." "" { target *-*-* } 249 } */
+  labs (1L); /* { dg-warning "incompatible implicit" } */
+  /* { dg-message "include ..stdlib.h.." "" { target *-*-* } 251 } */
+  llabs (1LL); /* { dg-warning "incompatible implicit" } */
+  /* { dg-message "include ..stdlib.h.." "" { target *-*-* } 253 } */
+  malloc (sz); /* { dg-warning "incompatible implicit" } */
+  /* { dg-message "include ..stdlib.h.." "" { target *-*-* } 255 } */
+  realloc (p, sz); /* { dg-warning "incompatible implicit" } */
+  /* { dg-message "include ..stdlib.h.." "" { target *-*-* } 257 } */
+  aligned_alloc (sz, sz); /* { dg-warning "incompatible implicit" } */
+  /* { dg-message "include ..stdlib.h.." "" { target *-*-* } 259 } */
+}
+
+void
+inttypes (__INTMAX_TYPE__ j)
+{
+  imaxabs (j); /* { dg-warning "incompatible implicit" } */
+  /* { dg-message "include ..inttypes.h.." "" { target *-*-* } 266 } */
+}
+
+struct tm;
+
+void
+timeh (char *s, __SIZE_TYPE__ sz, struct tm *tm)
+{
+  strftime (s, sz, "", tm); /* { dg-warning "incompatible implicit" } */
+  /* { dg-message "include ..time.h.." "" { target *-*-* } 275 } */
+}