diff --git a/gcc/ChangeLog b/gcc/ChangeLog
index 4d67a4d9153087a857b01d2bee2df158fb47d2f8..c23794a1558f55a265c648cae477b488c49f49ad 100644
--- a/gcc/ChangeLog
+++ b/gcc/ChangeLog
@@ -1,3 +1,9 @@
+2015-05-12  David Malcolm  <dmalcolm@redhat.com>
+
+	* doc/invoke.texi (Warning Options): Add -Wmisleading-indentation.
+	(-Wmisleading-indentation): New option.
+	* Makefile.in (C_COMMON_OBJS): Add c-family/c-indentation.o.
+
 2015-05-12  Uros Bizjak  <ubizjak@gmail.com>
 
 	* config/alpha/alpha.h (TARGET_SUPPORTS_WIDE_INT): New define.
diff --git a/gcc/Makefile.in b/gcc/Makefile.in
index 652b3e71d39a0e31904f85d24dbbbce3db3ee8e7..fe22236cc0d21d89196e1f1ffa2d7189f601cbe5 100644
--- a/gcc/Makefile.in
+++ b/gcc/Makefile.in
@@ -1145,8 +1145,8 @@ c-family-warn = $(STRICT_WARN)
 
 # Language-specific object files shared by all C-family front ends.
 C_COMMON_OBJS = c-family/c-common.o c-family/c-cppbuiltin.o c-family/c-dump.o \
-  c-family/c-format.o c-family/c-gimplify.o c-family/c-lex.o \
-  c-family/c-omp.o c-family/c-opts.o c-family/c-pch.o \
+  c-family/c-format.o c-family/c-gimplify.o c-family/c-indentation.o \
+  c-family/c-lex.o c-family/c-omp.o c-family/c-opts.o c-family/c-pch.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 \
diff --git a/gcc/c-family/ChangeLog b/gcc/c-family/ChangeLog
index 8a19bc119b27300cda5eacf6a54c3621215e6a57..52b4d5cb7a40b824671fff8504a7e701f635df5b 100644
--- a/gcc/c-family/ChangeLog
+++ b/gcc/c-family/ChangeLog
@@ -1,3 +1,9 @@
+2015-05-12  David Malcolm  <dmalcolm@redhat.com>
+
+	* c-common.h (warn_for_misleading_indentation): New prototype.
+	* c-indentation.c: New file.
+	* c.opt (Wmisleading-indentation): New option.
+
 2015-05-12  Tom de Vries  <tom@codesourcery.com>
 
 	PR tree-optimization/66010
diff --git a/gcc/c-family/c-common.h b/gcc/c-family/c-common.h
index 5c1fa7b98687f6e39f7516d72460698a0d593620..444d80d3fed61fcb1320dc89baa941c15574e9a1 100644
--- a/gcc/c-family/c-common.h
+++ b/gcc/c-family/c-common.h
@@ -1429,4 +1429,12 @@ extern bool contains_cilk_spawn_stmt (tree);
 extern tree cilk_for_number_of_iterations (tree);
 extern bool check_no_cilk (tree, const char *, const char *,
 		           location_t loc = UNKNOWN_LOCATION);
+/* In c-indentation.c.  */
+extern void
+warn_for_misleading_indentation (location_t guard_loc,
+				 location_t body_loc,
+				 location_t next_stmt_loc,
+				 enum cpp_ttype next_tok_type,
+				 const char *guard_kind);
+
 #endif /* ! GCC_C_COMMON_H */
diff --git a/gcc/c-family/c-indentation.c b/gcc/c-family/c-indentation.c
new file mode 100644
index 0000000000000000000000000000000000000000..94565f6daa24ad019cb24782a3fcdbe13146c27f
--- /dev/null
+++ b/gcc/c-family/c-indentation.c
@@ -0,0 +1,384 @@
+/* Implementation of -Wmisleading-indentation
+   Copyright (C) 2015 Free Software Foundation, Inc.
+
+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"
+#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 "stor-layout.h"
+#include "input.h"
+#include "c-common.h"
+
+extern cpp_options *cpp_opts;
+
+/* 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.
+   Returns true if a conversion was possible, writing the result to OUT,
+   otherwise returns false.  */
+
+static bool
+get_visual_column (expanded_location exploc, unsigned int *out)
+{
+  int line_len;
+  const char *line = location_get_source_line (exploc, &line_len);
+  if (!line)
+    return false;
+  unsigned int vis_column = 0;
+  for (int i = 1; i < exploc.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++;
+    }
+
+  *out = vis_column;
+  return true;
+}
+
+/* Is the token at LOC the first non-whitespace on its line?
+   Helper function for should_warn_for_misleading_indentation.  */
+
+static bool
+is_first_nonwhitespace_on_line (expanded_location exploc)
+{
+  int line_len;
+  const char *line = location_get_source_line (exploc, &line_len);
+
+   /* If we can't determine it, return false so that we don't issue a
+      warning.  This is sometimes the case for input files
+      containing #line directives, and these are often for autogenerated
+      sources (e.g. from .md files), where it's not clear that it's
+      meaningful to look at indentation.  */
+  if (!line)
+    return false;
+
+  for (int i = 1; i < exploc.column; i++)
+    {
+      unsigned char ch = line[i - 1];
+      if (!ISSPACE (ch))
+	return false;
+    }
+  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.  */
+
+static bool
+line_contains_hash_if (const char *file, int line_num)
+{
+  expanded_location exploc;
+  exploc.file = file;
+  exploc.line = line_num;
+  exploc.column = 1;
+
+  int line_len;
+  const char *line = location_get_source_line (exploc, &line_len);
+  if (!line)
+    return false;
+
+  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++;
+
+  /* Skip whitespace.  */
+  while (idx < line_len)
+    {
+      if (!ISSPACE (line[idx]))
+	break;
+      idx++;
+    }
+
+  /* Match #if/#ifdef/#ifndef.  */
+  if (idx + 2 <= line_len)
+    if (line[idx] == 'i')
+      if (line[idx + 1] == 'f')
+	return true;
+
+  return false;
+}
+
+
+/* Determine if there is preprocessor logic between
+   BODY_EXPLOC and NEXT_STMT_EXPLOC, to ensure that we don't
+   issue a warning for cases like this:
+
+	if (flagA)
+	  foo ();
+	  ^ BODY_EXPLOC
+      #if SOME_CONDITION_THAT_DOES_NOT_HOLD
+	if (flagB)
+      #endif
+	  bar ();
+	  ^ NEXT_STMT_EXPLOC
+
+   despite "bar ();" being visually aligned below "foo ();" and
+   being (as far as the parser sees) the next token.
+
+   Return true if such logic is detected.  */
+
+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);
+
+  if (next_stmt_exploc.line - body_exploc.line < 4)
+    return false;
+
+  /* Is there a #if/#ifdef/#ifndef directive somewhere in the lines
+     between the given locations?
+
+     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;
+
+  /* Not found.  */
+  return false;
+}
+
+
+/* Helper function for warn_for_misleading_indentation; see
+   description of that function below.  */
+
+static bool
+should_warn_for_misleading_indentation (location_t guard_loc,
+					location_t body_loc,
+					location_t next_stmt_loc,
+					enum cpp_ttype next_tok_type)
+{
+  /* Don't attempt to compare the indentation of BODY_LOC and NEXT_STMT_LOC
+     if either are within macros.  */
+  if (linemap_location_from_macro_expansion_p (line_table, body_loc)
+      || linemap_location_from_macro_expansion_p (line_table, next_stmt_loc))
+    return false;
+
+  /* Don't attempt to compare indentation if #line or # 44 "file"-style
+     directives are present, suggesting generated code.
+
+     All bets are off if these are present: the file that the #line
+     directive could have an entirely different coding layout to C/C++
+     (e.g. .md files).
+
+     To determine if a #line is present, in theory we could look for a
+     map with reason == LC_RENAME_VERBATIM.  However, if there has
+     subsequently been a long line requiring a column number larger than
+     that representable by the original LC_RENAME_VERBATIM map, then
+     we'll have a map with reason LC_RENAME.
+     Rather than attempting to search all of the maps for a
+     LC_RENAME_VERBATIM, instead we have libcpp set a flag whenever one
+     is seen, and we check for the flag here.
+  */
+  if (line_table->seen_line_directive)
+    return false;
+
+  if (next_tok_type == CPP_CLOSE_BRACE)
+    return false;
+
+  /* Don't warn here about spurious semicolons.  */
+  if (next_tok_type == CPP_SEMICOLON)
+    return false;
+
+  expanded_location body_exploc
+    = expand_location_to_spelling_point (body_loc);
+  expanded_location next_stmt_exploc
+    = expand_location_to_spelling_point (next_stmt_loc);
+
+  /* They must be in the same file.  */
+  if (next_stmt_exploc.file != body_exploc.file)
+    return false;
+
+  /* If NEXT_STMT_LOC and BODY_LOC are on the same line, consider
+     the location of the guard.
+
+     Cases where we want to issue a warning:
+
+       if (flag)
+         foo ();  bar ();
+                  ^ WARN HERE
+
+       if (flag) foo (); bar ();
+                         ^ WARN HERE
+
+     Cases where we don't want to issue a warning:
+
+       various_code (); if (flag) foo (); bar (); more_code ();
+                                          ^ DON'T WARN HERE.  */
+  if (next_stmt_exploc.line == body_exploc.line)
+    {
+      expanded_location guard_exploc
+	= expand_location_to_spelling_point (guard_loc);
+      if (guard_exploc.file != body_exploc.file)
+	return true;
+      if (guard_exploc.line < body_exploc.line)
+	/* The guard is on a line before a line that contains both
+	   the body and the next stmt.  */
+	return true;
+      else if (guard_exploc.line == body_exploc.line)
+	{
+	  /* They're all on the same line.  */
+	  gcc_assert (guard_exploc.file == next_stmt_exploc.file);
+	  gcc_assert (guard_exploc.line == next_stmt_exploc.line);
+	  /* Heuristic: only warn if the guard is the first thing
+	     on its line.  */
+	  if (is_first_nonwhitespace_on_line (guard_exploc))
+	    return true;
+	}
+    }
+
+  /* If NEXT_STMT_LOC is on a line after BODY_LOC, consider
+     their relative locations, and of the guard.
+
+     Cases where we want to issue a warning:
+        if (flag)
+          foo ();
+          bar ();
+          ^ WARN HERE
+
+     Cases where we don't want to issue a warning:
+        if (flag)
+        foo ();
+        bar ();
+        ^ DON'T WARN HERE (autogenerated code?)
+
+	if (flagA)
+	  foo ();
+      #if SOME_CONDITION_THAT_DOES_NOT_HOLD
+	if (flagB)
+      #endif
+	  bar ();
+	  ^ DON'T WARN HERE
+  */
+  if (next_stmt_exploc.line > body_exploc.line)
+    {
+      /* Determine if GUARD_LOC and NEXT_STMT_LOC are aligned on the same
+	 "visual column"...  */
+      unsigned int next_stmt_vis_column;
+      unsigned int body_vis_column;
+      /* If we can't determine it, don't issue a warning.  This is sometimes
+	 the case for input files containing #line directives, and these
+	 are often for autogenerated sources (e.g. from .md files), where
+	 it's not clear that it's meaningful to look at indentation.  */
+      if (!get_visual_column (next_stmt_exploc, &next_stmt_vis_column))
+	return false;
+      if (!get_visual_column (body_exploc, &body_vis_column))
+	return false;
+      if (next_stmt_vis_column == body_vis_column)
+	{
+	  /* Don't warn if they aren't aligned on the same column
+	     as the guard itself (suggesting autogenerated code that
+	     doesn't bother indenting at all).  */
+	  expanded_location guard_exploc
+	    = expand_location_to_spelling_point (guard_loc);
+	  unsigned int guard_vis_column;
+	  if (!get_visual_column (guard_exploc, &guard_vis_column))
+	    return false;
+	  if (guard_vis_column == body_vis_column)
+	    return false;
+
+	  /* Don't warn if there is multiline preprocessor logic between
+	     the two statements. */
+	  if (detect_preprocessor_logic (body_exploc, next_stmt_exploc))
+	    return false;
+
+	  /* Otherwise, they are visually aligned: issue a warning.  */
+	  return true;
+	}
+    }
+
+  return false;
+}
+
+/* Called by the C/C++ frontends when we have a guarding statement at
+   GUARD_LOC containing a statement at BODY_LOC, where the block wasn't
+   written using braces, like this:
+
+     if (flag)
+       foo ();
+
+   along with the location of the next token, at NEXT_STMT_LOC,
+   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:
+
+     GUARD_LOC
+     |
+     V
+     if (flag)
+       foo (); <- BODY_LOC
+       bar (); <- NEXT_STMT_LOC
+
+   In the above, "bar ();" isn't guarded by the "if", but
+   is indented to misleadingly suggest that it is in the same
+   block as "foo ();".
+
+   GUARD_KIND identifies the kind of clause e.g. "if", "else" etc.  */
+
+void
+warn_for_misleading_indentation (location_t guard_loc,
+				 location_t body_loc,
+				 location_t next_stmt_loc,
+				 enum cpp_ttype next_tok_type,
+				 const char *guard_kind)
+{
+  if (should_warn_for_misleading_indentation (guard_loc,
+					      body_loc,
+					      next_stmt_loc,
+					      next_tok_type))
+    if (warning_at (next_stmt_loc, OPT_Wmisleading_indentation,
+		    "statement is indented as if it were guarded by..."))
+      inform (guard_loc,
+	      "...this %qs clause, but it is not", guard_kind);
+}
diff --git a/gcc/c-family/c.opt b/gcc/c-family/c.opt
index 343a599e3b96d20c2c4b317d3eadeb0b1566ce5a..285952ea5fdfd10e0d574e1a924b6334694f7695 100644
--- a/gcc/c-family/c.opt
+++ b/gcc/c-family/c.opt
@@ -553,6 +553,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/ChangeLog b/gcc/c/ChangeLog
index 3b8f491ff841837c5c20c318b358b1f5d4bd5715..f1c40738b41e7f3f188ff6fcb1c5096b7c2b958d 100644
--- a/gcc/c/ChangeLog
+++ b/gcc/c/ChangeLog
@@ -1,3 +1,12 @@
+2015-05-12  David Malcolm  <dmalcolm@redhat.com>
+
+	* c-parser.c (c_parser_if_body): Add param "if_loc", use it
+	to add a call to warn_for_misleading_indentation.
+	(c_parser_else_body): Likewise, adding param "else_loc".
+	(c_parser_if_statement): Check for misleading indentation.
+	(c_parser_while_statement): Likewise.
+	(c_parser_for_statement): Likewise.
+
 2015-05-08  Marek Polacek  <polacek@redhat.com>
 
 	PR c/64918
diff --git a/gcc/c/c-parser.c b/gcc/c/c-parser.c
index bf0e4c577cc085cc4b3c75ba89b7191554669fdc..36438d0254029751aba76c599b55836f0627ca52 100644
--- a/gcc/c/c-parser.c
+++ b/gcc/c/c-parser.c
@@ -5185,7 +5185,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 +5203,15 @@ 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 (!c_parser_next_token_is_keyword (parser, RID_ELSE))
+	warn_for_misleading_indentation (if_loc, body_loc,
+					 c_parser_peek_token (parser)->location,
+					 c_parser_peek_token (parser)->type,
+					 "if");
+    }
+
   return c_end_compound_stmt (body_loc, block, flag_isoc99);
 }
 
@@ -5212,9 +5220,9 @@ 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_loc)
 {
-  location_t else_loc = c_parser_peek_token (parser)->location;
+  location_t body_loc = c_parser_peek_token (parser)->location;
   tree block = c_begin_compound_stmt (flag_isoc99);
   c_parser_all_labels (parser);
   if (c_parser_next_token_is (parser, CPP_SEMICOLON))
@@ -5227,8 +5235,14 @@ c_parser_else_body (c_parser *parser)
       c_parser_consume_token (parser);
     }
   else
-    c_parser_statement_after_labels (parser);
-  return c_end_compound_stmt (else_loc, block, flag_isoc99);
+    {
+      c_parser_statement_after_labels (parser);
+      warn_for_misleading_indentation (else_loc, body_loc,
+				       c_parser_peek_token (parser)->location,
+				       c_parser_peek_token (parser)->type,
+				       "else");
+    }
+  return c_end_compound_stmt (body_loc, block, flag_isoc99);
 }
 
 /* Parse an if statement (C90 6.6.4, C99 6.8.4).
@@ -5250,6 +5264,7 @@ c_parser_if_statement (c_parser *parser)
   tree if_stmt;
 
   gcc_assert (c_parser_next_token_is_keyword (parser, RID_IF));
+  location_t 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;
@@ -5261,12 +5276,13 @@ c_parser_if_statement (c_parser *parser)
     }
   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_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_loc);
     }
   else
     second_body = NULL_TREE;
@@ -5346,6 +5362,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_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 +5379,16 @@ c_parser_while_statement (c_parser *parser, bool ivdep)
   c_break_label = NULL_TREE;
   save_cont = c_cont_label;
   c_cont_label = NULL_TREE;
+
+  location_t body_loc = UNKNOWN_LOCATION;
+  if (c_parser_peek_token (parser)->type != CPP_OPEN_BRACE)
+    body_loc = c_parser_peek_token (parser)->location;
   body = c_parser_c99_block_statement (parser);
+  warn_for_misleading_indentation (while_loc, body_loc,
+				   c_parser_peek_token (parser)->location,
+				   c_parser_peek_token (parser)->type,
+				   "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;
@@ -5640,7 +5666,16 @@ c_parser_for_statement (c_parser *parser, bool ivdep)
   c_break_label = NULL_TREE;
   save_cont = c_cont_label;
   c_cont_label = NULL_TREE;
+
+  location_t body_loc = UNKNOWN_LOCATION;
+  if (c_parser_peek_token (parser)->type != CPP_OPEN_BRACE)
+    body_loc = c_parser_peek_token (parser)->location;
   body = c_parser_c99_block_statement (parser);
+  warn_for_misleading_indentation (for_loc, body_loc,
+				   c_parser_peek_token (parser)->location,
+				   c_parser_peek_token (parser)->type,
+				   "for");
+
   if (is_foreach_statement)
     objc_finish_foreach_loop (loc, object_expression, collection_expression, body, c_break_label, c_cont_label);
   else
diff --git a/gcc/cp/ChangeLog b/gcc/cp/ChangeLog
index 0bdbf3c4c1cedfe25e3f9ceb5d30169466b0775c..b119f7bc4f2a912c50456e4f8754b2c05232ce36 100644
--- a/gcc/cp/ChangeLog
+++ b/gcc/cp/ChangeLog
@@ -1,3 +1,15 @@
+2015-05-12  David Malcolm  <dmalcolm@redhat.com>
+
+	* parser.c (cp_parser_selection_statement): Add location and
+	guard_kind arguments to calls to
+	cp_parser_implicitly_scoped_statement.
+	(cp_parser_iteration_statement): Likewise for calls to
+	cp_parser_already_scoped_statement.
+	(cp_parser_implicitly_scoped_statement): Add "guard_loc" and
+	"guard_kind" params; use them to warn for misleading
+	indentation.
+	(cp_parser_already_scoped_statement): Likewise.
+
 2015-05-11  Jan Hubicka  <hubicka@ucw.cz>
 
 	* class.c (fixup_type_variants): Do not copy TYPE_METHODS
diff --git a/gcc/cp/parser.c b/gcc/cp/parser.c
index 6f746a1d3624c33dabb9989732fad0d61bef8451..432aa1cab93dc21f80eea9d4cd0ecf99f04b8a59 100644
--- a/gcc/cp/parser.c
+++ b/gcc/cp/parser.c
@@ -2065,9 +2065,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 +10174,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 +10185,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 +10200,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 +10241,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 +10787,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 +10797,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 +10822,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 +10837,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 +10867,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 +11136,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;
 
@@ -11152,9 +11161,18 @@ cp_parser_implicitly_scoped_statement (cp_parser* parser, bool *if_p)
       /* Create a compound-statement.  */
       statement = begin_compound_stmt (0);
       /* Parse the dependent-statement.  */
+      location_t body_loc = cp_lexer_peek_token (parser->lexer)->location;
       cp_parser_statement (parser, NULL_TREE, false, if_p);
       /* Finish the dummy compound-statement.  */
       finish_compound_stmt (statement);
+      cp_token *next_tok = cp_lexer_peek_token (parser->lexer);
+      if (next_tok->keyword != RID_ELSE)
+        {
+          location_t next_stmt_loc = next_tok->location;
+          warn_for_misleading_indentation (guard_loc, body_loc,
+                                           next_stmt_loc, next_tok->type,
+                                           guard_kind);
+        }
     }
 
   /* Return the statement.  */
@@ -11167,11 +11185,20 @@ 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);
+    {
+      location_t body_loc = cp_lexer_peek_token (parser->lexer)->location;
+      cp_parser_statement (parser, NULL_TREE, false, NULL);
+      cp_token *next_tok = cp_lexer_peek_token (parser->lexer);
+      location_t next_stmt_loc = next_tok->location;
+      warn_for_misleading_indentation (guard_loc, body_loc,
+                                       next_stmt_loc, next_tok->type,
+                                       guard_kind);
+    }
   else
     {
       /* Avoid calling cp_parser_compound_statement, so that we
diff --git a/gcc/doc/invoke.texi b/gcc/doc/invoke.texi
index b5721c9f242dc01efe895f49b55e3977809d46b8..117b5d99dfc7ad2c60225c21c4f8d65f726695fc 100644
--- a/gcc/doc/invoke.texi
+++ b/gcc/doc/invoke.texi
@@ -262,7 +262,8 @@ Objective-C and Objective-C++ Dialects}.
 -Wno-int-to-pointer-cast -Wno-invalid-offsetof @gol
 -Winvalid-pch -Wlarger-than=@var{len}  -Wunsafe-loop-optimizations @gol
 -Wlogical-op -Wlogical-not-parentheses -Wlong-long @gol
--Wmain -Wmaybe-uninitialized -Wmemset-transposed-args -Wmissing-braces @gol
+-Wmain -Wmaybe-uninitialized -Wmemset-transposed-args @gol
+-Wmisleading-indentation -Wmissing-braces @gol
 -Wmissing-field-initializers -Wmissing-include-dirs @gol
 -Wno-multichar  -Wnonnull  -Wnormalized=@r{[}none@r{|}id@r{|}nfc@r{|}nfkc@r{]} @gol
 -Wodr  -Wno-overflow  -Wopenmp-simd @gol
@@ -3766,6 +3767,45 @@ arguments, two, or three arguments of appropriate types.  This warning
 is enabled by default in C++ and is enabled by either @option{-Wall}
 or @option{-Wpedantic}.
 
+@item -Wmisleading-indentation @r{(C and C++ only)}
+@opindex Wmisleading-indentation
+@opindex Wno-misleading-indentation
+Warn when the indentation of the code does not reflect the block structure.
+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.
+
+In the following example, the call to ``bar'' is misleadingly indented as
+if it were guarded by the ``if'' conditional.
+
+@smallexample
+  if (some_condition ())
+    foo ();
+    bar ();  /* Gotcha: this is not guarded by the "if".  */
+@end smallexample
+
+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).
+
+The warning is not issued for code involving multiline preprocessor logic
+such as the following example.
+
+@smallexample
+  if (flagA)
+    foo (0);
+#if SOME_CONDITION_THAT_DOES_NOT_HOLD
+  if (flagB)
+#endif
+    foo (1);
+@end smallexample
+
+The warning is not issued after a @code{#line} directive, since this
+typically indicates autogenerated code, and no assumptions can be made
+about the layout of the file that the directive references.
+
 @item -Wmissing-braces
 @opindex Wmissing-braces
 @opindex Wno-missing-braces
diff --git a/gcc/testsuite/ChangeLog b/gcc/testsuite/ChangeLog
index 16c6853dde2a90865203c83101af95a2d2ef88fe..60f7d30482452a62e67d1c98c88ab2f454256774 100644
--- a/gcc/testsuite/ChangeLog
+++ b/gcc/testsuite/ChangeLog
@@ -1,3 +1,9 @@
+2015-05-12  David Malcolm  <dmalcolm@redhat.com>
+
+	* c-c++-common/Wmisleading-indentation.c: New testcase.
+	* c-c++-common/Wmisleading-indentation-2.c: New testcase.
+	* c-c++-common/Wmisleading-indentation-2.md: New file.
+
 2015-05-12 Sandra Loosemore <sandra@codesourcery.com>
 
 	* gcc.target/nios2/nios2-trap-insn.c: Expect "trap" instead of
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 0000000000000000000000000000000000000000..b4ee700ec297755c0a3d4695837bdbe108a3c42d
--- /dev/null
+++ b/gcc/testsuite/c-c++-common/Wmisleading-indentation-2.c
@@ -0,0 +1,56 @@
+/* { dg-options "-Wmisleading-indentation" } */
+/* { dg-do compile } */
+
+/* Based on get_attr_athlon_decode from the generated insn-attrtab.c
+   for x86_64.
+   A #line directive, followed by a very long line to ensure that
+   we're in a fresh line_map.
+
+   This should not generate a misleading indentation warning.
+
+   This needs to be in its own file since -Wmisleading-indentation stops
+   after seeing a #line directive.  */
+void fn ()
+{
+  switch (0)
+    {
+#line 6 "../../../../src/gcc/testsuite/c-c++-common/Wmisleading-indentation-2.md"
+    case 0:
+      if (0)
+        {
+	  return;
+        }
+
+    case 1:
+      if (0)
+        {
+	  return;
+        }
+      else
+        {
+	  return;
+        }
+
+      /**********************************************************************************************************************************/
+      if (0)
+        {
+	  return;
+        }
+      else if (0)
+        {
+	  return;
+        }
+      else if (0)
+        {
+	  return;
+        }
+      else
+        {
+	  return;
+        }
+
+    default:
+      return;
+
+    }
+}
diff --git a/gcc/testsuite/c-c++-common/Wmisleading-indentation-2.md b/gcc/testsuite/c-c++-common/Wmisleading-indentation-2.md
new file mode 100644
index 0000000000000000000000000000000000000000..44bc13adf9df62926893d266ed1a8f322841f970
--- /dev/null
+++ b/gcc/testsuite/c-c++-common/Wmisleading-indentation-2.md
@@ -0,0 +1,46 @@
+;; Support file for testcase Wmisleading-indentation.c
+;; Adapted from gcc/config/i386/i386.md
+(define_attr "cpu" "none,pentium,pentiumpro,geode,k6,athlon,k8,core2,nehalem,
+		    atom,slm,generic,amdfam10,bdver1,bdver2,bdver3,bdver4,
+		    btver2,knl"
+  (const (symbol_ref "ix86_schedule")))
+
+;; A basic instruction type.  Refinements due to arguments to be
+;; provided in other attributes.
+(define_attr "type"
+  "other,multi,
+   alu,alu1,negnot,imov,imovx,lea,
+   incdec,ishift,ishiftx,ishift1,rotate,rotatex,rotate1,
+   imul,imulx,idiv,icmp,test,ibr,setcc,icmov,
+   push,pop,call,callv,leave,
+   str,bitmanip,
+   fmov,fop,fsgn,fmul,fdiv,fpspc,fcmov,fcmp,
+   fxch,fistp,fisttp,frndint,
+   sse,ssemov,sseadd,sseadd1,sseiadd,sseiadd1,
+   ssemul,sseimul,ssediv,sselog,sselog1,
+   sseishft,sseishft1,ssecmp,ssecomi,
+   ssecvt,ssecvt1,sseicvt,sseins,
+   sseshuf,sseshuf1,ssemuladd,sse4arg,
+   lwp,mskmov,msklog,
+   mmx,mmxmov,mmxadd,mmxmul,mmxcmp,mmxcvt,mmxshft,
+   mpxmov,mpxmk,mpxchk,mpxld,mpxst"
+  (const_string "other"))
+
+;; Main data type used by the insn
+(define_attr "mode"
+  "unknown,none,QI,HI,SI,DI,TI,OI,XI,SF,DF,XF,TF,V16SF,V8SF,V4DF,V4SF,
+  V2DF,V2SF,V1DF,V8DF"
+  (const_string "unknown"))
+
+;; The CPU unit operations uses.
+(define_attr "unit" "integer,i387,sse,mmx,unknown"
+  (cond [(eq_attr "type" "fmov,fop,fsgn,fmul,fdiv,fpspc,fcmov,fcmp,
+			  fxch,fistp,fisttp,frndint")
+	   (const_string "i387")
+	 (eq_attr "type" "sse,ssemov,sseadd,sseadd1,sseiadd,sseiadd1,
+			  ssemul,sseimul,ssediv,sselog,sselog1,
+			  sseishft,sseishft1,ssecmp,ssecomi,
+			  ssecvt,ssecvt1,sseicvt,sseins,
+			  sseshuf,sseshuf1,ssemuladd,sse4arg,mskmov")
+	   (const_string "sse")
+	 (const_string "integer")))
diff --git a/gcc/testsuite/c-c++-common/Wmisleading-indentation.c b/gcc/testsuite/c-c++-common/Wmisleading-indentation.c
new file mode 100644
index 0000000000000000000000000000000000000000..3dbbb8b17d3554c6d8fa0223685b07042f51443e
--- /dev/null
+++ b/gcc/testsuite/c-c++-common/Wmisleading-indentation.c
@@ -0,0 +1,431 @@
+/* { dg-options "-Wmisleading-indentation -Wall" } */
+/* { dg-do compile } */
+
+extern int foo (int);
+extern int bar (int, int);
+extern int flagA;
+extern int flagB;
+extern int flagC;
+extern int flagD;
+
+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;
+}
+
+int
+fn_2 (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;
+}
+
+int
+fn_3 (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;
+}
+
+void
+fn_4 (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..." } */
+}
+
+void
+fn_5 (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..." } */
+}
+
+/* Based on CVE-2014-1266 aka "goto fail" */
+int fn_6 (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;
+}
+
+int fn_7 (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..." } */
+      t++;
+    }
+  return p + q + r + s + t;
+}
+
+int fn_8 (int a, int b, int c)
+{
+  /* This should *not* be flagged as misleading indentation.  */
+  if (a) return b; else return c;
+}
+
+void fn_9 (int flag)
+{
+  if (flag) /* { dg-message "3: ...this 'if' clause, but it is not" } */
+    foo (0);
+    foo (1); /* { dg-warning "statement is indented as if it were guarded by..." } */
+}
+
+void fn_10 (int flag)
+{
+  if (flag) /* { dg-message "3: ...this 'if' clause, but it is not" } */
+    if (flag / 2)
+      {
+        foo (0);
+        foo (1);
+      }
+    foo (2); /* { dg-warning "statement is indented as if it were guarded by..." } */
+  foo (3);
+}
+
+void fn_11 (void)
+{
+  if (flagA)
+    if (flagB)
+      if (flagC) /* { dg-message "7: ...this 'if' clause, but it is not" } */
+        foo (0);
+        bar (1, 2); /* { dg-warning "statement is indented as if it were guarded by..." } */
+}
+
+void fn_12 (void)
+{
+  if (flagA)
+    if (flagB) /* { dg-message "5: ...this 'if' clause, but it is not" } */
+      if (flagC)
+        foo (0);
+      bar (1, 2); /* { dg-warning "statement is indented as if it were guarded by..." } */
+}
+
+void fn_13 (void)
+{
+  if (flagA) /* { dg-message "3: ...this 'if' clause, but it is not" } */
+    if (flagB)
+      if (flagC)
+        foo (0);
+    bar (1, 2); /* { dg-warning "statement is indented as if it were guarded by..." } */
+}
+
+#define FOR_EACH(VAR, START, STOP) \
+  for ((VAR) = (START); (VAR) < (STOP); (VAR++)) /* { dg-message "3: ...this 'for' clause, but it is not" } */
+
+void fn_14 (void)
+{
+  int i;
+  FOR_EACH (i, 0, 10) /* { dg-message "3: in expansion of macro" } */
+    foo (i);
+    bar (i, i); /* { dg-warning "statement is indented as if it were guarded by..." } */
+}
+#undef FOR_EACH
+
+#define FOR_EACH(VAR, START, STOP) for ((VAR) = (START); (VAR) < (STOP); (VAR++)) /* { dg-message "36: ...this 'for' clause, but it is not" } */
+void fn_15 (void)
+{
+  int i;
+  FOR_EACH (i, 0, 10) /* { dg-message "3: in expansion of macro" } */
+    foo (i);
+    bar (i, i); /* { dg-warning "statement is indented as if it were guarded by..." } */
+}
+#undef FOR_EACH
+
+void fn_16_spaces (void)
+{
+  int i;
+  for (i = 0; i < 10; i++)
+    while (flagA)
+      if (flagB) /* { dg-message "7: ...this 'if' clause, but it is not" } */
+        foo (0);
+        foo (1); /* { dg-warning "statement is indented as if it were guarded by..." } */
+}
+
+void fn_16_tabs (void)
+{
+  int i;
+  for (i = 0; i < 10; i++)
+    while (flagA)
+      if (flagB) /* { dg-message "7: ...this 'if' clause, but it is not" } */
+	foo (0);
+	foo (1);/* { dg-warning "statement is indented as if it were guarded by..." } */
+}
+
+void fn_17_spaces (void)
+{
+  int i;
+  for (i = 0; i < 10; i++) /* { dg-message "3: ...this 'for' clause, but it is not" } */
+    while (flagA)
+      if (flagB)
+        foo (0);
+    foo (1);/* { dg-warning "statement is indented as if it were guarded by..." } */
+}
+
+void fn_17_tabs (void)
+{
+  int i;
+  for (i = 0; i < 10; i++) /* { dg-message "3: ...this 'for' clause, but it is not" } */
+    while (flagA)
+      if (flagB)
+	foo (0);
+    foo (1);/* { dg-warning "statement is indented as if it were guarded by..." } */
+}
+
+void fn_18_spaces (void)
+{
+  int i;
+  for (i = 0; i < 10; i++)
+    while (flagA) /* { dg-message "5: ...this 'while' clause, but it is not" } */
+      if (flagB)
+        foo (0);
+      foo (1);/* { dg-warning "statement is indented as if it were guarded by..." } */
+}
+
+void fn_18_tabs (void)
+{
+  int i;
+  for (i = 0; i < 10; i++)
+    while (flagA) /* { dg-message "5: ...this 'while' clause, but it is not" } */
+      if (flagB)
+	foo (0);
+      foo (1);/* { dg-warning "statement is indented as if it were guarded by..." } */
+}
+
+/* This shouldn't lead to a warning.  */
+int fn_19 (void) { if (flagA) return 1; else return 0; }
+
+/* A deeply-nested mixture of spaces and tabs, adapted from
+   c-c++-common/pr60101.c.
+   This should not lead to a warning.  */
+void
+fn_20 (unsigned int l)
+{
+  unsigned int i;
+
+  for (i = 0; i < 10; i++)
+    {
+      unsigned int n0, n1, n2, n3, n4, n5, n6, n7, n8, n9, n10, n11;
+
+      for (n0 = 0; n0 < l; n0++)
+	for (n1 = 0; n1 < l; n1++)
+	  for (n2 = 0; n2 < l; n2++)
+	    for (n3 = 0; n3 < l; n3++)
+	      for (n4 = 0; n4 < l; n4++)
+		for (n5 = 0; n5 < l; n5++)
+		  for (n6 = 0; n6 < l; n6++)
+		    for (n7 = 0; n7 < l; n7++)
+		      for (n8 = 0; n8 < l; n8++)
+			for (n9 = 0; n9 < l; n9++)
+			  for (n10 = 0; n10 < l; n10++)
+			    for (n11 = 0; n11 < l; n11++)
+			      {
+				if (flagA)
+				  foo (0);
+				foo (1);
+			      }
+      foo (2);
+    }
+}
+
+/* Another nested mix of tabs and spaces that shouldn't lead to a warning,
+   with a preprocessor directive thrown in for good measure
+   (adapted from libgomp/loop.c: gomp_loop_init).  */
+void fn_21 (void)
+{
+  foo (0);
+  if (flagA)
+    {
+      foo (1);
+
+#if 1
+      {
+	foo (2);
+	if (flagB)
+	  {
+	    if (flagC)
+	      foo (3);
+	    else
+	      foo (4);
+	  }
+	else if (flagD)
+	  foo (5);
+	else
+	  foo (6);
+      }
+#endif
+    }
+}
+
+/* The conditionals within the following macros shouldn't be warned about.
+   Adapted from libgomp/driver.c: gomp_load_plugin_for_device.  */
+int fn_22 (void)
+{
+  int err = 0;
+
+#define DLSYM()							\
+  do									\
+    {									\
+      err = foo (0);							\
+      if (err)								\
+	goto out;							\
+    }									\
+  while (0)
+#define DLSYM_OPT()							\
+  do									\
+    {									\
+      err = foo (1);							\
+      if (err)								\
+        foo (2);							\
+      else								\
+        foo (3);							\
+      foo (4);								\
+    }									\
+  while (0)
+  DLSYM ();
+  DLSYM_OPT ();
+#undef DLSYM
+#undef DLSYM_OPT
+
+ out:
+  return err;
+}
+
+/* This shouldn't be warned about.  */
+void fn_23 (void) { foo (0); foo (1); if (flagA) foo (2); foo (3); foo (4); }
+
+/* Code that simply doesn't bother indenting anywhere (e.g. autogenerated
+   code) shouldn't be warned about.  */
+void fn_24 (void)
+{
+  foo (0);
+  if (flagA)
+  foo (1);
+  foo (2);
+}
+
+/* Adapted from libiberty/regex.c; an example of a conditional in a
+   macro where the successor statement begins with a macro arg:
+
+	    if (num < 0)
+	      num = 0;
+	    num = num * 10 + c - '0';
+	    ^ this successor statement
+
+   and hence "num" has a spelling location at the argument of the
+   macro usage site ("lower_bound"), we want the definition of the
+   parameter ("num") for the indentation comparison to be meaninful.
+
+   This should not generate a misleading indentation warning.  */
+
+# define GET_UNSIGNED_NUMBER(num) \
+  {									\
+    while (flagA)							\
+      {									\
+	if (flagB)						\
+	  {								\
+	    if (num < 0)						\
+	      num = 0;							\
+	    num = num * 10 + c - '0';					\
+	  }								\
+      }									\
+  }
+void fn_25 (int c, int lower_bound, int upper_bound)
+{
+  GET_UNSIGNED_NUMBER (lower_bound);
+}
+#undef GET_UNSIGNED_NUMBER
+
+/* Example adapted from libdecnumber/decNumber.c:decExpOp that shouldn't
+   trigger a warning.  */
+void fn_26 (void)
+{
+  if (flagA) {
+    if (flagB) foo (0); }
+  foo (1);
+}
+
+/* Ensure that we don't get confused by mixed tabs and spaces; the line
+   "foo (1);" has leading spaces before a tab, but this should not
+   lead to a warning from -Wmisleading-indentation.  */
+void fn_27 (void)
+{
+	      if (flagA)
+		foo (0);
+  	      foo (1);
+}
+
+/* Example adapted from gcc/cgraph.h:symtab_node::get_availability of
+   a spurious trailing semicolon that shouldn't generate a warning.  */
+void fn_28 (void)
+{
+  if (flagA)
+    foo (0);
+  else
+    foo (1);;
+}
+
+/* However, other kinds of spurious semicolons can be a problem.  Sadly
+   we don't yet report for the misleading-indented "foo (1);" in the
+   following, due to the spurious semicolon.  */
+void fn_29 (void)
+{
+  if (flagA)
+    if (flagB)
+      foo (0);;
+    foo (1);
+}
+
+/* Adapted from usage site of #ifdef HAVE_cc0.  This should not lead
+   to a warning from -Wmisleading-indentation.  */
+void fn_30 (void)
+{
+  if (flagA)
+    foo (0);
+#if SOME_CONDITION_THAT_DOES_NOT_HOLD
+  if (flagB)
+#endif
+    foo (1);
+}
+
+/* This shouldn't lead to a warning.  */
+void fn_31 (void)
+{
+  if (flagA)
+    foo (0);
+  else if (flagB)
+    foo (1);
+  else if (flagC)
+    foo (2);
+  else
+    foo (3);
+}
diff --git a/libcpp/ChangeLog b/libcpp/ChangeLog
index 51304424753e93bebf01a6c7dd907012dbea52f9..c0f04ac044547e52c6ac122a2a1ae164d7640907 100644
--- a/libcpp/ChangeLog
+++ b/libcpp/ChangeLog
@@ -1,3 +1,10 @@
+2015-05-12  David Malcolm  <dmalcolm@redhat.com>
+
+	* directives.c (do_line): Set seen_line_directive on line_table.
+	(do_linemarker): Likewise.
+	* include/line-map.h (struct line_maps): Add new field
+	"seen_line_directive".
+
 2015-05-08  Jason Merrill  <jason@redhat.com>
 
 	* include/cpplib.h: Add CPP_W_CXX11_COMPAT.
diff --git a/libcpp/directives.c b/libcpp/directives.c
index 2a824e6ed3f14a05b65fb37f8631883834e50f85..356ec135100d9c9d7e32b87b9b55fcfc3227daa7 100644
--- a/libcpp/directives.c
+++ b/libcpp/directives.c
@@ -911,7 +911,7 @@ strtolinenum (const uchar *str, size_t len, linenum_type *nump, bool *wrapped)
 static void
 do_line (cpp_reader *pfile)
 {
-  const struct line_maps *line_table = pfile->line_table;
+  struct line_maps *line_table = pfile->line_table;
   const struct line_map *map = LINEMAPS_LAST_ORDINARY_MAP (line_table);
 
   /* skip_rest_of_line() may cause line table to be realloc()ed so note down
@@ -965,6 +965,7 @@ do_line (cpp_reader *pfile)
   skip_rest_of_line (pfile);
   _cpp_do_file_change (pfile, LC_RENAME_VERBATIM, new_file, new_lineno,
 		       map_sysp);
+  line_table->seen_line_directive = true;
 }
 
 /* Interpret the # 44 "file" [flags] notation, which has slightly
@@ -973,7 +974,7 @@ do_line (cpp_reader *pfile)
 static void
 do_linemarker (cpp_reader *pfile)
 {
-  const struct line_maps *line_table = pfile->line_table;
+  struct line_maps *line_table = pfile->line_table;
   const struct line_map *map = LINEMAPS_LAST_ORDINARY_MAP (line_table);
   const cpp_token *token;
   const char *new_file = ORDINARY_MAP_FILE_NAME (map);
@@ -1052,6 +1053,7 @@ do_linemarker (cpp_reader *pfile)
   pfile->line_table->highest_location--;
 
   _cpp_do_file_change (pfile, reason, new_file, new_lineno, new_sysp);
+  line_table->seen_line_directive = true;
 }
 
 /* Arrange the file_change callback.  pfile->line has changed to
diff --git a/libcpp/include/line-map.h b/libcpp/include/line-map.h
index e1681ea591d91ec59f07f7d5897974243569e448..ddeaf0c1954bb40e6ead87d83213c83b2980dac1 100644
--- a/libcpp/include/line-map.h
+++ b/libcpp/include/line-map.h
@@ -386,6 +386,9 @@ struct GTY(()) line_maps {
   /* The special location value that is used as spelling location for
      built-in tokens.  */
   source_location builtin_location;
+
+  /* True if we've seen a #line or # 44 "file" directive.  */
+  bool seen_line_directive;
 };
 
 /* Returns the pointer to the memory region where information about