diff options
author | David Malcolm <dmalcolm@redhat.com> | 2016-03-04 15:50:27 +0000 |
---|---|---|
committer | David Malcolm <dmalcolm@gcc.gnu.org> | 2016-03-04 15:50:27 +0000 |
commit | 64b23c13dcf2e7bd771a746f6b477e07e31a045e (patch) | |
tree | 24010d29aad3b44205b89c06002db41c9964abd6 | |
parent | 729526f5d4399d141458ca0026490a1231149338 (diff) | |
download | gcc-64b23c13dcf2e7bd771a746f6b477e07e31a045e.zip gcc-64b23c13dcf2e7bd771a746f6b477e07e31a045e.tar.gz gcc-64b23c13dcf2e7bd771a746f6b477e07e31a045e.tar.bz2 |
PR c/68187: fix overzealous -Wmisleading-indentation (comment #1)
gcc/c-family/ChangeLog:
PR c/68187
* c-indentation.c (get_visual_column): Move code to determine next
tab stop to...
(next_tab_stop): ...this new function.
(line_contains_hash_if): Delete function.
(detect_preprocessor_logic): Delete function.
(get_first_nws_vis_column): New function.
(detect_intervening_unindent): New function.
(should_warn_for_misleading_indentation): Replace call to
detect_preprocessor_logic with a call to
detect_intervening_unindent.
gcc/testsuite/ChangeLog:
PR c/68187
* c-c++-common/Wmisleading-indentation.c (fn_42_a): New test
function.
(fn_42_b): Likewise.
(fn_42_c): Likewise.
From-SVN: r233972
-rw-r--r-- | gcc/c-family/ChangeLog | 14 | ||||
-rw-r--r-- | gcc/c-family/c-indentation.c | 141 | ||||
-rw-r--r-- | gcc/testsuite/ChangeLog | 8 | ||||
-rw-r--r-- | gcc/testsuite/c-c++-common/Wmisleading-indentation.c | 72 |
4 files changed, 174 insertions, 61 deletions
diff --git a/gcc/c-family/ChangeLog b/gcc/c-family/ChangeLog index fa728f0..f285c8b 100644 --- a/gcc/c-family/ChangeLog +++ b/gcc/c-family/ChangeLog @@ -1,6 +1,20 @@ 2016-03-04 David Malcolm <dmalcolm@redhat.com> PR c/68187 + * c-indentation.c (get_visual_column): Move code to determine next + tab stop to... + (next_tab_stop): ...this new function. + (line_contains_hash_if): Delete function. + (detect_preprocessor_logic): Delete function. + (get_first_nws_vis_column): New function. + (detect_intervening_unindent): New function. + (should_warn_for_misleading_indentation): Replace call to + detect_preprocessor_logic with a call to + detect_intervening_unindent. + +2016-03-04 David Malcolm <dmalcolm@redhat.com> + + 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 diff --git a/gcc/c-family/c-indentation.c b/gcc/c-family/c-indentation.c index c72192d..b84fbf4 100644 --- a/gcc/c-family/c-indentation.c +++ b/gcc/c-family/c-indentation.c @@ -26,6 +26,16 @@ along with GCC; see the file COPYING3. If not see extern cpp_options *cpp_opts; +/* Round up VIS_COLUMN to nearest tab stop. */ + +static unsigned int +next_tab_stop (unsigned int vis_column) +{ + const unsigned int tab_width = cpp_opts->tabstop; + vis_column = ((vis_column + tab_width) / tab_width) * tab_width; + return vis_column; +} + /* Convert libcpp's notion of a column (a 1-based char count) to the "visual column" (0-based column, respecting tabs), by reading the relevant line. @@ -77,11 +87,7 @@ get_visual_column (expanded_location exploc, location_t loc, } if (ch == '\t') - { - /* Round up to nearest tab stop. */ - const unsigned int tab_width = cpp_opts->tabstop; - vis_column = ((vis_column + tab_width) / tab_width) * tab_width; - } + vis_column = next_tab_stop (vis_column); else vis_column++; } @@ -93,54 +99,49 @@ get_visual_column (expanded_location exploc, location_t loc, return true; } -/* Does the given source line appear to contain a #if directive? - (or #ifdef/#ifndef). Ignore the possibility of it being inside a - comment, for simplicity. - Helper function for detect_preprocessor_logic. */ +/* Attempt to determine the first non-whitespace character in line LINE_NUM + of source line FILE. + + If this is possible, return true and write its "visual column" to + *FIRST_NWS. + Otherwise, return false, leaving *FIRST_NWS untouched. */ static bool -line_contains_hash_if (const char *file, int line_num) +get_first_nws_vis_column (const char *file, int line_num, + unsigned int *first_nws) { + gcc_assert (first_nws); + int line_len; const char *line = location_get_source_line (file, line_num, &line_len); if (!line) return false; + unsigned int vis_column = 0; + for (int i = 1; i < line_len; i++) + { + unsigned char ch = line[i - 1]; - int idx; - - /* Skip leading whitespace. */ - for (idx = 0; idx < line_len; idx++) - if (!ISSPACE (line[idx])) - break; - if (idx == line_len) - return false; - - /* Require a '#' character. */ - if (line[idx] != '#') - return false; - idx++; + if (!ISSPACE (ch)) + { + *first_nws = vis_column; + return true; + } - /* Skip whitespace. */ - while (idx < line_len) - { - if (!ISSPACE (line[idx])) - break; - idx++; + if (ch == '\t') + vis_column = next_tab_stop (vis_column); + else + vis_column++; } - /* Match #if/#ifdef/#ifndef. */ - if (idx + 2 <= line_len) - if (line[idx] == 'i') - if (line[idx + 1] == 'f') - return true; - + /* No non-whitespace characters found. */ return false; } - -/* Determine if there is preprocessor logic between +/* Determine if there is an unindent/outdent between BODY_EXPLOC and NEXT_STMT_EXPLOC, to ensure that we don't - issue a warning for cases like this: + issue a warning for cases like the following: + + (1) Preprocessor logic if (flagA) foo (); @@ -151,31 +152,47 @@ line_contains_hash_if (const char *file, int line_num) bar (); ^ NEXT_STMT_EXPLOC - despite "bar ();" being visually aligned below "foo ();" and - being (as far as the parser sees) the next token. + "bar ();" is visually aligned below "foo ();" and + is (as far as the parser sees) the next token, but + this isn't misleading to a human reader. - Return true if such logic is detected. */ + (2) Empty macro with bad indentation -static bool -detect_preprocessor_logic (expanded_location body_exploc, - expanded_location next_stmt_exploc) -{ - gcc_assert (next_stmt_exploc.file == body_exploc.file); - gcc_assert (next_stmt_exploc.line > body_exploc.line); + In the following, the + "if (i > 0)" + is poorly indented, and ought to be on the same column as + "engine_ref_debug(e, 0, -1)" + However, it is not misleadingly indented, due to the presence + of that macro. - if (next_stmt_exploc.line - body_exploc.line < 4) - return false; + #define engine_ref_debug(X, Y, Z) + + if (locked) + i = foo (0); + else + i = foo (1); + engine_ref_debug(e, 0, -1) + if (i > 0) + return 1; - /* Is there a #if/#ifdef/#ifndef directive somewhere in the lines - between the given locations? + Return true if such an unindent/outdent is detected. */ - This is something of a layering violation, but by necessity, - given the nature of what we're testing for. For example, - in theory we could be fooled by a #if within a comment, but - it's unlikely to matter. */ - for (int line = body_exploc.line + 1; line < next_stmt_exploc.line; line++) - if (line_contains_hash_if (body_exploc.file, line)) - return true; +static bool +detect_intervening_unindent (const char *file, + int body_line, + int next_stmt_line, + unsigned int vis_column) +{ + gcc_assert (file); + gcc_assert (next_stmt_line > body_line); + + for (int line = body_line + 1; line < next_stmt_line; line++) + { + unsigned int line_vis_column; + if (get_first_nws_vis_column (file, line, &line_vis_column)) + if (line_vis_column < vis_column) + return true; + } /* Not found. */ return false; @@ -467,9 +484,11 @@ should_warn_for_misleading_indentation (const token_indent_info &guard_tinfo, if (body_vis_column <= guard_line_first_nws) return false; - /* Don't warn if there is multiline preprocessor logic between - the two statements. */ - if (detect_preprocessor_logic (body_exploc, next_stmt_exploc)) + /* Don't warn if there is an unindent between the two statements. */ + int vis_column = MIN (next_stmt_vis_column, body_vis_column); + if (detect_intervening_unindent (body_exploc.file, body_exploc.line, + next_stmt_exploc.line, + vis_column)) return false; /* Otherwise, they are visually aligned: issue a warning. */ diff --git a/gcc/testsuite/ChangeLog b/gcc/testsuite/ChangeLog index b659439..3c5caac 100644 --- a/gcc/testsuite/ChangeLog +++ b/gcc/testsuite/ChangeLog @@ -1,6 +1,14 @@ 2016-03-04 David Malcolm <dmalcolm@redhat.com> PR c/68187 + * c-c++-common/Wmisleading-indentation.c (fn_42_a): New test + function. + (fn_42_b): Likewise. + (fn_42_c): Likewise. + +2016-03-04 David Malcolm <dmalcolm@redhat.com> + + PR c/68187 * c-c++-common/Wmisleading-indentation.c (fn_40_a): New test function. (fn_40_b): Likewise. diff --git a/gcc/testsuite/c-c++-common/Wmisleading-indentation.c b/gcc/testsuite/c-c++-common/Wmisleading-indentation.c index 04500b7..7b499d4 100644 --- a/gcc/testsuite/c-c++-common/Wmisleading-indentation.c +++ b/gcc/testsuite/c-c++-common/Wmisleading-indentation.c @@ -982,3 +982,75 @@ fn_41_b (void) if (!flagC) goto fail; } + +/* In the following, the + "if (i > 0)" + is poorly indented, and ought to be on the same column as + "engine_ref_debug(e, 0, -1)" + However, it is not misleadingly indented, due to the presence + of that macro. Verify that we do not emit a warning about it + not being guarded by the "else" clause above. + + Based on an example seen in OpenSSL 1.0.1, which was filed as + PR c/68187 in comment #1, though it's arguably a separate bug to + the one in comment #0. */ + +int +fn_42_a (int locked) +{ +#define engine_ref_debug(X, Y, Z) + + int i; + + if (locked) + i = foo (0); + else + i = foo (1); + engine_ref_debug(e, 0, -1) + if (i > 0) + return 1; + return 0; +#undef engine_ref_debug +} + +/* As above, but the empty macro is at the same indentation level. + This *is* misleading; verify that we do emit a warning about it. */ + +int +fn_42_b (int locked) +{ +#define engine_ref_debug(X, Y, Z) + + int i; + + if (locked) + i = foo (0); + else /* { dg-message "...this .else. clause" } */ + i = foo (1); + engine_ref_debug(e, 0, -1) + if (i > 0) /* { dg-warning "statement is indented" } */ + return 1; + return 0; +#undef engine_ref_debug +} + +/* As above, but where the body is a semicolon "hidden" by a preceding + comment, where the semicolon is not in the same column as the successor + "if" statement, but the empty macro expansion is at the same indentation + level as the guard. + This is poor indentation, but not misleading; verify that we don't emit a + warning about it. */ + +int +fn_42_c (int locked, int i) +{ +#define engine_ref_debug(X, Y, Z) + + if (locked) + /* blah */; + engine_ref_debug(e, 0, -1) + if (i > 0) + return 1; + return 0; +#undef engine_ref_debug +} |