On Thu, 2015-04-16 at 10:26 -0700, Mike Stump wrote: > On Apr 16, 2015, at 8:01 AM, David Malcolm <dmalc...@redhat.com> wrote: > > Attached is a work-in-progress patch for a new > > -Wmisleading-indentation > > warning I've been experimenting with, for GCC 6. > > Seems like a nice idea in general. > > Does it also handle: > > if (cone); > stmt; > > ? Would be good to add that to the test suite, as that is another hard to > spot common error that should be caught.
Not yet, but I agree that it would be a good thing to issue a warning for. > I do think that it is reasonable to warn for things like: > > stmt; > stmt; > > one of those two lines is likely misindented, though, maybe you want to start > with the high payback things first. > > An issue here is how to determine (i), or if it's OK to default to 8 > > Yes, 8 is the proper value to default it to. > > > and have a command-line option (param?) to override it? (though what about, > > say, each header file?) > > I’ll abstain from this. The purist in me says no option for other > than 8, life goes on. 20 years ago, someone was confused over hard v > soft tabbing and what exactly the editor key TAB does. That confusion > is over, the 8 people have won. Catering to other than 8 gives the > impression that the people that lost still have a chance at > winning. :-) > > > Thoughts on this, and on the patch? > > Would be nice to have a stricter version that warns about all wildly > inconsistently or wrongly indented lines. > > { > stmt; > stmt; // must be same as above > } > > { > stmt; // must be indented at least 1 > } > > if (cond) > stmt; // must be indented at least 1 I think I want to make a distinction between (A) classic C "gotchas", like the one in my mail and the: if (cond); stmt; one you mentioned above vs (B) wrong/inconsistent indentation. I think (A) is high-value, since it detects subtly wrong code, likely to have misled the reader, whereas I don't find (B) as interesting. I think (A) is "misleading", whereas (B) is "wrong"; the ugliness of the (B) cases tends to give me a "this code is ugly; beware, danger Will Robinson!" reaction, whereas (A) is less ugly and thus more dangerous. (if that makes sense; this may just be my own visceral reaction to the erroneous code). Or to put it another way, I hope to make (A) good enough to go into -Wall, whereas I think (B) would meet more resistance. Also, I think autogenerated code is more likely to run into (B) than (A). I have the patch working now for the C++ frontend. Am attaching the work-in-progress (sans ChangeLog). This one (v2) bootstrapped and regrtested on x86_64-unknown-linux-gnu (Fedora 20), with: 63 new "PASS" results in gcc.sum 189 new "PASS" results in g++.sum for the new test cases (relative to a control build of r222248). I also moved the visual-parser.c/h to c-family, to make use of the -ftabstop option Tom mentioned in another mail. I also made it identify the kind of clause, so error messages say things like: ./Wmisleading-indentation-1.c:10:7: warning: statement is indented as if it were guarded by... [-Wmisleading-indentation] ./Wmisleading-indentation-1.c:8:3: note: ...this 'if' clause, but it is not which makes it easier to read, especially when dealing with nesting. This hasn't yet had any performance/leak fixes so it isn't ready as is. I plan to look at making it warn about the: if (cond); stmt; gotcha next, before trying to optimize it. (and no ChangeLog yet) Dave
diff --git a/gcc/Makefile.in b/gcc/Makefile.in index 80c91f0..8154469 100644 --- a/gcc/Makefile.in +++ b/gcc/Makefile.in @@ -1143,7 +1143,8 @@ C_COMMON_OBJS = c-family/c-common.o c-family/c-cppbuiltin.o c-family/c-dump.o \ c-family/c-ppoutput.o c-family/c-pragma.o c-family/c-pretty-print.o \ c-family/c-semantics.o c-family/c-ada-spec.o \ c-family/c-cilkplus.o \ - c-family/array-notation-common.o c-family/cilk.o c-family/c-ubsan.o + c-family/array-notation-common.o c-family/cilk.o c-family/c-ubsan.o \ + c-family/visual-parser.o # Language-independent object files. # We put the insn-*.o files first so that a parallel make will build diff --git a/gcc/c-family/c.opt b/gcc/c-family/c.opt index 983f4a8..88f1f94 100644 --- a/gcc/c-family/c.opt +++ b/gcc/c-family/c.opt @@ -554,6 +554,10 @@ Wmemset-transposed-args C ObjC C++ ObjC++ Var(warn_memset_transposed_args) Warning LangEnabledBy(C ObjC C++ ObjC++,Wall) Warn about suspicious calls to memset where the third argument is constant literal zero and the second is not +Wmisleading-indentation +C C++ Common Var(warn_misleading_indentation) Warning +Warn when the indentation of the code does not reflect the block structure + Wmissing-braces C ObjC C++ ObjC++ Var(warn_missing_braces) Warning LangEnabledBy(C ObjC,Wall) Warn about possibly missing braces around initializers diff --git a/gcc/c-family/visual-parser.c b/gcc/c-family/visual-parser.c new file mode 100644 index 0000000..b1fcb8b --- /dev/null +++ b/gcc/c-family/visual-parser.c @@ -0,0 +1,337 @@ +/* "Visual parser" for detecting misleading indentation. + Copyright (C) 2015 Free Software Foundation, Inc. + Contributed by David Malcolm <dmalc...@redhat.com>. + +This file is part of GCC. + +GCC is free software; you can redistribute it and/or modify it under +the terms of the GNU General Public License as published by the Free +Software Foundation; either version 3, or (at your option) any later +version. + +GCC is distributed in the hope that it will be useful, but WITHOUT ANY +WARRANTY; without even the implied warranty of MERCHANTABILITY or +FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License +for more details. + +You should have received a copy of the GNU General Public License +along with GCC; see the file COPYING3. If not see +<http://www.gnu.org/licenses/>. */ + +#include "config.h" +#include "system.h" +#include "coretypes.h" +#include "tm.h" /* For rtl.h: needs enum reg_class. */ +#include "hash-set.h" +#include "machmode.h" +#include "vec.h" +#include "double-int.h" +#include "input.h" +#include "alias.h" +#include "symtab.h" +#include "wide-int.h" +#include "inchash.h" +#include "tree.h" +#include "stringpool.h" +#include "attribs.h" +#include "stor-layout.h" +#include "varasm.h" +#include "trans-mem.h" +#include "langhooks.h" +#include "input.h" +#include "cpplib.h" +#include "timevar.h" +#include "c-family/c-pragma.h" +#include "flags.h" +#include "ggc.h" +#include "vec.h" +#include "target.h" +#include "visual-parser.h" +#include "diagnostic-core.h" +#include "tree-iterator.h" + +extern cpp_options *cpp_opts; + +/* Ptr to the singleton instance of visual_parser. */ +visual_parser *vis_parser; + +/* The ctor for visual_parser. */ +visual_parser::visual_parser () +{ + m_debug = false; + m_last_xloc.file = NULL; + m_last_xloc.line = 0; + m_last_xloc.column = 0; +} + +static expanded_location +expand_location_with_visual_column (location_t loc) +{ + /* Get file/line info. */ + expanded_location xloc = expand_location (loc); + + /* Convert libcpp's notion of a column (a 1-based char count) to + the "visual column" (respecting tabs), by reading the + relevant line. */ + int line_len; + const char *line = location_get_source_line (xloc, &line_len); + int vis_column = 0; + for (int i = 1; i < xloc.column; i++) + { + unsigned char ch = line[i - 1]; + 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; + } + else + vis_column++; + } + + xloc.column = vis_column; + //inform (loc, "vis column is %i", vis_column); + return xloc; +} + +/* Token-handling. This takes a stream of locations, examining their + spelling locations, and calling on_indent, on_line, on_outdent + accordingly. */ + +void +visual_parser::on_token (location_t loc) +{ + if (m_debug) + inform (loc, "on_token"); + + /* TODO: only do the perhaps-expensive vis_column work if the line changed? */ + expanded_location xloc = expand_location_with_visual_column (loc); + if (xloc.line != m_last_xloc.line) + { + //inform (loc, "first token on new line"); + visual_block *curblock = get_stack_top (); + if (curblock) + { + /* FIXME: what about entirely empty lines??? + Presumably they simply don't get tokens. */ + int last_indent = curblock->get_column (); + if (xloc.column > last_indent) + { + /* This line starts more indented than any current + indentation level; begin a new "visual block". */ + visual_block *block = new visual_block (loc, xloc.column); + if (m_debug) + inform (loc, "new visual block here: %p", (void *)block); + m_block_stack.safe_push (block); + on_indent (loc); + } + else if (xloc.column == last_indent) + { + /* This line is at the same indentation level as before, + within the current "visual block". */ + on_line (loc); + } + else + { + /* We have some amount of outdenting; how much? */ + while (m_block_stack.length ()) + { + visual_block *block = m_block_stack.pop (); + if (m_debug) + inform (block->get_location (), + "closing visual block %p", (void *)block); + on_outdent (loc); + visual_block *new_top = get_stack_top (); + if (new_top) + if (new_top->get_column () <= xloc.column) + { + if (m_debug) + inform (new_top->get_location (), + "outdented to within visual block %p", + (void *)new_top); + break; + } + } + } + } + else + { + /* No current indentation level; start one. */ + visual_block *block = new visual_block (loc, xloc.column); + m_block_stack.safe_push (block); + on_indent (loc); + } + } + m_last_xloc = xloc; +} + +/* Called when we have a token that's on a new line that's more indented + than the token that began the last line. */ +void +visual_parser::on_indent (location_t loc) +{ + if (m_debug) + inform (loc, "on_indent"); +} + +/* Called when we have a token that's on a new line that's less indented + than the token that began the last line. */ + +void +visual_parser::on_outdent (location_t loc) +{ + if (m_debug) + inform (loc, "on_outdent"); +} + +/* Called for the first token on a new line that's at the same indentation + level as the previous line. */ +void +visual_parser::on_line (location_t loc) +{ + if (m_debug) + inform (loc, "on_line"); + visual_block *curblock = get_stack_top (); + curblock->on_line (loc); +} + +/* FIXME. */ +visual_block * +visual_parser::get_block_containing_loc (location_t loc) const +{ + int i; + visual_block *vis_block; + visual_block *candidate = NULL; + FOR_EACH_VEC_ELT(m_block_stack, i, vis_block) + if (vis_block->get_location () <= loc) + candidate = vis_block; + else + break; + + return candidate; +} + +/* Called by the C/C++ FE when we have a guarding statement at GUARD_LOC + containing BLOCK, where the block wasn't written using braces, like + this: + + guard-loc + | + V + if (flag) + foo (); <--BLOCK + + so that we can detect followup statements that are within + the same "visual block" as the guarded statement, but which + aren't logically grouped within the guarding statement, such + as: + + if (flag) + foo (); + bar (); + + In the above, "bar ();" isn't guarded by the "if", but + misleading is in the same visual block as "foo ();". */ + +void +visual_parser::on_solo_stmt (tree block, location_t guard_loc, + const char *guard_kind) +{ + /* Locate the visual block containing the solo-stmt, and mark + it as such. */ + + tree_stmt_iterator tsi = tsi_start (block); + tree stmt = tsi_stmt (tsi); + location_t loc_solo_stmt = EXPR_LOCATION (stmt); + visual_block *vis_block = get_block_containing_loc (loc_solo_stmt); + + vis_block->on_solo_stmt (stmt, guard_loc, guard_kind); +} + +/* See comment above for visual_parser::on_solo_stmt. + Mark the visual block containing the solo statement STMT as + (supposedly) only containing a solo statement. */ + +void +visual_block::on_solo_stmt (tree stmt, location_t guard_loc, + const char *guard_kind) +{ + m_loc_solo_stmt = EXPR_LOCATION (stmt); + m_loc_guard = guard_loc; + + m_exploc_solo_stmt + = expand_location_with_visual_column (m_loc_solo_stmt); + m_exploc_guard + = expand_location_with_visual_column (guard_loc); + + /* If the solo-stmt is on a new line and more indented than + the guard location, mark the current visual block (which + presumably contains the solo stmt) for checking. + Doing this rejects cases such as + if (foo) bar (); baz (); + where it's not clear whether or not we ought to warn about + "baz ();" and hence we don't. */ + if (m_exploc_solo_stmt.file == m_exploc_guard.file) + if (m_exploc_solo_stmt.line > m_exploc_guard.line) + if (m_exploc_solo_stmt.column > m_exploc_guard.column) + { + if (0) + { + inform (m_loc, + "visual_block here (this=%p)", (void *)this); + inform (m_loc_solo_stmt, + "solo statement here (this=%p)", (void *)this); + inform (m_loc_guard, + "visually guarded here (this=%p)", (void *)this); + } + m_has_solo_stmt = true; + m_guard_kind = guard_kind; + } +} + +/* Check NEW_STMT for misleading indentation. + Called when adding NEW_STMT to a statement list. + + If we have a solo statement, and we're in the same + visual block, and NEW_STMT is visually after the + solo statement, then NEW_STMT is misleadingly indented as + if were guarded by the guard, but it isn't. + Issue a warning for such a statement. */ + +void +visual_parser::check_stmt (tree new_stmt) +{ + if (m_debug) + inform (EXPR_LOCATION (new_stmt), "check_stmt"); + get_stack_top ()->check_stmt (new_stmt); +} + +/* See comment above for visual_parser::check_stmt. */ + +void +visual_block::check_stmt (tree new_stmt) +{ + if (!m_has_solo_stmt) + return; + + location_t loc_new_stmt = EXPR_LOCATION (new_stmt); + //inform (loc_new_stmt, "checking stmt here"); + + expanded_location exploc_new_stmt + = expand_location_with_visual_column (loc_new_stmt); + + if (exploc_new_stmt.file == m_exploc_guard.file) + { + if (/* Statement is visually after the guarded stmt. */ + (exploc_new_stmt.line == m_exploc_solo_stmt.line + && exploc_new_stmt.column > m_exploc_solo_stmt.column) + || (exploc_new_stmt.line > m_exploc_solo_stmt.line)) + if (warning_at (loc_new_stmt, + OPT_Wmisleading_indentation, + "statement is indented as if it" + " were guarded by...")) + inform (m_loc_guard, + "...this '%s' clause, but it is not", + m_guard_kind); + } +} diff --git a/gcc/c-family/visual-parser.h b/gcc/c-family/visual-parser.h new file mode 100644 index 0000000..bbc0483 --- /dev/null +++ b/gcc/c-family/visual-parser.h @@ -0,0 +1,172 @@ +/* "Visual parser" for detecting misleading indentation. + Copyright (C) 2015 Free Software Foundation, Inc. + Contributed by David Malcolm <dmalc...@redhat.com>. + +This file is part of GCC. + +GCC is free software; you can redistribute it and/or modify it under +the terms of the GNU General Public License as published by the Free +Software Foundation; either version 3, or (at your option) any later +version. + +GCC is distributed in the hope that it will be useful, but WITHOUT ANY +WARRANTY; without even the implied warranty of MERCHANTABILITY or +FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License +for more details. + +You should have received a copy of the GNU General Public License +along with GCC; see the file COPYING3. If not see +<http://www.gnu.org/licenses/>. */ + +/* Forward declaration. */ +class visual_block; + +/* A "visual parser" for detecting misleading indentation. + + This is fed three things by the frontend: + + (A) a series of location_t by the frontend's tokenizer, + corresponding to the locations of the token stream. It uses + this to model a stack of "visual blocks", corresponding to + indentation levels within the source code. + For example: + + Source VBlock # VBlock stack + ------ -------- ------------ + void 0 [b0] + foo (int i) 0 [b0] + { 0 [b0] + int j; .1 [b0, b1] + if (i) .1 [b0, b1] + { ..2 [b0, b1, b2] + foo (0); ...3 [b0, b1, b2, b3] + bar (0); ...3 [b0, b1, b2, b3] + } ..2 [b0, b1, b2] + else .1 [b0, b1] + foo (1); ..4 [b0, b1, b4] + bar (1); ..4 [b0, b1, b4] <-- WARNING! + } 0 [b0] + + Note how the call to "bar (1);" called out with "WARNING!" is + indented as if it's in the same block as the call to "foo (1);", + guarded by the "else" (both are in visual block 4), but they are + *not* in the same actual block as far as the real frontend + (and language standards) see it. + The purpose of this class is to issue a warning about this + misleading indentation. + + (2) The frontend notifies the class about "solo statements", that + is, non-compound statements guarded by control-flow statements, + such as "foo (1);", a non-compound statement guarded by the else + clause. Misleading indentation can occur in the statement + immediately following such a non-compound statement, if the + successor statement is indented in the same way + (i.e. it is within the same visual block). + + (3) The frontend notifiees the class about statements being added + to a statement list. If we have a guarded non-compound statement, + the new statements can be checked for misleading indentation. + + Note that we can't simply use statement locations; for example, in: + if (flag) + x = 1; + the "if (flag)"'s location is at the open-paren, and that of the + assignment "x = 1;" is at the equals-sign, so any attempt to use + statement locations can be fooled by varying the spacing: + + V + if (flag) + x = 1; + ^ apparent indentation relative to conditional + + V + if (flag) + x = 1; + ^ same column as conditional + + V + if (flag) + x = 1; + ^ apparent "outdent" relative to conditional + + Hence we have to use token locations. */ + +class GTY(()) visual_parser { + public: + visual_parser (); + void on_token (location_t loc); + void on_solo_stmt (tree block, location_t guard_loc, + const char *guard_kind); + void check_stmt (tree stmt); + + private: + void on_newline (location_t loc); + + void on_indent (location_t loc); + void on_outdent (location_t loc); + void on_line (location_t loc); + + visual_block * get_stack_top () const + { + if (m_block_stack.length ()) + return m_block_stack[m_block_stack.length () - 1]; + else + return NULL; + } + + visual_block * get_block_containing_loc (location_t loc) const; + + private: + bool m_debug; + expanded_location m_last_xloc; + /* A stack of indentation levels. */ + auto_vec<visual_block *> m_block_stack; +}; + +/* A visual block: a run of lines with the same initial indentation. */ + +class visual_block +{ + public: + visual_block (location_t loc, int column_start) + : m_loc (loc), + m_loc_last_line (loc), + m_column_start (column_start), + m_has_solo_stmt (false) + {} + + location_t get_location () const { return m_loc; } + location_t get_last_location () const { return m_loc_last_line; } + int get_column () const { return m_column_start; } + + void on_line (location_t loc) { m_loc_last_line = loc; } + + void on_solo_stmt (tree stmt, location_t guard_loc, + const char *guard_kind); + void check_stmt (tree stmt); + + private: + location_t m_loc; + location_t m_loc_last_line; + int m_column_start; + + /* Detection of misleading indentation. + If m_has_solo_stmt is true, then this visual + block contains a "solo statement" i.e. one within a block + created without braces, such as: + if (flag) <- guard + foo (); <- solo stmt in this visblock + Any followup statements that are in the same visual block as + "foo ();" are therefore misleadingly indented. */ + bool m_has_solo_stmt; + const char *m_guard_kind; + location_t m_loc_solo_stmt; + location_t m_loc_guard; + expanded_location m_exploc_solo_stmt; + expanded_location m_exploc_guard; + +}; + +/* The singleton instance of the visual_parser, created by the + C/C++ frontend if -Wmisleading-indentation is enabled. */ +extern visual_parser *vis_parser; diff --git a/gcc/c/c-decl.c b/gcc/c/c-decl.c index e28a294..ec7a0a4 100644 --- a/gcc/c/c-decl.c +++ b/gcc/c/c-decl.c @@ -81,6 +81,7 @@ along with GCC; see the file COPYING3. If not see #include "c-family/c-ada-spec.h" #include "cilk.h" #include "builtins.h" +#include "c-family/visual-parser.h" /* In grokdeclarator, distinguish syntactic contexts of declarators. */ enum decl_context @@ -651,6 +652,10 @@ add_stmt (tree t) recorded during statement expressions. */ if (!building_stmt_list_p ()) push_stmt_list (); + + if (vis_parser) + vis_parser->check_stmt (t); + append_to_statement_list_force (t, &cur_stmt_list); return t; diff --git a/gcc/c/c-parser.c b/gcc/c/c-parser.c index f5e2ac2c..47186cb 100644 --- a/gcc/c/c-parser.c +++ b/gcc/c/c-parser.c @@ -82,6 +82,7 @@ along with GCC; see the file COPYING3. If not see #include "omp-low.h" #include "builtins.h" #include "gomp-constants.h" +#include "c-family/visual-parser.h" /* Initialization routine for this file. */ @@ -242,7 +243,6 @@ typedef struct GTY(()) c_parser { vec <c_token, va_gc> *cilk_simd_fn_tokens; } c_parser; - /* The actual parser and external interface. ??? Does this need to be garbage-collected? */ @@ -262,6 +262,9 @@ c_lex_one_token (c_parser *parser, c_token *token) token->keyword = RID_MAX; token->pragma_kind = PRAGMA_NONE; + if (vis_parser) + vis_parser->on_token (token->location); + switch (token->type) { case CPP_NAME: @@ -5168,11 +5171,14 @@ c_parser_paren_condition (c_parser *parser) /* Parse a statement which is a block in C99. */ static tree -c_parser_c99_block_statement (c_parser *parser) +c_parser_c99_block_statement (c_parser *parser, location_t guard_loc, + const char *guard_kind) { tree block = c_begin_compound_stmt (flag_isoc99); location_t loc = c_parser_peek_token (parser)->location; c_parser_statement (parser); + if (vis_parser) + vis_parser->on_solo_stmt (block, guard_loc, guard_kind); return c_end_compound_stmt (loc, block, flag_isoc99); } @@ -5185,7 +5191,7 @@ c_parser_c99_block_statement (c_parser *parser) parser->in_if_block. */ static tree -c_parser_if_body (c_parser *parser, bool *if_p) +c_parser_if_body (c_parser *parser, bool *if_p, location_t if_loc) { tree block = c_begin_compound_stmt (flag_isoc99); location_t body_loc = c_parser_peek_token (parser)->location; @@ -5203,7 +5209,11 @@ c_parser_if_body (c_parser *parser, bool *if_p) 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); + { + c_parser_statement_after_labels (parser); + if (vis_parser) + vis_parser->on_solo_stmt (block, if_loc, "if"); + } return c_end_compound_stmt (body_loc, block, flag_isoc99); } @@ -5212,7 +5222,7 @@ c_parser_if_body (c_parser *parser, bool *if_p) specially for the sake of -Wempty-body warnings. */ static tree -c_parser_else_body (c_parser *parser) +c_parser_else_body (c_parser *parser, location_t else_tok_loc) { location_t else_loc = c_parser_peek_token (parser)->location; tree block = c_begin_compound_stmt (flag_isoc99); @@ -5227,7 +5237,12 @@ c_parser_else_body (c_parser *parser) c_parser_consume_token (parser); } else - c_parser_statement_after_labels (parser); + { + c_parser_statement_after_labels (parser); + if (vis_parser) + vis_parser->on_solo_stmt (block, else_tok_loc, "else"); + } + return c_end_compound_stmt (else_loc, block, flag_isoc99); } @@ -5242,7 +5257,7 @@ static void c_parser_if_statement (c_parser *parser) { tree block; - location_t loc; + location_t if_loc, cond_loc; tree cond; bool first_if = false; tree first_body, second_body; @@ -5250,28 +5265,30 @@ c_parser_if_statement (c_parser *parser) tree if_stmt; gcc_assert (c_parser_next_token_is_keyword (parser, RID_IF)); + if_loc = c_parser_peek_token (parser)->location; c_parser_consume_token (parser); block = c_begin_compound_stmt (flag_isoc99); - loc = c_parser_peek_token (parser)->location; + cond_loc = c_parser_peek_token (parser)->location; cond = c_parser_paren_condition (parser); if (flag_cilkplus && contains_cilk_spawn_stmt (cond)) { - error_at (loc, "if statement cannot contain %<Cilk_spawn%>"); + error_at (cond_loc, "if statement cannot contain %<Cilk_spawn%>"); cond = error_mark_node; } in_if_block = parser->in_if_block; parser->in_if_block = true; - first_body = c_parser_if_body (parser, &first_if); + first_body = c_parser_if_body (parser, &first_if, if_loc); parser->in_if_block = in_if_block; if (c_parser_next_token_is_keyword (parser, RID_ELSE)) { + location_t else_tok_loc = c_parser_peek_token (parser)->location; c_parser_consume_token (parser); - second_body = c_parser_else_body (parser); + second_body = c_parser_else_body (parser, else_tok_loc); } else second_body = NULL_TREE; - c_finish_if_stmt (loc, cond, first_body, second_body, first_if); - if_stmt = c_end_compound_stmt (loc, block, flag_isoc99); + c_finish_if_stmt (cond_loc, cond, first_body, second_body, first_if); + if_stmt = c_end_compound_stmt (cond_loc, block, flag_isoc99); /* If the if statement contains array notations, then we expand them. */ if (flag_cilkplus && contains_array_notation_expr (if_stmt)) @@ -5321,7 +5338,7 @@ c_parser_switch_statement (c_parser *parser) c_start_case (switch_loc, switch_cond_loc, expr, explicit_cast_p); save_break = c_break_label; c_break_label = NULL_TREE; - body = c_parser_c99_block_statement (parser); + body = c_parser_c99_block_statement (parser, switch_loc, "switch"); c_finish_case (body, ce.original_type); if (c_break_label) { @@ -5346,6 +5363,7 @@ 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_tok_loc = c_parser_peek_token (parser)->location; c_parser_consume_token (parser); block = c_begin_compound_stmt (flag_isoc99); loc = c_parser_peek_token (parser)->location; @@ -5362,7 +5380,7 @@ c_parser_while_statement (c_parser *parser, bool ivdep) c_break_label = NULL_TREE; save_cont = c_cont_label; c_cont_label = NULL_TREE; - body = c_parser_c99_block_statement (parser); + body = c_parser_c99_block_statement (parser, while_tok_loc, "while"); c_finish_loop (loc, cond, NULL, body, c_break_label, c_cont_label, true); add_stmt (c_end_compound_stmt (loc, block, flag_isoc99)); c_break_label = save_break; @@ -5381,6 +5399,7 @@ c_parser_do_statement (c_parser *parser, bool ivdep) tree block, cond, body, save_break, save_cont, new_break, new_cont; location_t loc; gcc_assert (c_parser_next_token_is_keyword (parser, RID_DO)); + location_t do_tok_loc = c_parser_peek_token (parser)->location; c_parser_consume_token (parser); if (c_parser_next_token_is (parser, CPP_SEMICOLON)) warning_at (c_parser_peek_token (parser)->location, @@ -5392,7 +5411,7 @@ c_parser_do_statement (c_parser *parser, bool ivdep) c_break_label = NULL_TREE; save_cont = c_cont_label; c_cont_label = NULL_TREE; - body = c_parser_c99_block_statement (parser); + body = c_parser_c99_block_statement (parser, do_tok_loc, "do"); c_parser_require_keyword (parser, RID_WHILE, "expected %<while%>"); new_break = c_break_label; c_break_label = save_break; @@ -5640,7 +5659,7 @@ c_parser_for_statement (c_parser *parser, bool ivdep) c_break_label = NULL_TREE; save_cont = c_cont_label; c_cont_label = NULL_TREE; - body = c_parser_c99_block_statement (parser); + body = c_parser_c99_block_statement (parser, for_loc, "for"); if (is_foreach_statement) objc_finish_foreach_loop (loc, object_expression, collection_expression, body, c_break_label, c_cont_label); else @@ -13000,7 +13019,7 @@ c_parser_omp_for_loop (location_t loc, c_parser *parser, enum tree_code code, add_stmt (c_end_compound_stmt (here, stmt, true)); } else - add_stmt (c_parser_c99_block_statement (parser)); + add_stmt (c_parser_c99_block_statement (parser, loc, "omp for")); if (c_cont_label) { tree t = build1 (LABEL_EXPR, void_type_node, c_cont_label); @@ -15403,6 +15422,9 @@ c_parse_file (void) tparser.tokens = &tparser.tokens_buf[0]; the_parser = &tparser; + if (warn_misleading_indentation) + vis_parser = new visual_parser (); + if (c_parser_peek_token (&tparser)->pragma_kind == PRAGMA_GCC_PCH_PREPROCESS) c_parser_pragma_pch_preprocess (&tparser); @@ -15416,6 +15438,10 @@ c_parse_file (void) using_eh_for_cleanups (); c_parser_translation_unit (the_parser); + + delete vis_parser; + vis_parser = NULL; + the_parser = NULL; } diff --git a/gcc/cp/parser.c b/gcc/cp/parser.c index 4ea2ca2..d6c8b89 100644 --- a/gcc/cp/parser.c +++ b/gcc/cp/parser.c @@ -61,6 +61,7 @@ along with GCC; see the file COPYING3. If not see #include "type-utils.h" #include "omp-low.h" #include "gomp-constants.h" +#include "c-family/visual-parser.h" /* The lexer. */ @@ -651,6 +652,11 @@ cp_lexer_new_main (void) lexer = cp_lexer_alloc (); + if (warn_misleading_indentation) + vis_parser = new visual_parser (); + + /* FIXME: delete this. */ + /* Put the first token in the buffer. */ lexer->buffer->quick_push (token); @@ -1058,6 +1064,9 @@ cp_lexer_consume_token (cp_lexer* lexer) gcc_assert (token != &eof_token); gcc_assert (!lexer->in_pragma || token->type != CPP_PRAGMA_EOL); + if (vis_parser) + vis_parser->on_token (lexer->next_token->location); + do { lexer->next_token++; @@ -2065,9 +2074,9 @@ static void cp_parser_declaration_statement (cp_parser *); static tree cp_parser_implicitly_scoped_statement - (cp_parser *, bool *); + (cp_parser *, bool *, location_t, const char *); static void cp_parser_already_scoped_statement - (cp_parser *); + (cp_parser *, location_t, const char *); /* Declarations [gram.dcl.dcl] */ @@ -10174,7 +10183,8 @@ cp_parser_selection_statement (cp_parser* parser, bool *if_p) nested_if = false; } else - cp_parser_implicitly_scoped_statement (parser, &nested_if); + cp_parser_implicitly_scoped_statement (parser, &nested_if, + token->location, "if"); parser->in_statement = in_statement; finish_then_clause (statement); @@ -10184,7 +10194,8 @@ cp_parser_selection_statement (cp_parser* parser, bool *if_p) RID_ELSE)) { /* Consume the `else' keyword. */ - cp_lexer_consume_token (parser->lexer); + location_t else_tok_loc + = cp_lexer_consume_token (parser->lexer)->location; begin_else_clause (statement); /* Parse the else-clause. */ if (cp_lexer_next_token_is (parser->lexer, CPP_SEMICOLON)) @@ -10198,7 +10209,8 @@ cp_parser_selection_statement (cp_parser* parser, bool *if_p) cp_lexer_consume_token (parser->lexer); } else - cp_parser_implicitly_scoped_statement (parser, NULL); + cp_parser_implicitly_scoped_statement (parser, NULL, + else_tok_loc, "else"); finish_else_clause (statement); @@ -10238,7 +10250,8 @@ cp_parser_selection_statement (cp_parser* parser, bool *if_p) in_statement = parser->in_statement; parser->in_switch_statement_p = true; parser->in_statement |= IN_SWITCH_STMT; - cp_parser_implicitly_scoped_statement (parser, NULL); + cp_parser_implicitly_scoped_statement (parser, NULL, + 0, "switch"); parser->in_switch_statement_p = in_switch_statement_p; parser->in_statement = in_statement; @@ -10783,6 +10796,7 @@ 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; @@ -10792,6 +10806,8 @@ cp_parser_iteration_statement (cp_parser* parser, bool ivdep) if (!token) return error_mark_node; + tok_loc = token->location; + /* Remember whether or not we are already within an iteration statement. */ in_statement = parser->in_statement; @@ -10815,7 +10831,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); + cp_parser_already_scoped_statement (parser, tok_loc, "while"); parser->in_statement = in_statement; /* We're done with the while-statement. */ finish_while_stmt (statement); @@ -10830,7 +10846,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); + cp_parser_implicitly_scoped_statement (parser, NULL, 0, "do"); parser->in_statement = in_statement; finish_do_body (statement); /* Look for the `while' keyword. */ @@ -10860,7 +10876,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); + cp_parser_already_scoped_statement (parser, tok_loc, "for"); parser->in_statement = in_statement; /* We're done with the for-statement. */ @@ -11129,7 +11145,9 @@ cp_parser_declaration_statement (cp_parser* parser) Returns the new statement. */ static tree -cp_parser_implicitly_scoped_statement (cp_parser* parser, bool *if_p) +cp_parser_implicitly_scoped_statement (cp_parser* parser, bool *if_p, + location_t guard_loc, + const char *guard_kind) { tree statement; @@ -11155,6 +11173,9 @@ cp_parser_implicitly_scoped_statement (cp_parser* parser, bool *if_p) cp_parser_statement (parser, NULL_TREE, false, if_p); /* Finish the dummy compound-statement. */ finish_compound_stmt (statement); + /* FIXME. */ + if (vis_parser) + vis_parser->on_solo_stmt (cur_stmt_list, guard_loc, guard_kind); } /* Return the statement. */ @@ -11167,11 +11188,17 @@ cp_parser_implicitly_scoped_statement (cp_parser* parser, bool *if_p) scope. */ static void -cp_parser_already_scoped_statement (cp_parser* parser) +cp_parser_already_scoped_statement (cp_parser* parser, location_t guard_loc, + const char *guard_kind) { /* If the token is a `{', then we must take special action. */ if (cp_lexer_next_token_is_not (parser->lexer, CPP_OPEN_BRACE)) - cp_parser_statement (parser, NULL_TREE, false, NULL); + { + cp_parser_statement (parser, NULL_TREE, false, NULL); + if (vis_parser) + vis_parser->on_solo_stmt (cur_stmt_list, guard_loc, + guard_kind); + } else { /* Avoid calling cp_parser_compound_statement, so that we diff --git a/gcc/cp/semantics.c b/gcc/cp/semantics.c index 0fc08b5f..2eab2ca 100644 --- a/gcc/cp/semantics.c +++ b/gcc/cp/semantics.c @@ -67,6 +67,7 @@ along with GCC; see the file COPYING3. If not see #include "builtins.h" #include "convert.h" #include "gomp-constants.h" +#include "c-family/visual-parser.h" /* There routines provide a modular interface to perform many parsing operations. They may therefore be used during actual parsing, or @@ -400,6 +401,9 @@ add_stmt (tree t) if (code == LABEL_EXPR || code == CASE_LABEL_EXPR) STATEMENT_LIST_HAS_LABEL (cur_stmt_list) = 1; + if (vis_parser) + vis_parser->check_stmt (t); + /* Add T to the statement-tree. Non-side-effect statements need to be recorded during statement expressions. */ gcc_checking_assert (!stmt_list_stack->is_empty ()); diff --git a/gcc/testsuite/c-c++-common/Wmisleading-indentation-1.c b/gcc/testsuite/c-c++-common/Wmisleading-indentation-1.c new file mode 100644 index 0000000..dc0deb1 --- /dev/null +++ b/gcc/testsuite/c-c++-common/Wmisleading-indentation-1.c @@ -0,0 +1,12 @@ +/* { dg-options "-Wmisleading-indentation" } */ +/* { dg-do compile } */ + +int +foo (int flag) +{ + int x = 4, y = 5; + if (flag) /* { dg-message "3: ...this 'if' clause, but it is not" } */ + x = 3; + y = 2; /* { dg-warning "statement is indented as if it were guarded by..." } */ + return x * y; +} diff --git a/gcc/testsuite/c-c++-common/Wmisleading-indentation-10.c b/gcc/testsuite/c-c++-common/Wmisleading-indentation-10.c new file mode 100644 index 0000000..8417e02 --- /dev/null +++ b/gcc/testsuite/c-c++-common/Wmisleading-indentation-10.c @@ -0,0 +1,15 @@ +/* { dg-options "-Wmisleading-indentation" } */ +/* { dg-do compile } */ +extern void bar (int); + +void foo (int flag) +{ + if (flag) /* { dg-message "3: ...this 'if' clause, but it is not" } */ + if (flag / 2) + { + bar (0); + bar (1); + } + bar (2); /* { dg-warning "statement is indented as if it were guarded by..." } */ + bar (3); +} diff --git a/gcc/testsuite/c-c++-common/Wmisleading-indentation-11.c b/gcc/testsuite/c-c++-common/Wmisleading-indentation-11.c new file mode 100644 index 0000000..dfcefe2 --- /dev/null +++ b/gcc/testsuite/c-c++-common/Wmisleading-indentation-11.c @@ -0,0 +1,12 @@ +/* { dg-options "-Wmisleading-indentation" } */ +extern void foo (void); +extern void bar (void); + +int test (int flagA, int flagB, int flagC) +{ + if (flagA) + if (flagB) + if (flagC) /* { dg-message "7: ...this 'if' clause, but it is not" } */ + foo (); + bar (); /* { dg-warning "statement is indented as if it were guarded by..." } */ +} diff --git a/gcc/testsuite/c-c++-common/Wmisleading-indentation-12.c b/gcc/testsuite/c-c++-common/Wmisleading-indentation-12.c new file mode 100644 index 0000000..5c01d3e --- /dev/null +++ b/gcc/testsuite/c-c++-common/Wmisleading-indentation-12.c @@ -0,0 +1,12 @@ +/* { dg-options "-Wmisleading-indentation" } */ +extern void foo (void); +extern void bar (void); + +int test (int flagA, int flagB, int flagC) +{ + if (flagA) + if (flagB) /* { dg-message "5: ...this 'if' clause, but it is not" } */ + if (flagC) + foo (); + bar (); /* { dg-warning "statement is indented as if it were guarded by..." } */ +} diff --git a/gcc/testsuite/c-c++-common/Wmisleading-indentation-13.c b/gcc/testsuite/c-c++-common/Wmisleading-indentation-13.c new file mode 100644 index 0000000..198395f --- /dev/null +++ b/gcc/testsuite/c-c++-common/Wmisleading-indentation-13.c @@ -0,0 +1,12 @@ +/* { dg-options "-Wmisleading-indentation" } */ +extern void foo (void); +extern void bar (void); + +int test (int flagA, int flagB, int flagC) +{ + if (flagA) /* { dg-message "3: ...this 'if' clause, but it is not" } */ + if (flagB) + if (flagC) + foo (); + bar (); /* { dg-warning "statement is indented as if it were guarded by..." } */ +} diff --git a/gcc/testsuite/c-c++-common/Wmisleading-indentation-14.c b/gcc/testsuite/c-c++-common/Wmisleading-indentation-14.c new file mode 100644 index 0000000..87a9040 --- /dev/null +++ b/gcc/testsuite/c-c++-common/Wmisleading-indentation-14.c @@ -0,0 +1,14 @@ +/* { dg-options "-Wmisleading-indentation" } */ +extern void foo (void); +extern void bar (void); + +#define FOR_EACH(VAR, START, STOP) \ + for ((VAR) = (START); (VAR) < (STOP); (VAR++)) /* { dg-message "3: ...this 'for' clause, but it is not" } */ + +int test (void) +{ + int i; + FOR_EACH (i, 0, 10) /* { dg-message "3: in expansion of macro" } */ + foo (); + bar (); /* { dg-warning "statement is indented as if it were guarded by..." } */ +} diff --git a/gcc/testsuite/c-c++-common/Wmisleading-indentation-15.c b/gcc/testsuite/c-c++-common/Wmisleading-indentation-15.c new file mode 100644 index 0000000..d8e2815 --- /dev/null +++ b/gcc/testsuite/c-c++-common/Wmisleading-indentation-15.c @@ -0,0 +1,13 @@ +/* { dg-options "-Wmisleading-indentation" } */ +extern void foo (void); +extern void bar (void); + +#define FOR_EACH(VAR, START, STOP) for ((VAR) = (START); (VAR) < (STOP); (VAR++)) /* { dg-message "36: ...this 'for' clause, but it is not" } */ + +int test (void) +{ + int i; + FOR_EACH (i, 0, 10) /* { dg-message "3: in expansion of macro" } */ + foo (); + bar (); /* { dg-warning "statement is indented as if it were guarded by..." } */ +} diff --git a/gcc/testsuite/c-c++-common/Wmisleading-indentation-16-tabs.c b/gcc/testsuite/c-c++-common/Wmisleading-indentation-16-tabs.c new file mode 100644 index 0000000..f224f9e --- /dev/null +++ b/gcc/testsuite/c-c++-common/Wmisleading-indentation-16-tabs.c @@ -0,0 +1,16 @@ +/* { dg-options "-Wmisleading-indentation" } */ +extern void foo (void); +extern void bar (void); + +extern int flagA; +extern int flagB; + +int test (void) +{ + int i; + for (i = 0; i < 10; i++) + while (flagA) + if (flagB) /* { dg-message "7: ...this 'if' clause, but it is not" } */ + foo (); + bar (); /* { dg-warning "statement is indented as if it were guarded by..." } */ +} diff --git a/gcc/testsuite/c-c++-common/Wmisleading-indentation-16.c b/gcc/testsuite/c-c++-common/Wmisleading-indentation-16.c new file mode 100644 index 0000000..e8e63ca --- /dev/null +++ b/gcc/testsuite/c-c++-common/Wmisleading-indentation-16.c @@ -0,0 +1,16 @@ +/* { dg-options "-Wmisleading-indentation" } */ +extern void foo (void); +extern void bar (void); + +extern int flagA; +extern int flagB; + +int test (void) +{ + int i; + for (i = 0; i < 10; i++) + while (flagA) + if (flagB) /* { dg-message "7: ...this 'if' clause, but it is not" } */ + foo (); + bar (); /* { dg-warning "statement is indented as if it were guarded by..." } */ +} diff --git a/gcc/testsuite/c-c++-common/Wmisleading-indentation-17-tabs.c b/gcc/testsuite/c-c++-common/Wmisleading-indentation-17-tabs.c new file mode 100644 index 0000000..db25945f --- /dev/null +++ b/gcc/testsuite/c-c++-common/Wmisleading-indentation-17-tabs.c @@ -0,0 +1,16 @@ +/* { dg-options "-Wmisleading-indentation" } */ +extern void foo (void); +extern void bar (void); + +extern int flagA; +extern int flagB; + +int test (void) +{ + int i; + for (i = 0; i < 10; i++) /* { dg-message "3: ...this 'for' clause, but it is not" } */ + while (flagA) + if (flagB) + foo (); + bar (); /* { dg-warning "statement is indented as if it were guarded by..." } */ +} diff --git a/gcc/testsuite/c-c++-common/Wmisleading-indentation-17.c b/gcc/testsuite/c-c++-common/Wmisleading-indentation-17.c new file mode 100644 index 0000000..61c3890 --- /dev/null +++ b/gcc/testsuite/c-c++-common/Wmisleading-indentation-17.c @@ -0,0 +1,16 @@ +/* { dg-options "-Wmisleading-indentation" } */ +extern void foo (void); +extern void bar (void); + +extern int flagA; +extern int flagB; + +int test (void) +{ + int i; + for (i = 0; i < 10; i++) /* { dg-message "3: ...this 'for' clause, but it is not" } */ + while (flagA) + if (flagB) + foo (); + bar (); /* { dg-warning "statement is indented as if it were guarded by..." } */ +} diff --git a/gcc/testsuite/c-c++-common/Wmisleading-indentation-18-tabs.c b/gcc/testsuite/c-c++-common/Wmisleading-indentation-18-tabs.c new file mode 100644 index 0000000..12d9443 --- /dev/null +++ b/gcc/testsuite/c-c++-common/Wmisleading-indentation-18-tabs.c @@ -0,0 +1,16 @@ +/* { dg-options "-Wmisleading-indentation" } */ +extern void foo (void); +extern void bar (void); + +extern int flagA; +extern int flagB; + +int test (void) +{ + int i; + for (i = 0; i < 10; i++) + while (flagA) /* { dg-message "5: ...this 'while' clause, but it is not" } */ + if (flagB) + foo (); + bar (); /* { dg-warning "statement is indented as if it were guarded by..." } */ +} diff --git a/gcc/testsuite/c-c++-common/Wmisleading-indentation-18.c b/gcc/testsuite/c-c++-common/Wmisleading-indentation-18.c new file mode 100644 index 0000000..b42dbd6 --- /dev/null +++ b/gcc/testsuite/c-c++-common/Wmisleading-indentation-18.c @@ -0,0 +1,16 @@ +/* { dg-options "-Wmisleading-indentation" } */ +extern void foo (void); +extern void bar (void); + +extern int flagA; +extern int flagB; + +int test (void) +{ + int i; + for (i = 0; i < 10; i++) + while (flagA) /* { dg-message "5: ...this 'while' clause, but it is not" } */ + if (flagB) + foo (); + bar (); /* { dg-warning "statement is indented as if it were guarded by..." } */ +} diff --git a/gcc/testsuite/c-c++-common/Wmisleading-indentation-2.c b/gcc/testsuite/c-c++-common/Wmisleading-indentation-2.c new file mode 100644 index 0000000..4aeb4e6 --- /dev/null +++ b/gcc/testsuite/c-c++-common/Wmisleading-indentation-2.c @@ -0,0 +1,11 @@ +/* { dg-options "-Wmisleading-indentation" } */ +/* { dg-do compile } */ + +int +foo (int flag, int x, int y) +{ + if (flag) /* { dg-message "3: ...this 'if' clause, but it is not" } */ + x++; y++; /* { dg-warning "statement is indented as if it were guarded by..." } */ + + return x * y; +} diff --git a/gcc/testsuite/c-c++-common/Wmisleading-indentation-3.c b/gcc/testsuite/c-c++-common/Wmisleading-indentation-3.c new file mode 100644 index 0000000..e37080d --- /dev/null +++ b/gcc/testsuite/c-c++-common/Wmisleading-indentation-3.c @@ -0,0 +1,14 @@ +/* { dg-options "-Wmisleading-indentation" } */ +/* { dg-do compile } */ + +int +foo (int flag) +{ + int x = 4, y = 5; + if (flag) + x = 3; + else /* { dg-message "3: ...this 'else' clause, but it is not" } */ + x = 2; + y = 2; /* { dg-warning "statement is indented as if it were guarded by..." } */ + return x * y; +} diff --git a/gcc/testsuite/c-c++-common/Wmisleading-indentation-4.c b/gcc/testsuite/c-c++-common/Wmisleading-indentation-4.c new file mode 100644 index 0000000..0c72782 --- /dev/null +++ b/gcc/testsuite/c-c++-common/Wmisleading-indentation-4.c @@ -0,0 +1,11 @@ +/* { dg-options "-Wmisleading-indentation" } */ +/* { dg-do compile } */ + +void +foo (double *a, double *b, double *c) +{ + int i = 0; + while (i < 10) /* { dg-message "3: ...this 'while' clause, but it is not" } */ + a[i] = b[i] * c[i]; + i++; /* { dg-warning "statement is indented as if it were guarded by..." } */ +} diff --git a/gcc/testsuite/c-c++-common/Wmisleading-indentation-5.c b/gcc/testsuite/c-c++-common/Wmisleading-indentation-5.c new file mode 100644 index 0000000..7537e8f --- /dev/null +++ b/gcc/testsuite/c-c++-common/Wmisleading-indentation-5.c @@ -0,0 +1,11 @@ +/* { dg-options "-Wmisleading-indentation" } */ +/* { dg-do compile } */ + +void +foo (double *a, double *b, double *sum, double *prod) +{ + int i = 0; + for (i = 0; i < 10; i++) /* { dg-output "3: ...this 'for' clause, but it is not" } */ + sum[i] = a[i] * b[i]; + prod[i] = a[i] * b[i]; /* { dg-warning "statement is indented as if it were guarded by..." } */ +} diff --git a/gcc/testsuite/c-c++-common/Wmisleading-indentation-6.c b/gcc/testsuite/c-c++-common/Wmisleading-indentation-6.c new file mode 100644 index 0000000..fc19537 --- /dev/null +++ b/gcc/testsuite/c-c++-common/Wmisleading-indentation-6.c @@ -0,0 +1,22 @@ +/* Based on CVE-2014-1266 aka "goto fail" */ +/* { dg-options "-Wmisleading-indentation" } */ +extern int foo (int); + +static int +goto_fail(int a, int b, int c) +{ + int err; + + /* ... */ + if ((err = foo (a)) != 0) + goto fail; + if ((err = foo (b)) != 0) /* { dg-message "2: ...this 'if' clause, but it is not" } */ + goto fail; + goto fail; /* { dg-warning "statement is indented as if it were guarded by..." } */ + if ((err = foo (c)) != 0) + goto fail; + /* ... */ + +fail: + return err; +} diff --git a/gcc/testsuite/c-c++-common/Wmisleading-indentation-7.c b/gcc/testsuite/c-c++-common/Wmisleading-indentation-7.c new file mode 100644 index 0000000..500884a --- /dev/null +++ b/gcc/testsuite/c-c++-common/Wmisleading-indentation-7.c @@ -0,0 +1,15 @@ +/* { dg-options "-Wmisleading-indentation" } */ + +extern int bar (int, int); + +int foo (int p, int q, int r, int s, int t) +{ + if (bar (p, q)) + { + if (p) /* { dg-message "7: ...this 'if' clause, but it is not" } */ + q++; r++; /* { dg-warning "statement is indented as if it were guarded by..." } */ + s++; /* { dg-warning "statement is indented as if it were guarded by..." } */ + t++; + } + return p + q + r + s + t; +} diff --git a/gcc/testsuite/c-c++-common/Wmisleading-indentation-8.c b/gcc/testsuite/c-c++-common/Wmisleading-indentation-8.c new file mode 100644 index 0000000..82c1e6b --- /dev/null +++ b/gcc/testsuite/c-c++-common/Wmisleading-indentation-8.c @@ -0,0 +1,6 @@ +/* { dg-options "-Wmisleading-indentation" } */ +int foo (int a, int b, int c) +{ + /* This should *not* be flagged as misleading indentation. */ + if (a) return b; else return c; +} diff --git a/gcc/testsuite/c-c++-common/Wmisleading-indentation-9.c b/gcc/testsuite/c-c++-common/Wmisleading-indentation-9.c new file mode 100644 index 0000000..3fcba34 --- /dev/null +++ b/gcc/testsuite/c-c++-common/Wmisleading-indentation-9.c @@ -0,0 +1,10 @@ +/* { dg-options "-Wmisleading-indentation" } */ +/* { dg-do compile } */ +extern void bar (int); + +void foo (int flag) +{ + if (flag) /* { dg-message "3: ...this 'if' clause, but it is not" } */ + bar (0); + bar (1); /* { dg-warning "statement is indented as if it were guarded by..." } */ +}