This patch refactors the entry point of -Wmisleading-indentation from:

  void
  warn_for_misleading_indentation (location_t guard_loc,
                                   location_t body_loc,
                                   location_t next_stmt_loc,
                                   enum cpp_ttype next_tok_type,
                                   const char *guard_kind);

to

  struct common_token_info
  {
    location_t location;
    cpp_ttype type;
    rid keyword;
  };

  void
  warn_for_misleading_indentation (const common_token_info &guard_tinfo,
                                   const common_token_info &body_tinfo,
                                   const common_token_info &next_tinfo);

The purpose of this refactoring is to expose more information to the
-Wmisleading-indentation implementation to allow for more advanced
heuristics and for better coverage.

This change of API of course required changes to the C and C++ frontend.
Amidst these minor changes I also made sure in both frontends that
warn_for_misleading_indentation() gets called even when the body of the
guard in question is a semicolon.  This allows us to implement warnings
about dubious semicolons.  Also I moved the keyword != RID_ELSE checks
guarding the call to warn_for_misleading_indentation() to the function
itself itself.

At the same time this patch extends the coverage of the
-Wmisleading-indentation implementation to catch misleading indentation
involving the semicolon.  (These changes are all contained in
c-indentation.c.)  For example, now we warn on the following code
samples:

  if (flag);
    foo ();

  while (flag);
  {
    ...
  }

  if (flag); {
    ...
  }

  if (flag)
    ; /* blah */ {
      ...
    }

  if (flag); foo ();

while avoiding to warn on code that is poorly indented but not
misleadingly so;

  while (flag);
  foo ();

  while (flag)
    ;
    foo ();

  if (flag1)
    ;
  if (flag)
    ;
  else
   ...

Finally this patch reverts the fix to PR 66620 because it regresses the
following test cases:

  if (foo)
    bar ();
  else if (baz)
    bar ();
    bar (); // No warning, because guard_vis_column > body_vis_column

The better fix for this PR IMO is to bail out early when the the body is
a braced compound statement.  This is what the patch does.  In general,
when the body of the guard in question is braced then control flow is
visually explicit despite any potentially sloppy indentation.  This
restriction could always be relaxed however.

Bootstrap and regtest on x86_64-linux in progress, OK to commit if succeeds?

gcc/c-family/ChangeLog:

        * c-common.h (struct common_token_info): Define.
        (extract_token_info): Define.
        (warn_for_misleading_information): Change declaration to take
        three common_token_infos.
        * c-identation.c (should_warn_for_misleading_indentation):
        Likewise.  Bail out early if the body is a compound statement or
        if the next token is the else keyword.  Float out the definition
        of guard_exploc.  Don't warn on code containing a semicolon body
        on its own line.  Remove fix for PR 66220.  Add heuristics for
        when a semicolon body is on the same line as the guard.
        (guard_tinfo_to_string): Define.
        (warn_for_misleading_indentation): Change declaration to take
        three common_token_infos.  Adjust accordingly.

gcc/c/ChangeLog:

        * c-parser.c (c_parser_if_body): Call
        warn_for_misleading_indentation even when the body is a
        semicolon.  Extract common_token_infos corresponding to the
        guard, body and next tokens.  Adjust call to
        warn_for_misleading_indentation accordingly.
        (c_parser_else_body): Likewise.
        (c_parser_if_statement): Likewise.
        (c_parser_while_statement): Likewise.
        (c_parser_for_statement): Likewise.

gcc/cp/ChangeLog:

        * parser.c (cp_parser_selection_statement): Move handling of
        semicolon body to ...
        (cp_parser_implicitly_scoped_statement): .. here.  Call
        warn_for_misleading_indentation even when the body is a
        semicolon.  Extract common_token_infos corresponding to the
        guard, body and next tokens.  Adjust call to
        warn_for_misleading_indentation accordingly.
        (cp_parser_already_scoped_statement): Likewise.
        (cp_parser_selection_statement, cp_parser_iteration_statement):
        Extract a common_token_info corresponding to the guard token.

gcc/testsuite/ChangeLog:

        * c-c++-common/Wmisleading-indentation.c: Augment test.
---
 gcc/c-family/c-common.h                            |  34 ++++-
 gcc/c-family/c-indentation.c                       | 144 ++++++++++++++++-----
 gcc/c/c-parser.c                                   |  82 ++++++------
 gcc/cp/parser.c                                    |  99 ++++++--------
 .../c-c++-common/Wmisleading-indentation.c         |  99 ++++++++++++++
 5 files changed, 325 insertions(+), 133 deletions(-)

diff --git a/gcc/c-family/c-common.h b/gcc/c-family/c-common.h
index af86e26..f152de6 100644
--- a/gcc/c-family/c-common.h
+++ b/gcc/c-family/c-common.h
@@ -1435,12 +1435,36 @@ extern bool contains_cilk_spawn_stmt (tree);
 extern tree cilk_for_number_of_iterations (tree);
 extern bool check_no_cilk (tree, const char *, const char *,
                           location_t loc = UNKNOWN_LOCATION);
+
+
+/* A subset of token information that is common between the C and C++ 
frontends.  */
+
+struct common_token_info
+{
+  location_t location;
+  ENUM_BITFIELD (cpp_ttype) type : 8;
+  ENUM_BITFIELD (rid) keyword : 8;
+};
+
+/* Extract common token information from TOKEN, which ought to either be a
+   cp_token * or a c_token *.  */
+
+template <typename T>
+inline common_token_info
+extract_token_info (const T *token)
+{
+  common_token_info info;
+  info.location = token->location;
+  info.type = token->type;
+  info.keyword = token->keyword;
+
+  return info;
+}
+
 /* In c-indentation.c.  */
 extern void
-warn_for_misleading_indentation (location_t guard_loc,
-                                location_t body_loc,
-                                location_t next_stmt_loc,
-                                enum cpp_ttype next_tok_type,
-                                const char *guard_kind);
+warn_for_misleading_indentation (const common_token_info &guard_tinfo,
+                                const common_token_info &body_tinfo,
+                                const common_token_info &next_tinfo);
 
 #endif /* ! GCC_C_COMMON_H */
diff --git a/gcc/c-family/c-indentation.c b/gcc/c-family/c-indentation.c
index 5c78e18..d3e842b 100644
--- a/gcc/c-family/c-indentation.c
+++ b/gcc/c-family/c-indentation.c
@@ -190,11 +190,17 @@ detect_preprocessor_logic (expanded_location body_exploc,
    description of that function below.  */
 
 static bool
-should_warn_for_misleading_indentation (location_t guard_loc,
-                                       location_t body_loc,
-                                       location_t next_stmt_loc,
-                                       enum cpp_ttype next_tok_type)
+should_warn_for_misleading_indentation (const common_token_info &guard_tinfo,
+                                       const common_token_info &body_tinfo,
+                                       const common_token_info &next_tinfo)
 {
+  location_t guard_loc = guard_tinfo.location;
+  location_t body_loc = body_tinfo.location;
+  location_t next_stmt_loc = next_tinfo.location;
+
+  enum cpp_ttype body_type = body_tinfo.type;
+  enum cpp_ttype next_tok_type = next_tinfo.type;
+
   /* Don't attempt to compare the indentation of BODY_LOC and NEXT_STMT_LOC
      if either are within macros.  */
   if (linemap_location_from_macro_expansion_p (line_table, body_loc)
@@ -220,7 +226,9 @@ should_warn_for_misleading_indentation (location_t 
guard_loc,
   if (line_table->seen_line_directive)
     return false;
 
-  if (next_tok_type == CPP_CLOSE_BRACE)
+  if (body_type == CPP_OPEN_BRACE
+      || next_tok_type == CPP_CLOSE_BRACE
+      || next_tinfo.keyword == RID_ELSE)
     return false;
 
   /* Don't warn here about spurious semicolons.  */
@@ -229,6 +237,7 @@ should_warn_for_misleading_indentation (location_t 
guard_loc,
 
   expanded_location body_exploc = expand_location (body_loc);
   expanded_location next_stmt_exploc = expand_location (next_stmt_loc);
+  expanded_location guard_exploc = expand_location (guard_loc);
 
   /* They must be in the same file.  */
   if (next_stmt_exploc.file != body_exploc.file)
@@ -246,13 +255,20 @@ should_warn_for_misleading_indentation (location_t 
guard_loc,
        if (flag) foo (); bar ();
                          ^ WARN HERE
 
+
+       if (flag) ; {
+                   ^ WARN HERE
+
+       if (flag)
+        ; {
+          ^ WARN HERE
+
      Cases where we don't want to issue a warning:
 
        various_code (); if (flag) foo (); bar (); more_code ();
                                           ^ DON'T WARN HERE.  */
   if (next_stmt_exploc.line == body_exploc.line)
     {
-      expanded_location guard_exploc = expand_location (guard_loc);
       if (guard_exploc.file != body_exploc.file)
        return true;
       if (guard_exploc.line < body_exploc.line)
@@ -294,14 +310,10 @@ should_warn_for_misleading_indentation (location_t 
guard_loc,
          bar ();
          ^ DON'T WARN HERE
 
-        if (flag) {
-          foo ();
-        } else
-        {
-          bar ();
-        }
-        baz ();
-        ^ DON'T WARN HERE
+       if (flag)
+         ;
+         foo ();
+         ^ DON'T WARN HERE
   */
   if (next_stmt_exploc.line > body_exploc.line)
     {
@@ -317,23 +329,22 @@ should_warn_for_misleading_indentation (location_t 
guard_loc,
        return false;
       if (!get_visual_column (body_exploc, &body_vis_column))
        return false;
-      if (next_stmt_vis_column == body_vis_column)
+
+      /* Don't emit a warning when the semicolon body is on its own line.  */
+      if (body_exploc.line > guard_exploc.line
+         && body_type == CPP_SEMICOLON)
+       ;
+       else if (next_stmt_vis_column == body_vis_column)
        {
          /* Don't warn if they aren't aligned on the same column
             as the guard itself (suggesting autogenerated code that
             doesn't bother indenting at all).  */
-         expanded_location guard_exploc = expand_location (guard_loc);
          unsigned int guard_vis_column;
          if (!get_visual_column (guard_exploc, &guard_vis_column))
            return false;
          if (guard_vis_column == body_vis_column)
            return false;
 
-         /* PR 66220: Don't warn if the guarding statement is more
-            indented than the next/body stmts.  */
-         if (guard_vis_column > body_vis_column)
-           return false;
-
          /* Don't warn if there is multiline preprocessor logic between
             the two statements. */
          if (detect_preprocessor_logic (body_exploc, next_stmt_exploc))
@@ -342,11 +353,76 @@ should_warn_for_misleading_indentation (location_t 
guard_loc,
          /* Otherwise, they are visually aligned: issue a warning.  */
          return true;
        }
+
+       /* Also issue a warning for code having the form:
+
+          if (flag);
+            foo ();
+
+          while (flag);
+          {
+            ...
+          }
+
+          for (...);
+            {
+              ...
+            }
+
+          if (flag)
+            ;
+          else if (flag);
+            foo ();
+
+          where the semicolon at the end of each guard is most likely spurious.
+
+          But do not warn on:
+
+          for (..);
+          foo ();
+
+          where the next statement is aligned with the guard.
+       */
+       if (body_type == CPP_SEMICOLON)
+         {
+           if (body_exploc.line == guard_exploc.line)
+             {
+               unsigned int guard_vis_column;
+               if (!get_visual_column (guard_exploc, &guard_vis_column))
+                 return false;
+               if (next_stmt_vis_column != guard_vis_column
+                   || (next_tok_type == CPP_OPEN_BRACE
+                       && next_stmt_vis_column == guard_vis_column))
+                 return true;
+             }
+         }
     }
 
   return false;
 }
 
+/* Return the string indentifier corresponding to the guard token.  */
+
+static const char *
+guard_tinfo_to_string (const common_token_info &guard_tinfo)
+{
+  switch (guard_tinfo.keyword)
+    {
+    case RID_FOR:
+      return "for";
+    case RID_ELSE:
+      return "else";
+    case RID_IF:
+      return "if";
+    case RID_WHILE:
+      return "while";
+    case RID_DO:
+      return "do";
+    default:
+      return "";
+    }
+}
+
 /* Called by the C/C++ frontends when we have a guarding statement at
    GUARD_LOC containing a statement at BODY_LOC, where the block wasn't
    written using braces, like this:
@@ -374,11 +450,9 @@ should_warn_for_misleading_indentation (location_t 
guard_loc,
    GUARD_KIND identifies the kind of clause e.g. "if", "else" etc.  */
 
 void
-warn_for_misleading_indentation (location_t guard_loc,
-                                location_t body_loc,
-                                location_t next_stmt_loc,
-                                enum cpp_ttype next_tok_type,
-                                const char *guard_kind)
+warn_for_misleading_indentation (const common_token_info &guard_tinfo,
+                                const common_token_info &body_tinfo,
+                                const common_token_info &next_tinfo)
 {
   /* Early reject for the case where -Wmisleading-indentation is disabled,
      to avoid doing work only to have the warning suppressed inside the
@@ -386,12 +460,14 @@ warn_for_misleading_indentation (location_t guard_loc,
   if (!warn_misleading_indentation)
     return;
 
-  if (should_warn_for_misleading_indentation (guard_loc,
-                                             body_loc,
-                                             next_stmt_loc,
-                                             next_tok_type))
-    if (warning_at (next_stmt_loc, OPT_Wmisleading_indentation,
-                   "statement is indented as if it were guarded by..."))
-      inform (guard_loc,
-             "...this %qs clause, but it is not", guard_kind);
+  if (should_warn_for_misleading_indentation (guard_tinfo,
+                                             body_tinfo,
+                                             next_tinfo))
+    {
+      if (warning_at (next_tinfo.location, OPT_Wmisleading_indentation,
+                     "statement is indented as if it were guarded by..."))
+        inform (guard_tinfo.location,
+               "...this %qs clause, but it is not",
+               guard_tinfo_to_string (guard_tinfo));
+    }
 }
diff --git a/gcc/c/c-parser.c b/gcc/c/c-parser.c
index c691e76..7705bd4 100644
--- a/gcc/c/c-parser.c
+++ b/gcc/c/c-parser.c
@@ -5193,10 +5193,14 @@ c_parser_c99_block_statement (c_parser *parser)
    parser->in_if_block.  */
 
 static tree
-c_parser_if_body (c_parser *parser, bool *if_p, location_t if_loc)
+c_parser_if_body (c_parser *parser, bool *if_p,
+                 const common_token_info &if_tinfo)
 {
   tree block = c_begin_compound_stmt (flag_isoc99);
   location_t body_loc = c_parser_peek_token (parser)->location;
+  common_token_info body_tinfo
+    = extract_token_info (c_parser_peek_token (parser));
+
   c_parser_all_labels (parser);
   *if_p = c_parser_next_token_is_keyword (parser, RID_IF);
   if (c_parser_next_token_is (parser, CPP_SEMICOLON))
@@ -5211,14 +5215,11 @@ c_parser_if_body (c_parser *parser, bool *if_p, 
location_t if_loc)
   else if (c_parser_next_token_is (parser, CPP_OPEN_BRACE))
     add_stmt (c_parser_compound_statement (parser));
   else
-    {
-      c_parser_statement_after_labels (parser);
-      if (!c_parser_next_token_is_keyword (parser, RID_ELSE))
-       warn_for_misleading_indentation (if_loc, body_loc,
-                                        c_parser_peek_token (parser)->location,
-                                        c_parser_peek_token (parser)->type,
-                                        "if");
-    }
+    c_parser_statement_after_labels (parser);
+
+  common_token_info next_tinfo
+    = extract_token_info (c_parser_peek_token (parser));
+  warn_for_misleading_indentation (if_tinfo, body_tinfo, next_tinfo);
 
   return c_end_compound_stmt (body_loc, block, flag_isoc99);
 }
@@ -5228,28 +5229,30 @@ c_parser_if_body (c_parser *parser, bool *if_p, 
location_t if_loc)
    specially for the sake of -Wempty-body warnings.  */
 
 static tree
-c_parser_else_body (c_parser *parser, location_t else_loc)
+c_parser_else_body (c_parser *parser, const common_token_info &else_tinfo)
 {
   location_t body_loc = c_parser_peek_token (parser)->location;
   tree block = c_begin_compound_stmt (flag_isoc99);
+  common_token_info body_tinfo
+    = extract_token_info (c_parser_peek_token (parser));
+
   c_parser_all_labels (parser);
   if (c_parser_next_token_is (parser, CPP_SEMICOLON))
     {
       location_t loc = c_parser_peek_token (parser)->location;
       warning_at (loc,
                  OPT_Wempty_body,
-                "suggest braces around empty body in an %<else%> statement");
+                 "suggest braces around empty body in an %<else%> statement");
       add_stmt (build_empty_stmt (loc));
       c_parser_consume_token (parser);
     }
   else
-    {
-      c_parser_statement_after_labels (parser);
-      warn_for_misleading_indentation (else_loc, body_loc,
-                                      c_parser_peek_token (parser)->location,
-                                      c_parser_peek_token (parser)->type,
-                                      "else");
-    }
+    c_parser_statement_after_labels (parser);
+
+  common_token_info next_tinfo
+    = extract_token_info (c_parser_peek_token (parser));
+  warn_for_misleading_indentation (else_tinfo, body_tinfo, next_tinfo);
+
   return c_end_compound_stmt (body_loc, block, flag_isoc99);
 }
 
@@ -5272,7 +5275,8 @@ c_parser_if_statement (c_parser *parser)
   tree if_stmt;
 
   gcc_assert (c_parser_next_token_is_keyword (parser, RID_IF));
-  location_t if_loc = c_parser_peek_token (parser)->location;
+  common_token_info if_tinfo
+    = extract_token_info (c_parser_peek_token (parser));
   c_parser_consume_token (parser);
   block = c_begin_compound_stmt (flag_isoc99);
   loc = c_parser_peek_token (parser)->location;
@@ -5284,13 +5288,14 @@ c_parser_if_statement (c_parser *parser)
     }
   in_if_block = parser->in_if_block;
   parser->in_if_block = true;
-  first_body = c_parser_if_body (parser, &first_if, if_loc);
+  first_body = c_parser_if_body (parser, &first_if, if_tinfo);
   parser->in_if_block = in_if_block;
   if (c_parser_next_token_is_keyword (parser, RID_ELSE))
     {
-      location_t else_loc = c_parser_peek_token (parser)->location;
+      common_token_info else_tinfo
+       = extract_token_info (c_parser_peek_token (parser));
       c_parser_consume_token (parser);
-      second_body = c_parser_else_body (parser, else_loc);
+      second_body = c_parser_else_body (parser, else_tinfo);
     }
   else
     second_body = NULL_TREE;
@@ -5370,7 +5375,8 @@ c_parser_while_statement (c_parser *parser, bool ivdep)
   tree block, cond, body, save_break, save_cont;
   location_t loc;
   gcc_assert (c_parser_next_token_is_keyword (parser, RID_WHILE));
-  location_t while_loc = c_parser_peek_token (parser)->location;
+  common_token_info while_tinfo
+    = extract_token_info (c_parser_peek_token (parser));
   c_parser_consume_token (parser);
   block = c_begin_compound_stmt (flag_isoc99);
   loc = c_parser_peek_token (parser)->location;
@@ -5388,14 +5394,14 @@ c_parser_while_statement (c_parser *parser, bool ivdep)
   save_cont = c_cont_label;
   c_cont_label = NULL_TREE;
 
-  location_t body_loc = UNKNOWN_LOCATION;
-  if (c_parser_peek_token (parser)->type != CPP_OPEN_BRACE)
-    body_loc = c_parser_peek_token (parser)->location;
+  common_token_info body_tinfo
+    = extract_token_info (c_parser_peek_token (parser));
+
   body = c_parser_c99_block_statement (parser);
-  warn_for_misleading_indentation (while_loc, body_loc,
-                                  c_parser_peek_token (parser)->location,
-                                  c_parser_peek_token (parser)->type,
-                                  "while");
+
+  common_token_info next_tinfo
+    = extract_token_info (c_parser_peek_token (parser));
+  warn_for_misleading_indentation (while_tinfo, body_tinfo, next_tinfo);
 
   c_finish_loop (loc, cond, NULL, body, c_break_label, c_cont_label, true);
   add_stmt (c_end_compound_stmt (loc, block, flag_isoc99));
@@ -5515,6 +5521,8 @@ c_parser_for_statement (c_parser *parser, bool ivdep)
   location_t for_loc = c_parser_peek_token (parser)->location;
   bool is_foreach_statement = false;
   gcc_assert (c_parser_next_token_is_keyword (parser, RID_FOR));
+  common_token_info for_tinfo
+    = extract_token_info (c_parser_peek_token (parser));
   c_parser_consume_token (parser);
   /* Open a compound statement in Objective-C as well, just in case this is
      as foreach expression.  */
@@ -5675,14 +5683,14 @@ c_parser_for_statement (c_parser *parser, bool ivdep)
   save_cont = c_cont_label;
   c_cont_label = NULL_TREE;
 
-  location_t body_loc = UNKNOWN_LOCATION;
-  if (c_parser_peek_token (parser)->type != CPP_OPEN_BRACE)
-    body_loc = c_parser_peek_token (parser)->location;
+  common_token_info body_tinfo
+    = extract_token_info (c_parser_peek_token (parser));
+
   body = c_parser_c99_block_statement (parser);
-  warn_for_misleading_indentation (for_loc, body_loc,
-                                  c_parser_peek_token (parser)->location,
-                                  c_parser_peek_token (parser)->type,
-                                  "for");
+
+  common_token_info next_tinfo
+    = extract_token_info (c_parser_peek_token (parser));
+  warn_for_misleading_indentation (for_tinfo, body_tinfo, next_tinfo);
 
   if (is_foreach_statement)
     objc_finish_foreach_loop (loc, object_expression, collection_expression, 
body, c_break_label, c_cont_label);
diff --git a/gcc/cp/parser.c b/gcc/cp/parser.c
index 2ea61c0..a220f3e 100644
--- a/gcc/cp/parser.c
+++ b/gcc/cp/parser.c
@@ -2062,9 +2062,9 @@ static void cp_parser_declaration_statement
   (cp_parser *);
 
 static tree cp_parser_implicitly_scoped_statement
-  (cp_parser *, bool *, location_t, const char *);
+  (cp_parser *, bool *, const common_token_info &);
 static void cp_parser_already_scoped_statement
-  (cp_parser *, location_t, const char *);
+  (cp_parser *, const common_token_info &);
 
 /* Declarations [gram.dcl.dcl] */
 
@@ -10112,12 +10112,14 @@ cp_parser_selection_statement (cp_parser* parser, 
bool *if_p)
 {
   cp_token *token;
   enum rid keyword;
+  common_token_info guard_tinfo;
 
   if (if_p != NULL)
     *if_p = false;
 
   /* Peek at the next token.  */
   token = cp_parser_require (parser, CPP_KEYWORD, RT_SELECT);
+  guard_tinfo = extract_token_info (token);
 
   /* See what kind of keyword it is.  */
   keyword = token->keyword;
@@ -10160,19 +10162,8 @@ cp_parser_selection_statement (cp_parser* parser, bool 
*if_p)
            /* Parse the then-clause.  */
            in_statement = parser->in_statement;
            parser->in_statement |= IN_IF_STMT;
-           if (cp_lexer_next_token_is (parser->lexer, CPP_SEMICOLON))
-             {
-               location_t loc = cp_lexer_peek_token (parser->lexer)->location;
-               add_stmt (build_empty_stmt (loc));
-               cp_lexer_consume_token (parser->lexer);
-               if (!cp_lexer_next_token_is_keyword (parser->lexer, RID_ELSE))
-                 warning_at (loc, OPT_Wempty_body, "suggest braces around "
-                             "empty body in an %<if%> statement");
-               nested_if = false;
-             }
-           else
-             cp_parser_implicitly_scoped_statement (parser, &nested_if,
-                                                    token->location, "if");
+           cp_parser_implicitly_scoped_statement (parser, &nested_if,
+                                                  guard_tinfo);
            parser->in_statement = in_statement;
 
            finish_then_clause (statement);
@@ -10181,24 +10172,14 @@ cp_parser_selection_statement (cp_parser* parser, 
bool *if_p)
            if (cp_lexer_next_token_is_keyword (parser->lexer,
                                                RID_ELSE))
              {
+               guard_tinfo
+                 = extract_token_info (cp_lexer_peek_token (parser->lexer));
                /* Consume the `else' keyword.  */
-               location_t else_tok_loc
-                 = cp_lexer_consume_token (parser->lexer)->location;
+               cp_lexer_consume_token (parser->lexer);
                begin_else_clause (statement);
                /* Parse the else-clause.  */
-               if (cp_lexer_next_token_is (parser->lexer, CPP_SEMICOLON))
-                 {
-                   location_t loc;
-                   loc = cp_lexer_peek_token (parser->lexer)->location;
-                   warning_at (loc,
-                               OPT_Wempty_body, "suggest braces around "
-                               "empty body in an %<else%> statement");
-                   add_stmt (build_empty_stmt (loc));
-                   cp_lexer_consume_token (parser->lexer);
-                 }
-               else
-                 cp_parser_implicitly_scoped_statement (parser, NULL,
-                                                        else_tok_loc, "else");
+               cp_parser_implicitly_scoped_statement (parser, NULL,
+                                                      guard_tinfo);
 
                finish_else_clause (statement);
 
@@ -10239,7 +10220,7 @@ cp_parser_selection_statement (cp_parser* parser, bool 
*if_p)
            parser->in_switch_statement_p = true;
            parser->in_statement |= IN_SWITCH_STMT;
            cp_parser_implicitly_scoped_statement (parser, NULL,
-                                                  0, "switch");
+                                                  guard_tinfo);
            parser->in_switch_statement_p = in_switch_statement_p;
            parser->in_statement = in_statement;
 
@@ -10784,17 +10765,17 @@ static tree
 cp_parser_iteration_statement (cp_parser* parser, bool ivdep)
 {
   cp_token *token;
-  location_t tok_loc;
   enum rid keyword;
   tree statement;
   unsigned char in_statement;
+  common_token_info guard_tinfo;
 
   /* Peek at the next token.  */
   token = cp_parser_require (parser, CPP_KEYWORD, RT_INTERATION);
   if (!token)
     return error_mark_node;
 
-  tok_loc = token->location;
+  guard_tinfo = extract_token_info (token);
 
   /* Remember whether or not we are already within an iteration
      statement.  */
@@ -10819,7 +10800,7 @@ cp_parser_iteration_statement (cp_parser* parser, bool 
ivdep)
        cp_parser_require (parser, CPP_CLOSE_PAREN, RT_CLOSE_PAREN);
        /* Parse the dependent statement.  */
        parser->in_statement = IN_ITERATION_STMT;
-       cp_parser_already_scoped_statement (parser, tok_loc, "while");
+       cp_parser_already_scoped_statement (parser, guard_tinfo);
        parser->in_statement = in_statement;
        /* We're done with the while-statement.  */
        finish_while_stmt (statement);
@@ -10834,7 +10815,7 @@ cp_parser_iteration_statement (cp_parser* parser, bool 
ivdep)
        statement = begin_do_stmt ();
        /* Parse the body of the do-statement.  */
        parser->in_statement = IN_ITERATION_STMT;
-       cp_parser_implicitly_scoped_statement (parser, NULL, 0, "do");
+       cp_parser_implicitly_scoped_statement (parser, NULL, guard_tinfo);
        parser->in_statement = in_statement;
        finish_do_body (statement);
        /* Look for the `while' keyword.  */
@@ -10864,7 +10845,7 @@ cp_parser_iteration_statement (cp_parser* parser, bool 
ivdep)
 
        /* Parse the body of the for-statement.  */
        parser->in_statement = IN_ITERATION_STMT;
-       cp_parser_already_scoped_statement (parser, tok_loc, "for");
+       cp_parser_already_scoped_statement (parser, guard_tinfo);
        parser->in_statement = in_statement;
 
        /* We're done with the for-statement.  */
@@ -11134,10 +11115,12 @@ cp_parser_declaration_statement (cp_parser* parser)
 
 static tree
 cp_parser_implicitly_scoped_statement (cp_parser* parser, bool *if_p,
-                                      location_t guard_loc,
-                                      const char *guard_kind)
+                                      const common_token_info &guard_tinfo)
 {
   tree statement;
+  location_t body_loc = cp_lexer_peek_token (parser->lexer)->location;
+  common_token_info body_tinfo
+    = extract_token_info (cp_lexer_peek_token (parser->lexer));
 
   if (if_p != NULL)
     *if_p = false;
@@ -11145,9 +11128,16 @@ cp_parser_implicitly_scoped_statement (cp_parser* 
parser, bool *if_p,
   /* Mark if () ; with a special NOP_EXPR.  */
   if (cp_lexer_next_token_is (parser->lexer, CPP_SEMICOLON))
     {
-      location_t loc = cp_lexer_peek_token (parser->lexer)->location;
       cp_lexer_consume_token (parser->lexer);
-      statement = add_stmt (build_empty_stmt (loc));
+      statement = add_stmt (build_empty_stmt (body_loc));
+
+      if (guard_tinfo.keyword == RID_IF
+         && !cp_lexer_next_token_is_keyword (parser->lexer, RID_ELSE))
+       warning_at (body_loc, OPT_Wempty_body,
+                   "suggest braces around empty body in an %<if%> statement");
+      else if (guard_tinfo.keyword == RID_ELSE)
+       warning_at (body_loc, OPT_Wempty_body,
+                   "suggest braces around empty body in an %<else%> 
statement");
     }
   /* if a compound is opened, we simply parse the statement directly.  */
   else if (cp_lexer_next_token_is (parser->lexer, CPP_OPEN_BRACE))
@@ -11158,20 +11148,15 @@ cp_parser_implicitly_scoped_statement (cp_parser* 
parser, bool *if_p,
       /* Create a compound-statement.  */
       statement = begin_compound_stmt (0);
       /* Parse the dependent-statement.  */
-      location_t body_loc = cp_lexer_peek_token (parser->lexer)->location;
       cp_parser_statement (parser, NULL_TREE, false, if_p);
       /* Finish the dummy compound-statement.  */
       finish_compound_stmt (statement);
-      cp_token *next_tok = cp_lexer_peek_token (parser->lexer);
-      if (next_tok->keyword != RID_ELSE)
-        {
-          location_t next_stmt_loc = next_tok->location;
-          warn_for_misleading_indentation (guard_loc, body_loc,
-                                           next_stmt_loc, next_tok->type,
-                                           guard_kind);
-        }
     }
 
+  common_token_info next_tinfo
+    = extract_token_info (cp_lexer_peek_token (parser->lexer));
+  warn_for_misleading_indentation (guard_tinfo, body_tinfo, next_tinfo);
+
   /* Return the statement.  */
   return statement;
 }
@@ -11182,19 +11167,19 @@ cp_parser_implicitly_scoped_statement (cp_parser* 
parser, bool *if_p,
    scope.  */
 
 static void
-cp_parser_already_scoped_statement (cp_parser* parser, location_t guard_loc,
-                                   const char *guard_kind)
+cp_parser_already_scoped_statement (cp_parser* parser,
+                                   const common_token_info &guard_tinfo)
 {
   /* If the token is a `{', then we must take special action.  */
   if (cp_lexer_next_token_is_not (parser->lexer, CPP_OPEN_BRACE))
     {
-      location_t body_loc = cp_lexer_peek_token (parser->lexer)->location;
+      common_token_info body_tinfo
+       = extract_token_info (cp_lexer_peek_token (parser->lexer));
+
       cp_parser_statement (parser, NULL_TREE, false, NULL);
-      cp_token *next_tok = cp_lexer_peek_token (parser->lexer);
-      location_t next_stmt_loc = next_tok->location;
-      warn_for_misleading_indentation (guard_loc, body_loc,
-                                       next_stmt_loc, next_tok->type,
-                                       guard_kind);
+      common_token_info next_tinfo
+       = extract_token_info (cp_lexer_peek_token (parser->lexer));
+      warn_for_misleading_indentation (guard_tinfo, body_tinfo, next_tinfo);
     }
   else
     {
diff --git a/gcc/testsuite/c-c++-common/Wmisleading-indentation.c 
b/gcc/testsuite/c-c++-common/Wmisleading-indentation.c
index 443e3dd..e8e04e3 100644
--- a/gcc/testsuite/c-c++-common/Wmisleading-indentation.c
+++ b/gcc/testsuite/c-c++-common/Wmisleading-indentation.c
@@ -691,3 +691,102 @@ fn_36 (void)
        }
        foo(6); /* We shouldn't warn here.  */
 }
+
+void
+fn_37 (void)
+{
+  int i;
+
+#define EMPTY
+#define FOR_EACH(VAR, START, STOP) for (VAR = START; VAR < STOP; VAR++)
+
+  while (flagA); /* { dg-message "3: ...this 'while' clause" } */
+    foo (0); /* { dg-warning "statement is indented as if" } */
+
+  if (flagA)
+    ;
+  else if (flagA); /* { dg-message "8: ...this 'if' clause" } */
+    foo (0); /* { dg-warning "statement is indented as if" } */
+
+  while (flagA)
+    ;
+    foo (0);
+
+  if (flagA)
+    ;
+  else if (flagA) /* { dg-message "8: ...this 'if' clause" } */
+    foo (0);
+    foo (0); /* { dg-warning "statement is indented as if" } */
+
+  if (flagA)
+    ;
+
+  if (flagB)
+    ;
+
+  if (flagB)
+    ;
+    {
+      foo (0);
+    }
+
+  if (flagB)
+    ;
+  else; foo (0); /* { dg-warning "statement is indented as if" } */
+
+  if (flagC); foo (2); /* { dg-warning "statement is indented as if" } */
+
+  if (flagA)
+    ; /* blah */ { /* { dg-warning "statement is indented as if" } */
+      foo (1);
+    }
+
+  if (flagB) ; /* { dg-message "3: ...this 'if' clause" } */
+    return; /* { dg-warning "statement is indented as if" } */
+
+  if (flagB) EMPTY; /* { dg-message "3: ...this 'if' clause" } */
+    foo (1); /* { dg-warning "statement is indented as if" } */
+
+  while (flagC);
+  foo (2);
+
+  for (i = 0; i < 10; i++); /* { dg-message "3: ...this 'for' clause" } */
+    foo (2); /* { dg-warning "statement is indented as if" } */
+
+  FOR_EACH (i, 0, 10);
+    foo (2); /* { dg-warning "statement is indented as if" } */
+
+  FOR_EACH (i, 0, 10);
+    { /* { dg-warning "statement is indented as if" } */
+      foo (3);
+    }
+
+  FOR_EACH (i, 0, 10);
+  { /* { dg-warning "statement is indented as if" } */
+    foo (3);
+  }
+
+  if (flagA)
+    while (flagC++);
+  else
+    ;
+
+  if (flagA)
+    if (flagB)
+      foo (0);
+    else
+      foo (0);
+  else
+    foo (0);
+
+  while (i++); { /* { dg-warning "statement is indented as if" } */
+    foo (3);
+  }
+
+  if (i++); { /* { dg-warning "statement is indented as if" } */
+    foo (3);
+  }
+
+#undef EMPTY
+#undef FOR_EACH
+}
-- 
2.4.3.368.g7974889

Reply via email to