Subject: bin/2708: enhancement: Warn for invalid declarations of main.
To: None <gnats-bugs@NetBSD.ORG>
From: Peter Seebach <seebs@taniemarie.solon.com>
List: netbsd-bugs
Date: 08/20/1996 18:46:01
>Number:         2708
>Category:       bin
>Synopsis:       gcc is not aggressive enough.
>Confidential:   no
>Severity:       non-critical
>Priority:       low
>Responsible:    bin-bug-people (Utility Bug People)
>State:          open
>Class:          change-request
>Submitter-Id:   net
>Arrival-Date:   Tue Aug 20 19:50:01 1996
>Last-Modified:
>Originator:     Peter Seebach
>Organization:
Peter Seebach - seebs@solon.com - Copyright 1996 Peter Seebach.
C/Unix wizard -- C/Unix questions? Send mail for help.  No, really!
Unsolicited email is not welcome, and will be billed for at consulting rates.
The *other* C FAQ - http://www.solon.com/~seebs/c/c-iaq.html
>Release:        1.2_BETA
>Environment:
	
System: NetBSD taniemarie 1.2_BETA NetBSD 1.2_BETA (SEEBS) #0: Fri Aug 16 17:16:09 CDT 1996 seebs@taniemarie:/usr/src/sys/arch/amiga/compile/SEEBS amiga


>Description:
	gcc does not detect or warn for any of the following:
		void main(void); /* forbidden */
		static int main; /* legal, but stupid */
		double main(short); /* forbidden *and* stupid */
>How-To-Repeat:
	Make an ass of yourself, and watch the compiler not notice
>Fix:
	The following patch seems to help.  I submitted it to the gcc
	people, and will submit it here also.  It detects, and warns for,
		* static objects named main.
		* non-function globals named main.
		* functions named main with unusual behavior.
	It allows the deprecated "char **envp" third argument, but warns
	for it in -pedantic mode.

	This will break the kernel; to fix, add
		-Wno-main
	when compiling modules expected to contain a main that should not
	be warned for.

	This patch is relative to /usr/src/gnu/usr.bin/gcc/

*** cc/gcc.1.orig	Mon Dec 11 14:14:38 1995
--- cc/gcc.1	Tue Aug 20 18:38:26 1996
***************
*** 187,192 ****
--- 187,193 ----
  .RI \-Wid\-clash\- len
  \-Wimplicit
  \-Winline
+ \-Wmain
  \-Wmissing\-prototypes
  \-Wmissing\-declarations
  \-Wnested\-externs
***************
*** 1700,1705 ****
--- 1701,1714 ----
  .TP
  .B \-Wimplicit
  Warn whenever a function or parameter is implicitly declared.
+ .TP
+ .B \-Wmain
+ Warn if
+ .B main\c
+ has an unusual type, or is not declared as a globally visible function.  It
+ is normal for
+ .B main\c
+ to return an integer value, and have either no arguments, or two.
  .TP
  .B \-Wreturn\-type
  Warn whenever a function is defined with a return-type that defaults
*** common/c-decl.c.orig	Mon Dec 11 14:15:48 1995
--- common/c-decl.c	Tue Aug 20 18:36:41 1996
***************
*** 541,546 ****
--- 541,550 ----
  
  int warn_missing_braces;
  
+ /* Warn for any suspicious declaration of main. */
+ 
+ int warn_main;
+ 
  /* Nonzero means `$' can be in an identifier.
     See cccp.c for reasons why this breaks some obscure ANSI C programs.  */
  
***************
*** 643,648 ****
--- 647,656 ----
      warn_bad_function_cast = 1;
    else if (!strcmp (p, "-Wno-bad-function-cast"))
      warn_bad_function_cast = 0;
+   else if (!strcmp (p, "-Wmain"))
+     warn_main = 1;
+   else if (!strcmp (p, "-Wno-main"))
+     warn_main = 0;
    else if (!strcmp (p, "-Wpointer-arith"))
      warn_pointer_arith = 1;
    else if (!strcmp (p, "-Wno-pointer-arith"))
***************
*** 723,728 ****
--- 731,737 ----
        warn_unused = 1;
        warn_switch = 1;
        warn_format = 1;
+       warn_main = 1;
        warn_char_subscripts = 1;
        warn_parentheses = 1;
        warn_missing_braces = 1;
***************
*** 3467,3472 ****
--- 3476,3486 ----
    /* The corresponding pop_obstacks is in finish_decl.  */
    push_obstacks_nochange ();
  
+   if (warn_main
+       && !strcmp (IDENTIFIER_POINTER (declarator), "main"))
+     {
+       warning_with_decl (decl, "`%s' is usually a function");
+     }
    if (initialized)
      /* Is it valid for this decl to have an initializer at all?
         If not, set INITIALIZED to zero, which will indirectly
***************
*** 6115,6120 ****
--- 6129,6198 ----
    /* A nested function is not global.  */
    if (current_function_decl != 0)
      TREE_PUBLIC (decl1) = 0;
+ 
+   /* warn for unlikely, improbable, or stupid declarations of `main'. */
+   if (warn_main && strcmp ("main", IDENTIFIER_POINTER (DECL_NAME (decl1))) == 0)
+     {
+       if (TREE_PUBLIC (decl1))
+ 	{
+ 	  tree args;
+ 	  int argct = 0;
+ 
+           if (TYPE_MAIN_VARIANT (TREE_TYPE (TREE_TYPE (decl1)))
+     	    != integer_type_node)
+     	    warning_with_decl (decl1, "return type of `%s' is not `int'");
+ 
+ 	  for (args = TYPE_ARG_TYPES (TREE_TYPE (decl1)); args;
+ 		args = TREE_CHAIN (args))
+ 	    {
+ 	      tree type = args ? TREE_VALUE (args) : 0;
+ 	      if (type == void_type_node)
+ 		break;
+ 	      ++argct;
+ 	      switch (argct) {
+ 	      case 1:
+ 		if (TYPE_MAIN_VARIANT (type) != integer_type_node)
+ 		  warning_with_decl (decl1,
+ 		    "first argument of `%s' should be `int'");
+ 		break;
+ 	      case 2:
+ 		if (TREE_CODE (type) != POINTER_TYPE
+ 		    || TREE_CODE (TREE_TYPE (type)) != POINTER_TYPE
+ 		    || TYPE_MAIN_VARIANT (TREE_TYPE (TREE_TYPE (type)))
+ 			!= char_type_node)
+ 		  {
+ 		    warning_with_decl (decl1,
+ 		      "second argument of `%s' should be `char **'");
+ 		  }
+ 		break;
+ 	      case 3:
+ 		if (TREE_CODE (type) != POINTER_TYPE
+ 		    || TREE_CODE (TREE_TYPE (type)) != POINTER_TYPE
+ 		    || TYPE_MAIN_VARIANT (TREE_TYPE (TREE_TYPE (type)))
+ 			!= char_type_node)
+ 		  {
+ 		    warning_with_decl (decl1,
+ 		      "third argument of `%s' should probably be `char **'");
+ 		  }
+ 		break;
+ 	      }
+ 	    }
+ 
+ 	  /* it is intentional that this message does not mention the third
+ 	   * argument, which is warned for only pedantically, because it's
+ 	   * blessed by mention in an appendix of the standard. */
+ 	  if (argct > 0 && (argct < 2 || argct > 3))
+ 	    warning_with_decl (decl1, "`%s' takes only zero or two arguments");
+ 
+ 	  /* see?  I told you we'd get around to warning for it... */
+ 	  if (argct == 3 && pedantic)
+ 	    pedwarn_with_decl (decl1, "third argument of `%s' is deprecated");
+ 	}
+       else /* `main' isn't TREE_PUBLIC? */
+ 	{
+ 	  warning_with_decl (decl1, "`%s' is normally a non-static function");
+ 	}
+     }
  
    /* Record the decl so that the function name is defined.
       If we already have a decl for this name, and it is a FUNCTION_DECL,
*** common/c-tree.h.orig	Mon Dec 11 14:15:51 1995
--- common/c-tree.h	Tue Aug 20 18:36:41 1996
***************
*** 474,479 ****
--- 474,483 ----
  
  extern int warn_missing_braces;
  
+ /* Warn for any suspicious declaration of main. */
+ 
+ extern int warn_main;
+ 
  /* Nonzero means this is a function to call to perform comptypes
     on two record types.  */
  
*** common/toplev.c.orig	Mon Dec 11 14:19:05 1995
--- common/toplev.c	Tue Aug 20 18:37:04 1996
***************
*** 609,614 ****
--- 609,616 ----
    "-Wall",
    "-Wbad-function-cast",
    "-Wno-bad-function-cast",
+   "-Wmain",
+   "-Wno-main",
    "-Wcast-qual",
    "-Wno-cast-qual",
    "-Wchar-subscripts",
>Audit-Trail:
>Unformatted: