@@ -73,6 +73,42 @@ get_visual_column (expanded_location exploc,
return true;
}
+/* Determine if the given source line of length LINE_LEN is entirely blank,
+ or contains one or more non-whitespace characters. */
+
+static bool
+line_is_blank_p (const char *line, int line_len)
+{
+ for (int i = 0; i < line_len; i++)
+ if (!ISSPACE (line[i]))
+ return false;
+
+ return true;
+}
+
+/* Helper function for should_warn_for_misleading_indentation.
+ Determines if there are one or more blank lines between the
+ given source lines. */
+
+static bool
+separated_by_blank_lines_p (const char *file,
+ int start_line, int end_line)
+{
+ gcc_assert (start_line < end_line);
+ for (int line_num = start_line; line_num < end_line; line_num++)
+ {
+ int line_len;
+ const char *line = location_get_source_line (file, line_num, &line_len);
+ if (!line)
+ return false;
+
+ if (line_is_blank_p (line, line_len))
+ return true;
+ }
+
+ return false;
+}
+
/* 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.
@@ -166,10 +202,17 @@ detect_preprocessor_logic (expanded_location body_exploc,
description of that function below. */
static bool
-should_warn_for_misleading_indentation (const token_indent_info &guard_tinfo,
+should_warn_for_misleading_indentation (int strictness_level,
+ const token_indent_info &guard_tinfo,
const token_indent_info &body_tinfo,
const token_indent_info &next_tinfo)
{
+ /* Early reject for the case where -Wmisleading-indentation is disabled,
+ to avoid doing work only to have the warning suppressed inside the
+ diagnostic machinery. */
+ if (!strictness_level)
+ return false;
+
location_t guard_loc = guard_tinfo.location;
location_t body_loc = body_tinfo.location;
location_t next_stmt_loc = next_tinfo.location;
@@ -329,6 +372,15 @@ should_warn_for_misleading_indentation (const token_indent_info &guard_tinfo,
;
foo ();
^ DON'T WARN HERE
+
+ Cases where we may want to issue a warning:
+
+ if (flag)
+ foo ();
+
+ bar ();
+ ^ blank line between guarded and unguarded code
+ Warn here at level 2, but not at level 1.
*/
if (next_stmt_exploc.line > body_exploc.line)
{
@@ -354,6 +406,23 @@ should_warn_for_misleading_indentation (const token_indent_info &guard_tinfo,
&guard_line_first_nws))
return false;
+ /* At level 1, don't warn if the guarded and unguarded code are
+ separated by one or more entirely blank lines, e.g.:
+ switch (arg)
+ {
+ case 0:
+ if (flagA)
+ foo (0);
+
+ break;
+ ^ DON'T WARN HERE
+ }
+ since this is arguably not misleading. */
+ if (strictness_level < 2)
+ if (separated_by_blank_lines_p (body_exploc.file, body_exploc.line,
+ next_stmt_exploc.line))
+ return false;
+
if ((body_type != CPP_SEMICOLON
&& next_stmt_vis_column == body_vis_column)
/* As a special case handle the case where the body is a semicolon
@@ -522,17 +591,12 @@ warn_for_misleading_indentation (const token_indent_info &guard_tinfo,
const token_indent_info &body_tinfo,
const token_indent_info &next_tinfo)
{
- /* Early reject for the case where -Wmisleading-indentation is disabled,
- to avoid doing work only to have the warning suppressed inside the
- diagnostic machinery. */
- if (!warn_misleading_indentation)
- return;
-
- if (should_warn_for_misleading_indentation (guard_tinfo,
+ if (should_warn_for_misleading_indentation (warn_misleading_indentation,
+ guard_tinfo,
body_tinfo,
next_tinfo))
{
- if (warning_at (next_tinfo.location, OPT_Wmisleading_indentation,
+ if (warning_at (next_tinfo.location, OPT_Wmisleading_indentation_,
"statement is indented as if it were guarded by..."))
inform (guard_tinfo.location,
"...this %qs clause, but it is not",
@@ -562,7 +562,11 @@ C ObjC C++ ObjC++ Var(warn_memset_transposed_args) Warning LangEnabledBy(C ObjC
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
+C C++ Common Warning Alias(Wmisleading-indentation=, 1, 0)
+Warn when the indentation of the code does not reflect the block structure.
+
+Wmisleading-indentation=
+C C++ Common Joined RejectNegative UInteger Var(warn_misleading_indentation) Warning LangEnabledBy(C C++,Wall, 1, 0)
Warn when the indentation of the code does not reflect the block structure.
Wmissing-braces
@@ -264,7 +264,7 @@ Objective-C and Objective-C++ Dialects}.
-Winvalid-pch -Wlarger-than=@var{len} @gol
-Wlogical-op -Wlogical-not-parentheses -Wlong-long @gol
-Wmain -Wmaybe-uninitialized -Wmemset-transposed-args @gol
--Wmisleading-indentation -Wmissing-braces @gol
+-Wmisleading-indentation -Wmisleading-indentation=@var{n} -Wmissing-braces @gol
-Wmissing-field-initializers -Wmissing-include-dirs @gol
-Wno-multichar -Wnonnull -Wnormalized=@r{[}none@r{|}id@r{|}nfc@r{|}nfkc@r{]} @gol
-Wnull-dereference -Wodr -Wno-overflow -Wopenmp-simd @gol
@@ -3551,6 +3551,7 @@ Options} and @ref{Objective-C and Objective-C++ Dialect Options}.
-Wformat @gol
-Wmain @r{(only for C/ObjC and unless} @option{-ffreestanding}@r{)} @gol
-Wmaybe-uninitialized @gol
+-Wmisleading-indentation=1 @r{(only for C/C++)} @gol
-Wmissing-braces @r{(only for C/ObjC)} @gol
-Wnonnull @gol
-Wopenmp-simd @gol
@@ -3889,6 +3890,7 @@ is enabled by default in C++ and is enabled by either @option{-Wall}
or @option{-Wpedantic}.
@item -Wmisleading-indentation @r{(C and C++ only)}
+@itemx -Wmisleading-indentation=@var{n}
@opindex Wmisleading-indentation
@opindex Wno-misleading-indentation
Warn when the indentation of the code does not reflect the block structure.
@@ -3896,7 +3898,12 @@ Specifically, a warning is issued for @code{if}, @code{else}, @code{while}, and
@code{for} clauses with a guarded statement that does not use braces,
followed by an unguarded statement with the same indentation.
-This warning is disabled by default.
+This warning is disabled by default. The warning can optionally accept a
+level (either 1 or 2), for specifying increasing levels of strictness;
+@option{-Wmisleading-indentation} (with no level) is equivalent to
+@option{-Wmisleading-indentation=1}.
+
+@option{-Wmisleading-indentation=1} is enabled by @option{-Wall} in C and C++.
In the following example, the call to ``bar'' is misleadingly indented as
if it were guarded by the ``if'' conditional.
@@ -3907,6 +3914,26 @@ if it were guarded by the ``if'' conditional.
bar (); /* Gotcha: this is not guarded by the "if". */
@end smallexample
+A warning will be issued for this at @option{-Wmisleading-indentation=1}
+and above.
+
+If there is a blank line between the guarded code and the unguarded code,
+such as in the following:
+
+@smallexample
+ @{
+ foo (0);
+
+ if (some_condition) /* these two lines are not indented enough. */
+ foo (1);
+
+ foo (2); /* this lines up with "foo (1);" but is not guarded by the "if". */
+ @}
+@end smallexample
+
+then a warning will be issued at @option{-Wmisleading-indentation=2},
+but not at @option{-Wmisleading-indentation=1}.
+
In the case of mixed tabs and spaces, the warning uses the
@option{-ftabstop=} option to determine if the statements line up
(defaulting to 8).
new file mode 100644
@@ -0,0 +1,30 @@
+/* { dg-options "-Wall" } */
+/* { dg-do compile } */
+
+/* Verify that -Wmisleading-indentation is enabled by -Wall. */
+
+int
+fn_1 (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;
+}
+
+/* Ensure that we can disable the warning. */
+
+int
+fn_32 (int flag)
+{
+ int x = 4, y = 5;
+#pragma GCC diagnostic push
+#pragma GCC diagnostic ignored "-Wmisleading-indentation"
+ if (flag)
+ x = 3;
+ y = 2;
+#pragma GCC diagnostic pop
+
+ return x * y;
+}
new file mode 100644
@@ -0,0 +1,35 @@
+/* { dg-options "-Wmisleading-indentation=1" } */
+/* { dg-do compile } */
+
+extern int foo (int);
+extern int flagA;
+
+/* At -Wmisleading-indentation=1 we shouldn't emit warnings for this
+ function. Compare with
+ fn_40_implicit_level_1 in Wmisleading-indentation.c and
+ fn_40_level_2 in Wmisleading-indentation-level-2.c. */
+
+void
+fn_40_level_1 (int arg)
+{
+if (flagA)
+ foo (0);
+
+ foo (1);
+
+
+ if (flagA)
+ foo (0);
+
+ foo (1);
+
+
+ switch (arg)
+ {
+ case 0:
+ if (flagA)
+ foo (0);
+
+ break;
+ }
+}
new file mode 100644
@@ -0,0 +1,34 @@
+/* { dg-options "-Wmisleading-indentation=2" } */
+/* { dg-do compile } */
+
+extern int foo (int);
+extern int flagA;
+
+/* Compare with fn_40_implicit_level_1 in Wmisleading-indentation.c and
+ fn_40_level_1 in Wmisleading-indentation-level-1.c.
+ Verify that we emit warnings at level 2 for this function. */
+
+void
+fn_40_level_2 (int arg)
+{
+if (flagA) /* { dg-message "1: ...this 'if' clause" } */
+ foo (0);
+
+ foo (1); /* { dg-warning "statement is indented as if" } */
+
+
+ if (flagA) /* { dg-message "3: ...this 'if' clause" } */
+ foo (0);
+
+ foo (1); /* { dg-warning "statement is indented as if" } */
+
+
+ switch (arg)
+ {
+ case 0:
+ if (flagA) /* { dg-message "6: ...this 'if' clause" } */
+ foo (0);
+
+ break; /* { dg-warning "statement is indented as if" } */
+ }
+}
@@ -891,3 +891,40 @@ fn_39 (void)
i++);
foo (i);
}
+
+/* The following function contains examples of bad indentation that's
+ arguably not misleading, due to a blank line between the guarded and the
+ non-guarded code. Some of the blank lines deliberately contain
+ redundant whitespace, to verify that this is handled.
+ Based on examples seen in gcc/fortran/io.c, gcc/function.c, and
+ gcc/regrename.c.
+
+ At -Wmisleading-indentation (implying level 1) we shouldn't emit
+ warnings for this function. Compare with
+ fn_40_level_1 in Wmisleading-indentation-level-1.c and
+ fn_40_level_2 in Wmisleading-indentation-level-2.c. */
+
+void
+fn_40_implicit_level_1 (int arg)
+{
+if (flagA)
+ foo (0);
+
+ foo (1);
+
+
+ if (flagA)
+ foo (0);
+
+ foo (1);
+
+
+ switch (arg)
+ {
+ case 0:
+ if (flagA)
+ foo (0);
+
+ break;
+ }
+}