diff mbox

[1/2] PR c/68187: fix overzealous -Wmisleading-indentation (comment #0)

Message ID 1457018483-26829-1-git-send-email-dmalcolm@redhat.com
State New
Headers show

Commit Message

David Malcolm March 3, 2016, 3:21 p.m. UTC
PR c/68187 covers two cases involving poor indentation where
the indentation is arguably not misleading, but for which
-Wmisleading-indentation emits a warning.

The two cases appear to be different in nature; one in comment #0
and the other in comment #1.  Richi marked the bug as a whole as
a P1 regression; it's not clear to me if he meant one or both of
these cases, so the following two patches fix both.

The rest of this post addresses the case in comment #0 of the PR;
the followup post addresses the other case, in comment #1 of the PR.

Building glibc (a9224562cbe9cfb0bd8d9e637a06141141f9e6e3) on x86_64
led to this diagnostic from -Wmisleading-indentation:

../stdlib/strtol_l.c: In function '____strtoul_l_internal':
../stdlib/strtol_l.c:356:9: error: statement is indented as if it were guarded by... [-Werror=misleading-indentation]
         cnt < thousands_len; })
         ^
../stdlib/strtol_l.c:353:9: note: ...this 'for' clause, but it is not
   && ({ for (cnt = 0; cnt < thousands_len; ++cnt)
         ^

The code is question looks like this:

   348            for (c = *end; c != L_('\0'); c = *++end)
   349              if (((STRING_TYPE) c < L_('0') || (STRING_TYPE) c > L_('9'))
   350  # ifdef USE_WIDE_CHAR
   351                  && (wchar_t) c != thousands
   352  # else
   353                  && ({ for (cnt = 0; cnt < thousands_len; ++cnt)
   354                        if (thousands[cnt] != end[cnt])
   355                          break;
   356                        cnt < thousands_len; })
   357  # endif
   358                  && (!ISALPHA (c)
   359                      || (int) (TOUPPER (c) - L_('A') + 10) >= base))
   360                break;

Lines 354 and 355 are poorly indented, leading to the warning from
-Wmisleading-indentation at line 356.

The wording of the warning is clearly wrong: line 356 isn't indented as if
guarded by line 353, it's more that lines 354 and 355 *aren't* indented.

What's happening is that should_warn_for_misleading_indentation has a
heuristic for handling "} else", such as:

     if (p)
       foo (1);
     } else       // GUARD
       foo (2);   // BODY
       foo (3);   // NEXT

and this heuristic uses the first non-whitespace character in the line
containing GUARD as the column of interest: the "}" character.

In this case we have:

   353        && ({ for (cnt = 0; cnt < thousands_len; ++cnt)  // GUARD
   354              if (thousands[cnt] != end[cnt])            // BODY
   355                break;
   356              cnt < thousands_len; })                    // NEXT

and so it uses the column of the "&&", and treats it as if it were
indented thus:

   353        for (cnt = 0; cnt < thousands_len; ++cnt)        // GUARD
   354              if (thousands[cnt] != end[cnt])            // BODY
   355                break;
   356              cnt < thousands_len; })                    // NEXT

and thus issues a warning.

As far as I can tell the heuristic in question only makes sense for
"else" clauses, so the following patch updates it to only use the
special column when handling "else" clauses, eliminating the
overzealous warning.

Doing so led to a nonsensical warning for
libstdc++-v3/src/c++11/random.cc:random_device::_M_init:

random.cc: In member function ‘void std::random_device::_M_init(const string&)’:
random.cc:102:10: warning: this ‘if’ clause does not guard... [-Wmisleading-indentation]
     else if (token != "/dev/urandom" && token != "/dev/random")
          ^~
random.cc:107:5: note: ...this statement, but the latter is indented as if it does
     _M_file = static_cast<void*>(std::fopen(fname, "rb"));
     ^~~~~~~

so the patch addresses this by tweaking the heuristic that rejects
aligned BODY and NEXT so that it doesn't require them to be aligned with
the first non-whitespace of the GUARD, simply that they not be indented
relative to it.

Successfully bootstrapped&regrtested on x86_64-pc-linux-gnu in
combination with the following patch; standalone bootstrap&regrtest
is in progress.

OK for trunk if the latter is successful?

gcc/c-family/ChangeLog:
	PR c/68187
	* c-indentation.c (should_warn_for_misleading_indentation): When
	suppressing warnings about cases where the guard and body are on
	the same column, only use the first non-whitespace column in place
	of the guard token column when dealing with "else" clauses.
	When rejecting aligned BODY and NEXT, loosen the requirement
	from equality with the first non-whitespace of guard to simply
	that they not be indented relative to it.

gcc/testsuite/ChangeLog:
	PR c/68187
	* c-c++-common/Wmisleading-indentation.c (fn_40_a): New test
	function.
	(fn_40_b): Likewise.
	(fn_41_a): Likewise.
	(fn_41_b): Likewise.
---
 gcc/c-family/c-indentation.c                       | 16 +++--
 .../c-c++-common/Wmisleading-indentation.c         | 79 ++++++++++++++++++++++
 2 files changed, 89 insertions(+), 6 deletions(-)

Comments

Patrick Palka March 3, 2016, 3:24 p.m. UTC | #1
On Thu, Mar 3, 2016 at 10:21 AM, David Malcolm <dmalcolm@redhat.com> wrote:
> PR c/68187 covers two cases involving poor indentation where
> the indentation is arguably not misleading, but for which
> -Wmisleading-indentation emits a warning.
>
> The two cases appear to be different in nature; one in comment #0
> and the other in comment #1.  Richi marked the bug as a whole as
> a P1 regression; it's not clear to me if he meant one or both of
> these cases, so the following two patches fix both.
>
> The rest of this post addresses the case in comment #0 of the PR;
> the followup post addresses the other case, in comment #1 of the PR.
>
> Building glibc (a9224562cbe9cfb0bd8d9e637a06141141f9e6e3) on x86_64
> led to this diagnostic from -Wmisleading-indentation:
>
> ../stdlib/strtol_l.c: In function '____strtoul_l_internal':
> ../stdlib/strtol_l.c:356:9: error: statement is indented as if it were guarded by... [-Werror=misleading-indentation]
>          cnt < thousands_len; })
>          ^
> ../stdlib/strtol_l.c:353:9: note: ...this 'for' clause, but it is not
>    && ({ for (cnt = 0; cnt < thousands_len; ++cnt)
>          ^
>
> The code is question looks like this:
>
>    348            for (c = *end; c != L_('\0'); c = *++end)
>    349              if (((STRING_TYPE) c < L_('0') || (STRING_TYPE) c > L_('9'))
>    350  # ifdef USE_WIDE_CHAR
>    351                  && (wchar_t) c != thousands
>    352  # else
>    353                  && ({ for (cnt = 0; cnt < thousands_len; ++cnt)
>    354                        if (thousands[cnt] != end[cnt])
>    355                          break;
>    356                        cnt < thousands_len; })
>    357  # endif
>    358                  && (!ISALPHA (c)
>    359                      || (int) (TOUPPER (c) - L_('A') + 10) >= base))
>    360                break;
>
> Lines 354 and 355 are poorly indented, leading to the warning from
> -Wmisleading-indentation at line 356.
>
> The wording of the warning is clearly wrong: line 356 isn't indented as if
> guarded by line 353, it's more that lines 354 and 355 *aren't* indented.
>
> What's happening is that should_warn_for_misleading_indentation has a
> heuristic for handling "} else", such as:
>
>      if (p)
>        foo (1);
>      } else       // GUARD
>        foo (2);   // BODY
>        foo (3);   // NEXT
>
> and this heuristic uses the first non-whitespace character in the line
> containing GUARD as the column of interest: the "}" character.
>
> In this case we have:
>
>    353        && ({ for (cnt = 0; cnt < thousands_len; ++cnt)  // GUARD
>    354              if (thousands[cnt] != end[cnt])            // BODY
>    355                break;
>    356              cnt < thousands_len; })                    // NEXT
>
> and so it uses the column of the "&&", and treats it as if it were
> indented thus:
>
>    353        for (cnt = 0; cnt < thousands_len; ++cnt)        // GUARD
>    354              if (thousands[cnt] != end[cnt])            // BODY
>    355                break;
>    356              cnt < thousands_len; })                    // NEXT
>
> and thus issues a warning.
>
> As far as I can tell the heuristic in question only makes sense for
> "else" clauses, so the following patch updates it to only use the
> special column when handling "else" clauses, eliminating the
> overzealous warning.

Wouldn't this change have the undesirable effect of no longer warning about:

      if (p)
        foo (1);
      } else if (q)
        foo (2);
        foo (3);
David Malcolm March 3, 2016, 3:56 p.m. UTC | #2
On Thu, 2016-03-03 at 10:24 -0500, Patrick Palka wrote:
> On Thu, Mar 3, 2016 at 10:21 AM, David Malcolm <dmalcolm@redhat.com>
> wrote:
> > PR c/68187 covers two cases involving poor indentation where
> > the indentation is arguably not misleading, but for which
> > -Wmisleading-indentation emits a warning.
> > 
> > The two cases appear to be different in nature; one in comment #0
> > and the other in comment #1.  Richi marked the bug as a whole as
> > a P1 regression; it's not clear to me if he meant one or both of
> > these cases, so the following two patches fix both.
> > 
> > The rest of this post addresses the case in comment #0 of the PR;
> > the followup post addresses the other case, in comment #1 of the
> > PR.
> > 
> > Building glibc (a9224562cbe9cfb0bd8d9e637a06141141f9e6e3) on x86_64
> > led to this diagnostic from -Wmisleading-indentation:
> > 
> > ../stdlib/strtol_l.c: In function '____strtoul_l_internal':
> > ../stdlib/strtol_l.c:356:9: error: statement is indented as if it
> > were guarded by... [-Werror=misleading-indentation]
> >          cnt < thousands_len; })
> >          ^
> > ../stdlib/strtol_l.c:353:9: note: ...this 'for' clause, but it is
> > not
> >    && ({ for (cnt = 0; cnt < thousands_len; ++cnt)
> >          ^
> > 
> > The code is question looks like this:
> > 
> >    348            for (c = *end; c != L_('\0'); c = *++end)
> >    349              if (((STRING_TYPE) c < L_('0') || (STRING_TYPE)
> > c > L_('9'))
> >    350  # ifdef USE_WIDE_CHAR
> >    351                  && (wchar_t) c != thousands
> >    352  # else
> >    353                  && ({ for (cnt = 0; cnt < thousands_len;
> > ++cnt)
> >    354                        if (thousands[cnt] != end[cnt])
> >    355                          break;
> >    356                        cnt < thousands_len; })
> >    357  # endif
> >    358                  && (!ISALPHA (c)
> >    359                      || (int) (TOUPPER (c) - L_('A') + 10)
> > >= base))
> >    360                break;
> > 
> > Lines 354 and 355 are poorly indented, leading to the warning from
> > -Wmisleading-indentation at line 356.
> > 
> > The wording of the warning is clearly wrong: line 356 isn't
> > indented as if
> > guarded by line 353, it's more that lines 354 and 355 *aren't*
> > indented.
> > 
> > What's happening is that should_warn_for_misleading_indentation has
> > a
> > heuristic for handling "} else", such as:
> > 
> >      if (p)
> >        foo (1);
> >      } else       // GUARD
> >        foo (2);   // BODY
> >        foo (3);   // NEXT
> > 
> > and this heuristic uses the first non-whitespace character in the
> > line
> > containing GUARD as the column of interest: the "}" character.
> > 
> > In this case we have:
> > 
> >    353        && ({ for (cnt = 0; cnt < thousands_len; ++cnt)  //
> > GUARD
> >    354              if (thousands[cnt] != end[cnt])            //
> > BODY
> >    355                break;
> >    356              cnt < thousands_len; })                    //
> > NEXT
> > 
> > and so it uses the column of the "&&", and treats it as if it were
> > indented thus:
> > 
> >    353        for (cnt = 0; cnt < thousands_len; ++cnt)        //
> > GUARD
> >    354              if (thousands[cnt] != end[cnt])            //
> > BODY
> >    355                break;
> >    356              cnt < thousands_len; })                    //
> > NEXT
> > 
> > and thus issues a warning.
> > 
> > As far as I can tell the heuristic in question only makes sense for
> > "else" clauses, so the following patch updates it to only use the
> > special column when handling "else" clauses, eliminating the
> > overzealous warning.
> 
> Wouldn't this change have the undesirable effect of no longer warning
> about:
> 
>       if (p)
>         foo (1);
>       } else if (q)
>         foo (2);
>         foo (3);

No, because the rejection based on indentation is done relative to
 guard_line_first_nws, rather than guard_vis_column (I tried doing it
via the latter in one version of the patch, and that broke some of the
existing cases, so I didn't make that change).

See the attached test file (which doesn't have dg-directives yet); the
example you give is test1_d, with an open-brace added to the "if (p)".

Trunk emits warnings for:
  * test1_c
  * test1_d
  * test1_e
  * test1_f (two warnings, one for the "if", one for the "else")
  * test1_g
  * test2_c
  * test2_d
  * test2_e

With the patches, it emits warnings for:
  * test1_c
  * test1_d
  * test1_e
  * test1_f (just one warnings, for the "if")
  * test1_g
  * test2_c
  * test2_d
  * test2_e

so the only change is the removal of the erroneous double warning for
the "else" in test1_f.

I can add dg-directives and add the attachment to Wmisleading
-indentation.c as part of the patch (or keep it as a separate new test
file, the former is getting large).
Patrick Palka March 3, 2016, 4:57 p.m. UTC | #3
On Thu, Mar 3, 2016 at 10:56 AM, David Malcolm <dmalcolm@redhat.com> wrote:
> On Thu, 2016-03-03 at 10:24 -0500, Patrick Palka wrote:
>> On Thu, Mar 3, 2016 at 10:21 AM, David Malcolm <dmalcolm@redhat.com>
>> wrote:
>> > PR c/68187 covers two cases involving poor indentation where
>> > the indentation is arguably not misleading, but for which
>> > -Wmisleading-indentation emits a warning.
>> >
>> > The two cases appear to be different in nature; one in comment #0
>> > and the other in comment #1.  Richi marked the bug as a whole as
>> > a P1 regression; it's not clear to me if he meant one or both of
>> > these cases, so the following two patches fix both.
>> >
>> > The rest of this post addresses the case in comment #0 of the PR;
>> > the followup post addresses the other case, in comment #1 of the
>> > PR.
>> >
>> > Building glibc (a9224562cbe9cfb0bd8d9e637a06141141f9e6e3) on x86_64
>> > led to this diagnostic from -Wmisleading-indentation:
>> >
>> > ../stdlib/strtol_l.c: In function '____strtoul_l_internal':
>> > ../stdlib/strtol_l.c:356:9: error: statement is indented as if it
>> > were guarded by... [-Werror=misleading-indentation]
>> >          cnt < thousands_len; })
>> >          ^
>> > ../stdlib/strtol_l.c:353:9: note: ...this 'for' clause, but it is
>> > not
>> >    && ({ for (cnt = 0; cnt < thousands_len; ++cnt)
>> >          ^
>> >
>> > The code is question looks like this:
>> >
>> >    348            for (c = *end; c != L_('\0'); c = *++end)
>> >    349              if (((STRING_TYPE) c < L_('0') || (STRING_TYPE)
>> > c > L_('9'))
>> >    350  # ifdef USE_WIDE_CHAR
>> >    351                  && (wchar_t) c != thousands
>> >    352  # else
>> >    353                  && ({ for (cnt = 0; cnt < thousands_len;
>> > ++cnt)
>> >    354                        if (thousands[cnt] != end[cnt])
>> >    355                          break;
>> >    356                        cnt < thousands_len; })
>> >    357  # endif
>> >    358                  && (!ISALPHA (c)
>> >    359                      || (int) (TOUPPER (c) - L_('A') + 10)
>> > >= base))
>> >    360                break;
>> >
>> > Lines 354 and 355 are poorly indented, leading to the warning from
>> > -Wmisleading-indentation at line 356.
>> >
>> > The wording of the warning is clearly wrong: line 356 isn't
>> > indented as if
>> > guarded by line 353, it's more that lines 354 and 355 *aren't*
>> > indented.
>> >
>> > What's happening is that should_warn_for_misleading_indentation has
>> > a
>> > heuristic for handling "} else", such as:
>> >
>> >      if (p)
>> >        foo (1);
>> >      } else       // GUARD
>> >        foo (2);   // BODY
>> >        foo (3);   // NEXT
>> >
>> > and this heuristic uses the first non-whitespace character in the
>> > line
>> > containing GUARD as the column of interest: the "}" character.
>> >
>> > In this case we have:
>> >
>> >    353        && ({ for (cnt = 0; cnt < thousands_len; ++cnt)  //
>> > GUARD
>> >    354              if (thousands[cnt] != end[cnt])            //
>> > BODY
>> >    355                break;
>> >    356              cnt < thousands_len; })                    //
>> > NEXT
>> >
>> > and so it uses the column of the "&&", and treats it as if it were
>> > indented thus:
>> >
>> >    353        for (cnt = 0; cnt < thousands_len; ++cnt)        //
>> > GUARD
>> >    354              if (thousands[cnt] != end[cnt])            //
>> > BODY
>> >    355                break;
>> >    356              cnt < thousands_len; })                    //
>> > NEXT
>> >
>> > and thus issues a warning.
>> >
>> > As far as I can tell the heuristic in question only makes sense for
>> > "else" clauses, so the following patch updates it to only use the
>> > special column when handling "else" clauses, eliminating the
>> > overzealous warning.
>>
>> Wouldn't this change have the undesirable effect of no longer warning
>> about:
>>
>>       if (p)
>>         foo (1);
>>       } else if (q)
>>         foo (2);
>>         foo (3);
>
> No, because the rejection based on indentation is done relative to
>  guard_line_first_nws, rather than guard_vis_column (I tried doing it
> via the latter in one version of the patch, and that broke some of the
> existing cases, so I didn't make that change).

I see. That clears things up for me, thanks.

>
> See the attached test file (which doesn't have dg-directives yet); the
> example you give is test1_d, with an open-brace added to the "if (p)".
>
> Trunk emits warnings for:
>   * test1_c
>   * test1_d
>   * test1_e
>   * test1_f (two warnings, one for the "if", one for the "else")
>   * test1_g
>   * test2_c
>   * test2_d
>   * test2_e
>
> With the patches, it emits warnings for:
>   * test1_c
>   * test1_d
>   * test1_e
>   * test1_f (just one warnings, for the "if")
>   * test1_g
>   * test2_c
>   * test2_d
>   * test2_e
>
> so the only change is the removal of the erroneous double warning for
> the "else" in test1_f.

Nice!
Jeff Law March 4, 2016, 7:15 a.m. UTC | #4
On 03/03/2016 08:21 AM, David Malcolm wrote:
> PR c/68187 covers two cases involving poor indentation where
> the indentation is arguably not misleading, but for which
> -Wmisleading-indentation emits a warning.
>
> The two cases appear to be different in nature; one in comment #0
> and the other in comment #1.  Richi marked the bug as a whole as
> a P1 regression; it's not clear to me if he meant one or both of
> these cases, so the following two patches fix both.
>
> The rest of this post addresses the case in comment #0 of the PR;
> the followup post addresses the other case, in comment #1 of the PR.
>
> Building glibc (a9224562cbe9cfb0bd8d9e637a06141141f9e6e3) on x86_64
> led to this diagnostic from -Wmisleading-indentation:
>
> ../stdlib/strtol_l.c: In function '____strtoul_l_internal':
> ../stdlib/strtol_l.c:356:9: error: statement is indented as if it were guarded by... [-Werror=misleading-indentation]
>           cnt < thousands_len; })
>           ^
> ../stdlib/strtol_l.c:353:9: note: ...this 'for' clause, but it is not
>     && ({ for (cnt = 0; cnt < thousands_len; ++cnt)
>           ^
>
> The code is question looks like this:
>
>     348            for (c = *end; c != L_('\0'); c = *++end)
>     349              if (((STRING_TYPE) c < L_('0') || (STRING_TYPE) c > L_('9'))
>     350  # ifdef USE_WIDE_CHAR
>     351                  && (wchar_t) c != thousands
>     352  # else
>     353                  && ({ for (cnt = 0; cnt < thousands_len; ++cnt)
>     354                        if (thousands[cnt] != end[cnt])
>     355                          break;
>     356                        cnt < thousands_len; })
>     357  # endif
>     358                  && (!ISALPHA (c)
>     359                      || (int) (TOUPPER (c) - L_('A') + 10) >= base))
>     360                break;
>
> Lines 354 and 355 are poorly indented, leading to the warning from
> -Wmisleading-indentation at line 356.
>
> The wording of the warning is clearly wrong: line 356 isn't indented as if
> guarded by line 353, it's more that lines 354 and 355 *aren't* indented.
>
> What's happening is that should_warn_for_misleading_indentation has a
> heuristic for handling "} else", such as:
>
>       if (p)
>         foo (1);
>       } else       // GUARD
>         foo (2);   // BODY
>         foo (3);   // NEXT
>
> and this heuristic uses the first non-whitespace character in the line
> containing GUARD as the column of interest: the "}" character.
>
> In this case we have:
>
>     353        && ({ for (cnt = 0; cnt < thousands_len; ++cnt)  // GUARD
>     354              if (thousands[cnt] != end[cnt])            // BODY
>     355                break;
>     356              cnt < thousands_len; })                    // NEXT
>
> and so it uses the column of the "&&", and treats it as if it were
> indented thus:
>
>     353        for (cnt = 0; cnt < thousands_len; ++cnt)        // GUARD
>     354              if (thousands[cnt] != end[cnt])            // BODY
>     355                break;
>     356              cnt < thousands_len; })                    // NEXT
>
> and thus issues a warning.
>
> As far as I can tell the heuristic in question only makes sense for
> "else" clauses, so the following patch updates it to only use the
> special column when handling "else" clauses, eliminating the
> overzealous warning.
>
> Doing so led to a nonsensical warning for
> libstdc++-v3/src/c++11/random.cc:random_device::_M_init:
>
> random.cc: In member function ‘void std::random_device::_M_init(const string&)’:
> random.cc:102:10: warning: this ‘if’ clause does not guard... [-Wmisleading-indentation]
>       else if (token != "/dev/urandom" && token != "/dev/random")
>            ^~
> random.cc:107:5: note: ...this statement, but the latter is indented as if it does
>       _M_file = static_cast<void*>(std::fopen(fname, "rb"));
>       ^~~~~~~
>
> so the patch addresses this by tweaking the heuristic that rejects
> aligned BODY and NEXT so that it doesn't require them to be aligned with
> the first non-whitespace of the GUARD, simply that they not be indented
> relative to it.
>
> Successfully bootstrapped&regrtested on x86_64-pc-linux-gnu in
> combination with the following patch; standalone bootstrap&regrtest
> is in progress.
>
> OK for trunk if the latter is successful?
>
> gcc/c-family/ChangeLog:
> 	PR c/68187
> 	* c-indentation.c (should_warn_for_misleading_indentation): When
> 	suppressing warnings about cases where the guard and body are on
> 	the same column, only use the first non-whitespace column in place
> 	of the guard token column when dealing with "else" clauses.
> 	When rejecting aligned BODY and NEXT, loosen the requirement
> 	from equality with the first non-whitespace of guard to simply
> 	that they not be indented relative to it.
>
> gcc/testsuite/ChangeLog:
> 	PR c/68187
> 	* c-c++-common/Wmisleading-indentation.c (fn_40_a): New test
> 	function.
> 	(fn_40_b): Likewise.
> 	(fn_41_a): Likewise.
> 	(fn_41_b): Likewise.
OK.

FWIW, I think all of c-indentation would fall under the diagnostics 
maintainership you picked up recently.

jeff
diff mbox

Patch

diff --git a/gcc/c-family/c-indentation.c b/gcc/c-family/c-indentation.c
index 521f992..c72192d 100644
--- a/gcc/c-family/c-indentation.c
+++ b/gcc/c-family/c-indentation.c
@@ -419,7 +419,8 @@  should_warn_for_misleading_indentation (const token_indent_info &guard_tinfo,
 	{
           /* Don't warn if they are aligned on the same column
 	     as the guard itself (suggesting autogenerated code that doesn't
-	     bother indenting at all).  We consider the column of the first
+	     bother indenting at all).
+	     For "else" clauses, we consider the column of the first
 	     non-whitespace character on the guard line instead of the column
 	     of the actual guard token itself because it is more sensible.
 	     Consider:
@@ -438,14 +439,17 @@  should_warn_for_misleading_indentation (const token_indent_info &guard_tinfo,
 	       foo (2);   // BODY
 	       foo (3);   // NEXT
 
-	     If we just used the column of the guard token, we would warn on
+	     If we just used the column of the "else" token, we would warn on
 	     the first example and not warn on the second.  But we want the
 	     exact opposite to happen: to not warn on the first example (which
 	     is probably autogenerated) and to warn on the second (whose
 	     indentation is misleading).  Using the column of the first
 	     non-whitespace character on the guard line makes that
 	     happen.  */
-	  if (guard_line_first_nws == body_vis_column)
+	  unsigned int guard_column = (guard_tinfo.keyword == RID_ELSE
+				       ? guard_line_first_nws
+				       : guard_vis_column);
+	  if (guard_column == body_vis_column)
 	    return false;
 
 	  /* We may have something like:
@@ -458,9 +462,9 @@  should_warn_for_misleading_indentation (const token_indent_info &guard_tinfo,
 	     foo (3);  // NEXT
 
 	     in which case the columns are not aligned but the code is not
-	     misleadingly indented.  If the column of the body is less than
-	     that of the guard line then don't warn.  */
-	  if (body_vis_column < guard_line_first_nws)
+	     misleadingly indented.  If the column of the body isn't indented
+	     more than the guard line then don't warn.  */
+	  if (body_vis_column <= guard_line_first_nws)
 	    return false;
 
 	  /* Don't warn if there is multiline preprocessor logic between
diff --git a/gcc/testsuite/c-c++-common/Wmisleading-indentation.c b/gcc/testsuite/c-c++-common/Wmisleading-indentation.c
index 25db8fe..04500b7 100644
--- a/gcc/testsuite/c-c++-common/Wmisleading-indentation.c
+++ b/gcc/testsuite/c-c++-common/Wmisleading-indentation.c
@@ -903,3 +903,82 @@  void pr69122 (void)
   emit foo (1);
 }
 #undef emit
+
+/* In the following, the 'if' within the 'for' statement is not indented,
+   but arguably should be.
+   The for loop:
+     "for (cnt = 0; cnt < thousands_len; ++cnt)"
+   does not guard this conditional:
+     "cnt < thousands_len;".
+   and the poor indentation is not misleading.  Verify that we do
+   not erroneously emit a warning about this.
+   Based on an example seen in glibc (PR c/68187).  */
+
+void
+fn_40_a (const char *end, const char *thousands, int thousands_len)
+{
+  int cnt;
+
+  while (flagA)
+    if (flagA
+        && ({ for (cnt = 0; cnt < thousands_len; ++cnt)
+              if (thousands[cnt] != end[cnt])
+                break;
+              cnt < thousands_len; })
+        && flagB)
+      break;
+}
+
+/* As above, but with the indentation within the "for" loop fixed.
+   We should not emit a warning for this, either.  */
+
+void
+fn_40_b (const char *end, const char *thousands, int thousands_len)
+{
+  int cnt;
+
+  while (flagA)
+    if (flagA
+        && ({ for (cnt = 0; cnt < thousands_len; ++cnt)
+                if (thousands[cnt] != end[cnt])
+                  break;
+              cnt < thousands_len; })
+        && flagB)
+      break;
+}
+
+/* We should not warn for the following
+   (based on libstdc++-v3/src/c++11/random.cc:random_device::_M_init).  */
+
+void
+fn_41_a (void)
+{
+  if (flagA)
+    {
+    }
+  else if (flagB)
+  fail:
+    foo (0);
+
+  foo (1);
+  if (!flagC)
+    goto fail;
+}
+
+/* Tweaked version of the above (with the label indented), which we should
+   also not warn for.  */
+
+void
+fn_41_b (void)
+{
+  if (flagA)
+    {
+    }
+  else if (flagB)
+   fail:
+    foo (0);
+
+  foo (1);
+  if (!flagC)
+    goto fail;
+}