This is the mail archive of the gcc-patches@gcc.gnu.org mailing list for the GCC project.


Index Nav: [Date Index] [Subject Index] [Author Index] [Thread Index]
Message Nav: [Date Prev] [Date Next] [Thread Prev] [Thread Next]
Other format: [Raw text]

[libcpp+C++ PATCH] Fix -Wempty-body C++ warning (PR c++/36478)


Hi!

In 4.3 Mike Stump extended -Wempty-body warning, such that C++ FE (no idea
why only C++ FE and not C FE) warns about:
while (cond);
for (;;);
but still doesn't about:
#define EMPTY
while (cond) ;
while (cond)/*EMPTY*/;
while (cond)
;
while (cond)EMPTY;
Unfortunately the way it is implemented is horribly fragile and not stable
with/without -save-temps (or ccache or anything that goes preprocesses
separately from compilation).
1) With -save-temps, warning is issued for
#define EMPTY
while (cond)EMPTY;
when that wasn't intended.
2) With -save-temps, warning isn't issued if while (cond); comes from a
macro.
While 2) could be fixed as pointed by Manuel in the PR using starting/ending
location in location_t, 1) can't without libcpp being aware of it.

So, this patch changes libcpp to set a token flag on CPP_CLOSE_PAREN
if it was immediately followed in the source by semicolon (as if
we had ); token, just that 2 tokens still come from libcpp, with the
first one with a special PAREN_SEMICOLON flag) and uses that new flag
in C++ parser's check_empty_body (to determine if the warning should be
printed or not) and in c-ppoutput.c (to print extra space between ) ; if
needed).

The reason why I haven't just added PREV_WHITE flag in that case is that
I don't want to affect stringification and it would need to be handled
in many places within libcpp.

Ok for trunk if bootstrap/regtest passes?

2008-11-10  Jakub Jelinek  <jakub@redhat.com>

	PR c++/36478
libcpp/
	* include/cpplib.h (PURE_ZERO): Document that it is valid only on
	CPP_NUMBER.
	(PAREN_SEMICOLON): Define.
	* lex.c (_cpp_lex_direct): Set PAREN_SEMICOLON flag on CPP_CLOSE_PAREN
	if immediately followed by semicolon.
gcc/cp/
	* parser.c (check_empty_body): Check PAREN_SEMICOLON flag on
	CPP_CLOSE_PAREN instead of comparing source lines and columns of the
	tokens.
gcc/
	* c-ppoutput.c (scan_translation_unit): Output space between ) and ;
	if PAREN_SEMICOLON isn't set on CPP_CLOSE_PAREN.
gcc/testsuite/
	* g++.dg/warn/Wempty-body-1.C: New test.
	* g++.dg/warn/Wempty-body-2.C: New test.

--- libcpp/include/cpplib.h.jj	2008-10-23 13:22:48.000000000 +0200
+++ libcpp/include/cpplib.h	2008-11-10 11:29:02.000000000 +0100
@@ -176,8 +176,11 @@ struct cpp_string GTY(())
 #define NAMED_OP	(1 << 4) /* C++ named operators.  */
 #define NO_EXPAND	(1 << 5) /* Do not macro-expand this token.  */
 #define BOL		(1 << 6) /* Token at beginning of line.  */
-#define PURE_ZERO	(1 << 7) /* Single 0 digit, used by the C++ frontend,
-				    set in c-lex.c.  */
+#define PURE_ZERO	(1 << 7) /* On CPP_NUMBER, single 0 digit, used by the
+				    C++ frontend, set in c-lex.c.  */
+#define PAREN_SEMICOLON	(1 << 7) /* On CPP_CLOSE_PAREN if immediately
+				    followed by CPP_SEMICOLON, with no
+				    intervening whitespace or macros.  */
 
 /* Specify which field, if any, of the cpp_token union is used.  */
 
--- libcpp/lex.c.jj	2008-10-23 13:22:48.000000000 +0200
+++ libcpp/lex.c	2008-11-10 11:32:28.000000000 +0100
@@ -1319,7 +1319,11 @@ _cpp_lex_direct (cpp_reader *pfile)
     case '~': result->type = CPP_COMPL; break;
     case ',': result->type = CPP_COMMA; break;
     case '(': result->type = CPP_OPEN_PAREN; break;
-    case ')': result->type = CPP_CLOSE_PAREN; break;
+    case ')':
+      result->type = CPP_CLOSE_PAREN;
+      if (*buffer->cur == ';')
+	result->flags |= PAREN_SEMICOLON;
+      break;
     case '[': result->type = CPP_OPEN_SQUARE; break;
     case ']': result->type = CPP_CLOSE_SQUARE; break;
     case '{': result->type = CPP_OPEN_BRACE; break;
--- gcc/cp/parser.c.jj	2008-11-10 10:28:19.000000000 +0100
+++ gcc/cp/parser.c	2008-11-10 11:34:14.000000000 +0100
@@ -7446,27 +7446,22 @@ check_empty_body (cp_parser* parser, con
 {
   cp_token *token;
   cp_token *close_paren;
-  expanded_location close_loc;
-  expanded_location semi_loc;
-  
+
   close_paren = cp_lexer_peek_token (parser->lexer);
-  if (close_paren->type != CPP_CLOSE_PAREN)
+  if (close_paren->type != CPP_CLOSE_PAREN
+      || (close_paren->flags & PAREN_SEMICOLON) == 0)
     return;
 
-  close_loc = expand_location (close_paren->location);
   token = cp_lexer_peek_nth_token (parser->lexer, 2);
 
   if (token->type != CPP_SEMICOLON
       || (token->flags & PREV_WHITE))
     return;
 
-  semi_loc =  expand_location (token->location);
-  if (close_loc.line == semi_loc.line
-      && close_loc.column+1 == semi_loc.column)
-    warning (OPT_Wempty_body,
-	     "suggest a space before %<;%> or explicit braces around empty "
-	     "body in %<%s%> statement",
-	     type);
+  warning (OPT_Wempty_body,
+	   "suggest a space before %<;%> or explicit braces around empty "
+	   "body in %<%s%> statement",
+	   type);
 }
 
 /* Parse an iteration-statement.
--- gcc/c-ppoutput.c.jj	2008-10-23 13:21:41.000000000 +0200
+++ gcc/c-ppoutput.c	2008-11-10 14:07:28.000000000 +0100
@@ -188,9 +188,21 @@ scan_translation_unit (cpp_reader *pfile
 	      || (print.prev
 		  && cpp_avoid_paste (pfile, print.prev, token))
 	      || (print.prev == NULL && token->type == CPP_HASH))
-	    putc (' ', print.outf);
+	    {
+	      putc (' ', print.outf);
+	      print.prev = NULL;
+	    }
 	}
       else if (token->flags & PREV_WHITE)
+	{
+	  putc (' ', print.outf);
+	  print.prev = NULL;
+	}
+      if (token->type == CPP_SEMICOLON
+	  && print.prev != NULL
+	  && print.prev->type == CPP_CLOSE_PAREN
+	  && !(print.prev->flags & PAREN_SEMICOLON)
+	  && cpp_get_options (parse_in)->lang != CLK_ASM)
 	putc (' ', print.outf);
 
       avoid_paste = false;
--- gcc/testsuite/g++.dg/warn/Wempty-body-1.C.jj	2008-11-10 11:46:08.000000000 +0100
+++ gcc/testsuite/g++.dg/warn/Wempty-body-1.C	2008-11-10 14:09:09.000000000 +0100
@@ -0,0 +1,39 @@
+// PR c++/36478
+// { dg-do compile }
+// { dg-options "-Wempty-body" }
+
+int
+main (int, char **)
+{
+#define NOPE
+  while (0);			// { dg-warning "suggest a space before " }
+#define M1 while (0);
+  M1				// { dg-warning "suggest a space before " }
+  while (0)/**/;
+  while (0)NOPE;
+#define M2 while (0)/**/;
+  M2
+#define M3 while (0)NOPE;
+  M3
+  while (0) ;
+  while (0)
+    ;
+  while (0)
+; 
+#define M4 while (0) ;
+  M4
+  while (0)\
+\
+;
+#define M5 while (0)\
+\
+;
+  M5				// { dg-warning "suggest a space before " }
+#define M6(a) while (0)
+#define M7 ;
+  M6(0)M7
+#define M8 M6(1)M7
+  M8
+}
+
+// { dg-warning "suggest a space before " "" { target *-*-* } 25 }
--- gcc/testsuite/g++.dg/warn/Wempty-body-2.C.jj	2008-11-10 11:47:05.000000000 +0100
+++ gcc/testsuite/g++.dg/warn/Wempty-body-2.C	2008-11-10 14:09:24.000000000 +0100
@@ -0,0 +1,40 @@
+// PR c++/36478
+// { dg-do compile }
+// { dg-options "-Wempty-body -save-temps" }
+
+int
+main (int, char **)
+{
+#define NOPE
+  while (0);			// { dg-warning "suggest a space before " }
+#define M1 while (0);
+  M1				// { dg-warning "suggest a space before " }
+  while (0)/**/;
+  while (0)NOPE;
+#define M2 while (0)/**/;
+  M2
+#define M3 while (0)NOPE;
+  M3
+  while (0) ;
+  while (0)
+    ;
+  while (0)
+; 
+#define M4 while (0) ;
+  M4
+  while (0)\
+\
+;
+#define M5 while (0)\
+\
+;
+  M5				// { dg-warning "suggest a space before " }
+#define M6(a) while (0)
+#define M7 ;
+  M6(0)M7
+#define M8 M6(1)M7
+  M8
+}
+
+// { dg-warning "suggest a space before " "" { target *-*-* } 25 }
+// { dg-final { cleanup-saved-temps } }

	Jakub


Index Nav: [Date Index] [Subject Index] [Author Index] [Thread Index]
Message Nav: [Date Prev] [Date Next] [Thread Prev] [Thread Next]