Patchwork C: Add new warning -Wunprototyped-calls

login
register
mail settings
Submitter Tobias Burnus
Date April 6, 2013, 9:40 p.m.
Message ID <5160963D.6090308@net-b.de>
Download mbox | patch
Permalink /patch/234452/
State New
Headers show

Comments

Tobias Burnus - April 6, 2013, 9:40 p.m.
This patch comes from Richard's SUSE GCC patch. There, 
-Wunprototyped-calls is enabled for all RPM builds.

-Wunprototyped-calls prints a warning if one calls a function with an 
argument with is declared without prototype. For instance:

gcc.dg/Wunprototyped-calls.c: In function ‘main’:
gcc.dg/Wunprototyped-calls.c:13:3: warning: call to function ‘g’ without 
a real prototype [-Wunprototyped-calls]
g(1); /* { dg-warning "call to function 'g' without a real prototype" } */
^
gcc.dg/Wunprototyped-calls.c:7:6: note: ‘g’ was declared here
void g() { } /* { dg-message "note: 'g' was declared here" } */


To avoid too many warning, no warning is shows for K&R procedures or if 
no argument is passed to the function. (i.e. for those where the 
programmer just forgot the "(void)".)

The warning can help finding argument-passing bugs and it is less 
intrusive than -Wstrict-prototypes.


The patch activates the warning with -Wall, but one could also argue 
that it should only be activated with -Wextra or only with 
-Wunprototyped-calls.


Bootstrapped (C,ObjC,C++,ObjC++ only) and regtested on x86-64-gnu-linux.
OK for the trunk?

Tobias
Andreas Schwab - April 6, 2013, 9:50 p.m.
Tobias Burnus <burnus@net-b.de> writes:

> gcc.dg/Wunprototyped-calls.c:13:3: warning: call to function ‘g’ without a
> real prototype [-Wunprototyped-calls]

What is a real prototype?

Andreas.
Richard Guenther - April 8, 2013, 9:24 a.m.
On Sat, Apr 6, 2013 at 11:50 PM, Andreas Schwab <schwab@linux-m68k.org> wrote:
> Tobias Burnus <burnus@net-b.de> writes:
>
>> gcc.dg/Wunprototyped-calls.c:13:3: warning: call to function ‘g’ without a
>> real prototype [-Wunprototyped-calls]
>
> What is a real prototype?

One reason I didn't bother to upstream that patch is language lawyer
legalise ...

We want to catch

int foo ();

int bar (T x)
{
   return foo (x);
}

int foo (U)
{
...
}

that is, calling foo () from a context where the definition or declaration with
argument specification is not visible.  This causes the C frontend to apply
var-args promotion rules to all arguments which may differ from promotion
rules that would be applied when a "real prototype" was visible at the point
of the function call.

I'd just say "without a prototype".  int foo();  or just foo(); is specified as
part of 6.7.5.3/14 as "The empty list in a function declarator that is not
part of a definition of that function specifies that no information about the
number or types of the parameters is supplied." (this appears mostly
in K&R style programs where the T D ( identifier-list(opt) ) form is valid).
I am not sure that GCC doing varargs style promotions to calls with
only this kind of declarator is valid or if the program would be rejected
by K&R (and only the GCC extension of varargs functions without
a first named arguments makes us do what we do ...).

The patch was implemented while hunting down "miscompiles" in
either X or ghostscript (I don't remember...).

Richard.

> Andreas.
>
> --
> Andreas Schwab, schwab@linux-m68k.org
> GPG Key fingerprint = 58CA 54C7 6D53 942B 1756  01D3 44D5 214B 8276 4ED5
> "And now for something completely different."
Andreas Schwab - April 8, 2013, 1:05 p.m.
Richard Biener <richard.guenther@gmail.com> writes:

> when a "real prototype" was visible

How is that different from a prototype?

Andreas.
Richard Guenther - April 8, 2013, 1:12 p.m.
On Mon, Apr 8, 2013 at 3:05 PM, Andreas Schwab <schwab@linux-m68k.org> wrote:
> Richard Biener <richard.guenther@gmail.com> writes:
>
>> when a "real prototype" was visible
>
> How is that different from a prototype?

It's different from the case where a K&R definition was seen and thus
type information is present via that mechanism.  We don't want to
warn in that case.

As I suggested, the warning should just print "without a prototype"
but "prototype" here means that a definition before the call is
enough to make us happy (as opposed to -Wstrict-prototypes which
warns about function definitions without a previous prototype we
want to warn about calls to functions without a definition or a prototype).

Any better suggestion?

Richard.

> Andreas.
>
> --
> Andreas Schwab, schwab@linux-m68k.org
> GPG Key fingerprint = 58CA 54C7 6D53 942B 1756  01D3 44D5 214B 8276 4ED5
> "And now for something completely different."
Andreas Schwab - April 8, 2013, 1:44 p.m.
Richard Biener <richard.guenther@gmail.com> writes:

> On Mon, Apr 8, 2013 at 3:05 PM, Andreas Schwab <schwab@linux-m68k.org> wrote:
>> Richard Biener <richard.guenther@gmail.com> writes:
>>
>>> when a "real prototype" was visible
>>
>> How is that different from a prototype?
>
> It's different from the case where a K&R definition was seen and thus
> type information is present via that mechanism.  We don't want to
> warn in that case.

But that isn't a prototype.

> As I suggested, the warning should just print "without a prototype"
> but "prototype" here means that a definition before the call is
> enough to make us happy (as opposed to -Wstrict-prototypes which
> warns about function definitions without a previous prototype we
> want to warn about calls to functions without a definition or a prototype).

How does a definition help here if it isn't a prototype?

Andreas.

Patch

gcc/c-family/
2013-04-07  Richard Biener  <rguenther@suse.de>
	    Tobias Burnus  <burnus@net-b.de>

	* c.opt (Wunprototyped-calls): New C/ObjC warning.
	* c-opts.c (c_common_handle_option): Handle it.

gcc/c/
2013-04-07  Richard Biener  <rguenther@suse.de>

	* c-typeck.c (build_function_call_vec): Handle warning
	warn_unprototyped_calls.

gcc/
2013-04-07  Tobias Burnus  <burnus@net-b.de>

	* doc/invoke.texi (-Wunprototyped-calls): Document it.
	(-Wall): Add -Wunprototyped-calls to the list.

gcc/testsuite/
2013-04-07  Richard Biener  <rguenther@suse.de>
	    Tobias Burnus  <burnus@net-b.de>

	* gcc.dg/cleanup-1.c: Update dg-warning.
	* gcc.dg/Wunprototyped-calls.c: New.

diff --git a/gcc/c-family/c-opts.c b/gcc/c-family/c-opts.c
index 4b6990a..a66e2a6 100644
--- a/gcc/c-family/c-opts.c
+++ b/gcc/c-family/c-opts.c
@@ -444,6 +444,10 @@  c_common_handle_option (size_t scode, const char *arg, int value,
       warn_unknown_pragmas = value * 2;
       break;
 
+    case OPT_Wunprototyped_calls:
+      warn_unprototyped_calls = value;
+      break;
+
     case OPT_ansi:
       if (!c_dialect_cxx ())
 	set_std_c89 (false, true);
diff --git a/gcc/c-family/c.opt b/gcc/c-family/c.opt
index 10ae84d..9c2de33 100644
--- a/gcc/c-family/c.opt
+++ b/gcc/c-family/c.opt
@@ -757,6 +757,10 @@  Wunused-local-typedefs
 C ObjC C++ ObjC++ Var(warn_unused_local_typedefs) Warning EnabledBy(Wunused)
 Warn when typedefs locally defined in a function are not used
 
+Wunprototyped-calls
+C ObjC Var(warn_unprototyped_calls) Warning LangEnabledBy(C ObjC,Wall)
+Warn about calls to unprototyped functions with at least one argument
+
 Wunused-macros
 C ObjC C++ ObjC++ Var(cpp_warn_unused_macros) Warning
 Warn about macros defined in the main file that are not used
diff --git a/gcc/c/c-typeck.c b/gcc/c/c-typeck.c
index ddb6d39..26336b3 100644
--- a/gcc/c/c-typeck.c
+++ b/gcc/c/c-typeck.c
@@ -2833,6 +2833,19 @@  build_function_call_vec (location_t loc, tree function,
       && !check_builtin_function_arguments (fundecl, nargs, argarray))
     return error_mark_node;
 
+  /* If we cannot check function arguments because a prototype is
+     missing for the callee, warn here.  */
+  if (warn_unprototyped_calls
+      && nargs > 0 && !TYPE_ARG_TYPES (fntype)
+      && fundecl && !DECL_BUILT_IN (fundecl) && !C_DECL_IMPLICIT (fundecl)
+      && !DECL_ARGUMENTS (fundecl))
+    {
+      if (warning (OPT_Wunprototyped_calls,
+		   "call to function %qD without a real prototype", fundecl))
+	inform (DECL_SOURCE_LOCATION (fundecl), "%qD was declared here",
+		fundecl);
+    }
+
   /* Check that the arguments to the function are valid.  */
   check_function_arguments (fntype, nargs, argarray);
 
diff --git a/gcc/doc/invoke.texi b/gcc/doc/invoke.texi
index 1652ebc..ee1a351 100644
--- a/gcc/doc/invoke.texi
+++ b/gcc/doc/invoke.texi
@@ -279,8 +279,8 @@  Objective-C and Objective-C++ Dialects}.
 @gccoptlist{-Wbad-function-cast  -Wmissing-declarations @gol
 -Wmissing-parameter-type  -Wmissing-prototypes  -Wnested-externs @gol
 -Wold-style-declaration  -Wold-style-definition @gol
--Wstrict-prototypes  -Wtraditional  -Wtraditional-conversion @gol
--Wdeclaration-after-statement -Wpointer-sign}
+-Wstrict-prototypes -Wunprototyped-calls -Wtraditional @gol
+-Wtraditional-conversion -Wdeclaration-after-statement -Wpointer-sign}
 
 @item Debugging Options
 @xref{Debugging Options,,Options for Debugging Your Program or GCC}.
@@ -3144,6 +3144,7 @@  Options} and @ref{Objective-C and Objective-C++ Dialect Options}.
 -Wtrigraphs  @gol
 -Wuninitialized  @gol
 -Wunknown-pragmas  @gol
+-Wunprototyped-calls @r{(only for C/ObjC)} @gol
 -Wunused-function  @gol
 -Wunused-label     @gol
 -Wunused-value     @gol
@@ -4455,6 +4456,15 @@  argument types.  (An old-style function definition is permitted without
 a warning if preceded by a declaration that specifies the argument
 types.)
 
+@item -Wunprototyped-calls @r{(C and Objective-C only)}
+@opindex Wunprototyped-calls
+@opindex Wno-unprototyped-calls
+Warn if a function is called using at least one argument when that
+function is declared or defined without specifying the argument types.
+Note that no warning is issued for functions without prototype
+which are declared in K&R style.  This warning is also enabled
+by @option{-Wall}.
+
 @item -Wold-style-declaration @r{(C and Objective-C only)}
 @opindex Wold-style-declaration
 @opindex Wno-old-style-declaration
diff --git a/gcc/testsuite/gcc.dg/Wunprototyped-calls.c b/gcc/testsuite/gcc.dg/Wunprototyped-calls.c
new file mode 100644
index 0000000..e87c844
--- /dev/null
+++ b/gcc/testsuite/gcc.dg/Wunprototyped-calls.c
@@ -0,0 +1,16 @@ 
+/* { dg-do compile } */
+/* { dg-options "-Wunprototyped-calls" } */
+/* Validate expected warnings and errors.  */
+
+/* All the following functions do not have a prototype. */
+void f() {  }
+void g() {  } /* { dg-message "note: 'g' was declared here" } */
+void h(i) int i; {  }
+
+
+int main() {
+  f();		/* OK, seemingly only "(void)" forgotten.  */
+  g(1);  /* { dg-warning "call to function 'g' without a real prototype" } */
+  h(5);		/* OK, K&R declaration; accept old code */
+  return 0;
+}
diff --git a/gcc/testsuite/gcc.dg/cleanup-1.c b/gcc/testsuite/gcc.dg/cleanup-1.c
index 48b8264..0f395cb 100644
--- a/gcc/testsuite/gcc.dg/cleanup-1.c
+++ b/gcc/testsuite/gcc.dg/cleanup-1.c
@@ -6,7 +6,7 @@ 
 #define C(x)	__attribute__((cleanup(x)))
 
 static int f1(void *x U) { return 0; }
-static void f2() { }
+static void f2() { } /* { dg-message "declared here" "" } */
 static void f3(void) { } /* { dg-message "note: declared here" } */
 static void f4(void *x U) { }
 static void f5(int *x U) { }
@@ -18,7 +18,7 @@  static void f9(int x U) { } /* { dg-message "note: expected '\[^\n'\]*' but argu
 void test(void)
 {
   int o1 C(f1);
-  int o2 C(f2);
+  int o2 C(f2);		/* { dg-warning "without a real prototype" } */
   int o3 C(f3);		/* { dg-error "too many arguments" } */
   int o4 C(f4);
   int o5 C(f5);