Message ID | 1457018483-26829-1-git-send-email-dmalcolm@redhat.com |
---|---|
State | New |
Headers | show |
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);
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).
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!
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®rtested on x86_64-pc-linux-gnu in > combination with the following patch; standalone bootstrap®rtest > 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 --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; +}