[PATCH] c-family: Macro support in -Wmisleading-indentation [PR80076]

Patrick Palka ppalka@redhat.com
Thu Sep 10 19:53:52 GMT 2020


On Thu, 10 Sep 2020, David Malcolm wrote:

> On Tue, 2020-07-28 at 20:22 -0400, Patrick Palka wrote:
> > On Tue, 28 Jul 2020, David Malcolm wrote:
> > 
> > > On Tue, 2020-07-28 at 15:50 -0400, Patrick Palka wrote:
> > > > Currently the -Wmisleading-indentation warning doesn't do any
> > > > analysis
> > > > when the guarded statement or the statement after it is produced
> > > > by a
> > > > macro, as the mentioned PR illustrates.  This means that we warn
> > > > for:
> > > > 
> > > >   if (flag)
> > > >     foo ();
> > > >     bar ();
> > > > 
> > > > and yet we don't warn for:
> > > > 
> > > >   #define BAR bar
> > > >   if (flag)
> > > >     foo ();
> > > >     BAR ();
> > > > 
> > > > which seems like a surprising limitation.
> > > 
> > > IIRC we were trying to keep things simple in the initial
> > > implementation.
> > > 
> > > > This patch extends the -Wmisleading-indentation implementation to
> > > > support analyzing such statements and their tokens.  This is done
> > > > in
> > > > the
> > > > "natural" way by resolving the location of each of the three
> > > > tokens
> > > > to
> > > > the token's macro expansion point.  (Additionally, if the tokens
> > > > all
> > > > resolve to the same macro expansion point then we instead use
> > > > their
> > > > locations within the macro definition.)  When these resolved
> > > > locations
> > > > are all different, then we can proceed with applying the warning
> > > > heuristics to them as if no macros were involved.
> > > 
> > > Thanks for working on this.  I've only looked at the patch briefly,
> > > but
> > > so far it looks reasonable.
> > > 
> > > Can you post some examples of what the output looks like for some
> > > of
> > > these cases?  The diagnostics code has some logic for printing how
> > > macros are unwound, so I'm wondering what we actually print for
> > > these
> > > cases, and if it looks intelligble to an end-user.
> > 
> > For the code fragment mentioned above:
> > 
> >   int
> >   main()
> >   {
> >     #define BAR
> >     if (flag)
> >       foo ();
> >       BAR ();
> >   }
> > 
> > we emit:
> > 
> > test.cc: In function ‘int main()’:
> > test.cc:7:3: warning: this ‘if’ clause does not guard... [-
> > Wmisleading-indentation]
> >     9 |   if (flag)
> >       |   ^~
> > test.cc:8:15: note: ...this statement, but the latter is misleadingly
> > indented as if it were guarded by the ‘if’
> >     8 |   #define BAR bar
> >       |               ^~~
> > test.cc:10:5: note: in expansion of macro ‘BAR’
> >    11 |     BAR ();
> >       |     ^~~
> > 
> > 
> > And when all tokens are generated from the same macro, e.g. for:
> > 
> >   int
> >   main()
> >   {
> >     #define BAR bar
> >     #define DO_STUFF      \
> >       if (flag)           \
> >         foo ();           \
> >         BAR ();
> >     DO_STUFF;
> >   }
> > 
> > we emit:
> > 
> > test.cc: In function ‘int main()’:
> > test.cc:11:5: warning: this ‘if’ clause does not guard... [-
> > Wmisleading-indentation]
> >    11 |     if (flag)           \
> >       |     ^~
> > test.cc:14:3: note: in expansion of macro ‘DO_STUFF’
> >    14 |   DO_STUFF;
> >       |   ^~~~~~~~
> > test.cc:9:15: note: ...this statement, but the latter is misleadingly
> > indented as if it were guarded by the ‘if’
> >     9 |   #define BAR bar
> >       |               ^~~
> > test.cc:13:7: note: in expansion of macro ‘BAR’
> >    13 |       BAR ();
> >       |       ^~~
> > test.cc:14:3: note: in expansion of macro ‘DO_STUFF’
> >    14 |   DO_STUFF;
> >       |   ^~~~~~~~
> > 
> > The automatic macro unwinding logic saves the day here and yields
> > mostly
> > legible output "for free".  What do you think?
> 
> Sorry about the delay in responding.
> 
> I agree that the output is "mostly legible".
> 
> The patch is OK as-is, and looking at the fixes you made to our source
> tree I think it's usefully catching problematic code.
> 

Thanks for your review!

> That said, I wonder if the output could be improved for the macro case.
>  
> Within should_warn_for_misleading_indentation the patch can update
> guard_loc, body_loc and next_stmt_loc before expand_location is called
> on them, but then in warn_for_misleading_indentation it uses the
> original guard_tinfo.location and next_tinfo.location for the locations
> of the warning and note.  I have a hunch that the readability of the
> diagnostic would be improved for the macro case by updating those
> locations whenever the inputs to expand_location are updated.  It would
> lose some detail from the point of view of the user grokking macro
> expansions, but perhaps is better given the specific focus of this
> warning on whitespace.  Does doing so help for the various cases you've
> tried?

This makes a lot of sense to me and it seems to work well in the cases
I've tried.

As before, for the code fragment:

  int
  main()
  {
    #define BAR
    if (flag)
      foo ();
      BAR ();
  }

we now emit:

test.cc: In function ‘int main()’:
test.cc:7:3: warning: this ‘if’ clause does not guard... [-
Wmisleading-indentation]
    9 |   if (flag)
      |   ^~
test.cc:10:5: note: ...this statement, but the latter is misleadingly indented as if it were guarded by the ‘if’
   11 |     BAR ();
      |     ^~~


When all tokens are generated from the same macro, e.g. for:

  int
  main()
  {
    #define BAR bar
    #define DO_STUFF      \
      if (flag)           \
        foo ();           \
        BAR ();
    DO_STUFF;
  }

we emit... the same diagnostic as above :)

The below patch implements the approach you outlined; some existing
-Wmisleading-indentation testcases had to be adjusted accordingly.  Is
something like this what you had in mind?

-- >8 --

gcc/c-family/ChangeLog:

	PR c/80076
	* c-indentation.c (should_warn_for_misleading_indentation): Take
	each token_indent_info argument by reference.  Move declarations
	of local variables closer to their first use.  Handle virtual
	token locations by resolving them to their respective macro
	expansion points.  If all three tokens are produced from the
	same macro expansion, then instead use their loci within the
	macro definition.  Update the token_indent_info::location of
	each of the supplied arguments.
	(warn_for_misleading_indentation): Take each token_indent_info
	argument by value.
	* c-indentation.h (warn_for_misleading_indentation): Adjust
	declaration accordingly.

gcc/objc/ChangeLog:

	PR c/80076
	* objc-gnu-runtime-abi-01.c
	(gnu_runtime_abi_01_get_class_super_ref): Reduce indentation of
	misleadingly indented return statements.
	* objc-next-runtime-abi-01.c
	(next_runtime_abi_01_get_class_super_ref): Likewise.

gcc/ChangeLog:

	PR c/80076
	* gensupport.c (alter_attrs_for_subst_insn) <case SET_ATTR>:
	Reduce indentation of misleadingly indented code fragment.
	* lra-constraints.c (multi_block_pseudo_p): Likewise.
	* sel-sched-ir.c (merge_fences): Likewise.

libcpp/ChangeLog:

	PR c/80076
	* include/line-map.h (first_map_in_common): Declare.
	* line-map.c (first_map_in_common): Remove static.

gcc/testsuite/ChangeLog:

	PR c/80076
	* c-c++-common/Wmisleading-indentation.c: Don't expect a "in
	expansion of macro ..." note when the guard token is inside a
	macro.  Expect the "this clause does not guard" warning at the
	macro expansion point instead of at the macro definition point
	when the guard token is inside a macro.
	* c-c++-common/Wmisleading-indentation-3.c: Likewise.
	* c-c++-common/Wmisleading-indentation-5.c: New test.
---
 gcc/c-family/c-indentation.c                  |  80 ++++++++++---
 gcc/c-family/c-indentation.h                  |   6 +-
 gcc/gensupport.c                              |   2 +-
 gcc/lra-constraints.c                         |  12 +-
 gcc/objc/objc-gnu-runtime-abi-01.c            |   4 +-
 gcc/objc/objc-next-runtime-abi-01.c           |   4 +-
 gcc/sel-sched-ir.c                            | 112 +++++++++---------
 .../c-c++-common/Wmisleading-indentation-3.c  |   8 +-
 .../c-c++-common/Wmisleading-indentation-5.c  |  52 ++++++++
 .../c-c++-common/Wmisleading-indentation.c    |  16 +--
 libcpp/include/line-map.h                     |   6 +
 libcpp/line-map.c                             |   2 +-
 12 files changed, 200 insertions(+), 104 deletions(-)
 create mode 100644 gcc/testsuite/c-c++-common/Wmisleading-indentation-5.c

diff --git a/gcc/c-family/c-indentation.c b/gcc/c-family/c-indentation.c
index d814f6f29e6..de7b426f35c 100644
--- a/gcc/c-family/c-indentation.c
+++ b/gcc/c-family/c-indentation.c
@@ -209,23 +209,10 @@ detect_intervening_unindent (const char *file,
    description of that function below.  */
 
 static bool
-should_warn_for_misleading_indentation (const token_indent_info &guard_tinfo,
-					const token_indent_info &body_tinfo,
-					const token_indent_info &next_tinfo)
+should_warn_for_misleading_indentation (token_indent_info &guard_tinfo,
+					token_indent_info &body_tinfo,
+					token_indent_info &next_tinfo)
 {
-  location_t guard_loc = guard_tinfo.location;
-  location_t body_loc = body_tinfo.location;
-  location_t next_stmt_loc = next_tinfo.location;
-
-  enum cpp_ttype body_type = body_tinfo.type;
-  enum cpp_ttype next_tok_type = next_tinfo.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.
 
@@ -266,6 +253,7 @@ should_warn_for_misleading_indentation (const token_indent_info &guard_tinfo,
      }            <- NEXT
      baz ();
   */
+  enum cpp_ttype next_tok_type = next_tinfo.type;
   if (next_tok_type == CPP_CLOSE_BRACE
       || next_tinfo.keyword == RID_ELSE)
     return false;
@@ -287,6 +275,7 @@ should_warn_for_misleading_indentation (const token_indent_info &guard_tinfo,
       bar (); <- BODY
       baz (); <- NEXT
   */
+  enum cpp_ttype body_type = body_tinfo.type;
   if (body_type == CPP_OPEN_BRACE)
     return false;
 
@@ -294,6 +283,59 @@ should_warn_for_misleading_indentation (const token_indent_info &guard_tinfo,
   if (next_tok_type == CPP_SEMICOLON)
     return false;
 
+  location_t guard_loc = guard_tinfo.location;
+  location_t body_loc = body_tinfo.location;
+  location_t next_stmt_loc = next_tinfo.location;
+
+  /* Resolve each token location to the respective macro expansion
+     point that produced the token.  */
+  if (linemap_location_from_macro_expansion_p (line_table, guard_loc))
+    guard_loc = linemap_resolve_location (line_table, guard_loc,
+					  LRK_MACRO_EXPANSION_POINT, NULL);
+  if (linemap_location_from_macro_expansion_p (line_table, body_loc))
+    body_loc = linemap_resolve_location (line_table, body_loc,
+					 LRK_MACRO_EXPANSION_POINT, NULL);
+  if (linemap_location_from_macro_expansion_p (line_table, next_stmt_loc))
+    next_stmt_loc = linemap_resolve_location (line_table, next_stmt_loc,
+					      LRK_MACRO_EXPANSION_POINT, NULL);
+
+  /* When all three tokens are produced from a single macro expansion, we
+     instead consider their loci inside that macro's definition.  */
+  if (guard_loc == body_loc && body_loc == next_stmt_loc)
+    {
+      const line_map *guard_body_common_map
+	= first_map_in_common (line_table,
+			       guard_tinfo.location, body_tinfo.location,
+			       &guard_loc, &body_loc);
+      const line_map *body_next_common_map
+	= first_map_in_common (line_table,
+			       body_tinfo.location, next_tinfo.location,
+			       &body_loc, &next_stmt_loc);
+
+      /* Punt on complicated nesting of macros.  */
+      if (guard_body_common_map != body_next_common_map)
+	return false;
+
+      guard_loc = linemap_resolve_location (line_table, guard_loc,
+					    LRK_MACRO_DEFINITION_LOCATION, NULL);
+      body_loc = linemap_resolve_location (line_table, body_loc,
+					   LRK_MACRO_DEFINITION_LOCATION, NULL);
+      next_stmt_loc = linemap_resolve_location (line_table, next_stmt_loc,
+						LRK_MACRO_DEFINITION_LOCATION,
+						NULL);
+    }
+
+  /* Give up if the loci are not all distinct.  */
+  if (guard_loc == body_loc || body_loc == next_stmt_loc)
+    return false;
+
+  /* Now update the tokens' locations on the caller side too, so that the
+     diagnostics emitted by warn_for_misleading_indentation focus on the
+     problematic whitespace by omitting macro expansion notes.  */
+  guard_tinfo.location = guard_loc;
+  body_tinfo.location = body_loc;
+  next_tinfo.location = next_stmt_loc;
+
   expanded_location body_exploc = expand_location (body_loc);
   expanded_location next_stmt_exploc = expand_location (next_stmt_loc);
   expanded_location guard_exploc = expand_location (guard_loc);
@@ -599,9 +641,9 @@ guard_tinfo_to_string (enum rid keyword)
    GUARD_KIND identifies the kind of clause e.g. "if", "else" etc.  */
 
 void
-warn_for_misleading_indentation (const token_indent_info &guard_tinfo,
-				 const token_indent_info &body_tinfo,
-				 const token_indent_info &next_tinfo)
+warn_for_misleading_indentation (token_indent_info guard_tinfo,
+				 token_indent_info body_tinfo,
+				 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
diff --git a/gcc/c-family/c-indentation.h b/gcc/c-family/c-indentation.h
index e183d3aafb7..67400f6d43b 100644
--- a/gcc/c-family/c-indentation.h
+++ b/gcc/c-family/c-indentation.h
@@ -45,9 +45,9 @@ get_token_indent_info (const T *token)
 }
 
 extern void
-warn_for_misleading_indentation (const token_indent_info &guard_tinfo,
-				 const token_indent_info &body_tinfo,
-				 const token_indent_info &next_tinfo);
+warn_for_misleading_indentation (token_indent_info guard_tinfo,
+				 token_indent_info body_tinfo,
+				 token_indent_info next_tinfo);
 extern const char *
 guard_tinfo_to_string (enum rid keyword);
 
diff --git a/gcc/gensupport.c b/gcc/gensupport.c
index f2ad54f0c55..61691aadff1 100644
--- a/gcc/gensupport.c
+++ b/gcc/gensupport.c
@@ -1501,7 +1501,7 @@ alter_attrs_for_subst_insn (class queue_elem * elem, int n_dup)
 	case SET_ATTR:
 	  if (strchr (XSTR (sub, 1), ',') != NULL)
 	    XSTR (sub, 1) = duplicate_alternatives (XSTR (sub, 1), n_dup);
-	    break;
+	  break;
 
 	case SET_ATTR_ALTERNATIVE:
 	case SET:
diff --git a/gcc/lra-constraints.c b/gcc/lra-constraints.c
index 161b721efb1..301c912cb21 100644
--- a/gcc/lra-constraints.c
+++ b/gcc/lra-constraints.c
@@ -4776,12 +4776,12 @@ multi_block_pseudo_p (int regno)
   if (regno < FIRST_PSEUDO_REGISTER)
     return false;
 
-    EXECUTE_IF_SET_IN_BITMAP (&lra_reg_info[regno].insn_bitmap, 0, uid, bi)
-      if (bb == NULL)
-	bb = BLOCK_FOR_INSN (lra_insn_recog_data[uid]->insn);
-      else if (BLOCK_FOR_INSN (lra_insn_recog_data[uid]->insn) != bb)
-	return true;
-    return false;
+  EXECUTE_IF_SET_IN_BITMAP (&lra_reg_info[regno].insn_bitmap, 0, uid, bi)
+    if (bb == NULL)
+      bb = BLOCK_FOR_INSN (lra_insn_recog_data[uid]->insn);
+    else if (BLOCK_FOR_INSN (lra_insn_recog_data[uid]->insn) != bb)
+      return true;
+  return false;
 }
 
 /* Return true if LIST contains a deleted insn.  */
diff --git a/gcc/objc/objc-gnu-runtime-abi-01.c b/gcc/objc/objc-gnu-runtime-abi-01.c
index d5862435c29..c9959a7e1e8 100644
--- a/gcc/objc/objc-gnu-runtime-abi-01.c
+++ b/gcc/objc/objc-gnu-runtime-abi-01.c
@@ -821,7 +821,7 @@ gnu_runtime_abi_01_get_class_super_ref (location_t loc ATTRIBUTE_UNUSED,
 	ucls_super_ref =
 		objc_build_component_ref (imp->class_decl,
 					  get_identifier ("super_class"));
-	return ucls_super_ref;
+      return ucls_super_ref;
     }
   else
     {
@@ -829,7 +829,7 @@ gnu_runtime_abi_01_get_class_super_ref (location_t loc ATTRIBUTE_UNUSED,
 	uucls_super_ref =
 		objc_build_component_ref (imp->meta_decl,
 					  get_identifier ("super_class"));
-	return uucls_super_ref;
+      return uucls_super_ref;
     }
 }
 
diff --git a/gcc/objc/objc-next-runtime-abi-01.c b/gcc/objc/objc-next-runtime-abi-01.c
index 5c34fcb05cb..233d89e75b5 100644
--- a/gcc/objc/objc-next-runtime-abi-01.c
+++ b/gcc/objc/objc-next-runtime-abi-01.c
@@ -938,7 +938,7 @@ next_runtime_abi_01_get_class_super_ref (location_t loc ATTRIBUTE_UNUSED,
 	ucls_super_ref =
 		objc_build_component_ref (imp->class_decl,
 					  get_identifier ("super_class"));
-	return ucls_super_ref;
+      return ucls_super_ref;
     }
   else
     {
@@ -946,7 +946,7 @@ next_runtime_abi_01_get_class_super_ref (location_t loc ATTRIBUTE_UNUSED,
 	uucls_super_ref =
 		objc_build_component_ref (imp->meta_decl,
 					  get_identifier ("super_class"));
-	return uucls_super_ref;
+      return uucls_super_ref;
     }
 }
 
diff --git a/gcc/sel-sched-ir.c b/gcc/sel-sched-ir.c
index f58628ae92d..c8e086e4950 100644
--- a/gcc/sel-sched-ir.c
+++ b/gcc/sel-sched-ir.c
@@ -722,63 +722,63 @@ merge_fences (fence_t f, insn_t insn,
                         != BLOCK_FOR_INSN (last_scheduled_insn));
           }
 
-        /* Find edge of first predecessor (last_scheduled_insn_old->insn).  */
-        FOR_EACH_SUCC_1 (succ, si, last_scheduled_insn_old,
-                         SUCCS_NORMAL | SUCCS_SKIP_TO_LOOP_EXITS)
-          {
-            if (succ == insn)
-              {
-                /* No same successor allowed from several edges.  */
-                gcc_assert (!edge_old);
-                edge_old = si.e1;
-              }
-          }
-        /* Find edge of second predecessor (last_scheduled_insn->insn).  */
-        FOR_EACH_SUCC_1 (succ, si, last_scheduled_insn,
-                         SUCCS_NORMAL | SUCCS_SKIP_TO_LOOP_EXITS)
-          {
-            if (succ == insn)
-              {
-                /* No same successor allowed from several edges.  */
-                gcc_assert (!edge_new);
-                edge_new = si.e1;
-              }
-          }
+      /* Find edge of first predecessor (last_scheduled_insn_old->insn).  */
+      FOR_EACH_SUCC_1 (succ, si, last_scheduled_insn_old,
+		       SUCCS_NORMAL | SUCCS_SKIP_TO_LOOP_EXITS)
+	{
+	  if (succ == insn)
+	    {
+	      /* No same successor allowed from several edges.  */
+	      gcc_assert (!edge_old);
+	      edge_old = si.e1;
+	    }
+	}
+      /* Find edge of second predecessor (last_scheduled_insn->insn).  */
+      FOR_EACH_SUCC_1 (succ, si, last_scheduled_insn,
+		       SUCCS_NORMAL | SUCCS_SKIP_TO_LOOP_EXITS)
+	{
+	  if (succ == insn)
+	    {
+	      /* No same successor allowed from several edges.  */
+	      gcc_assert (!edge_new);
+	      edge_new = si.e1;
+	    }
+	}
 
-        /* Check if we can choose most probable predecessor.  */
-        if (edge_old == NULL || edge_new == NULL)
-          {
-            reset_deps_context (FENCE_DC (f));
-            delete_deps_context (dc);
-            vec_free (executing_insns);
-            free (ready_ticks);
-
-            FENCE_CYCLE (f) = MAX (FENCE_CYCLE (f), cycle);
-            if (FENCE_EXECUTING_INSNS (f))
-              FENCE_EXECUTING_INSNS (f)->block_remove (0,
-                                FENCE_EXECUTING_INSNS (f)->length ());
-            if (FENCE_READY_TICKS (f))
-              memset (FENCE_READY_TICKS (f), 0, FENCE_READY_TICKS_SIZE (f));
-          }
-        else
-          if (edge_new->probability > edge_old->probability)
-            {
-              delete_deps_context (FENCE_DC (f));
-              FENCE_DC (f) = dc;
-              vec_free (FENCE_EXECUTING_INSNS (f));
-              FENCE_EXECUTING_INSNS (f) = executing_insns;
-              free (FENCE_READY_TICKS (f));
-              FENCE_READY_TICKS (f) = ready_ticks;
-              FENCE_READY_TICKS_SIZE (f) = ready_ticks_size;
-              FENCE_CYCLE (f) = cycle;
-            }
-          else
-            {
-              /* Leave DC and CYCLE untouched.  */
-              delete_deps_context (dc);
-              vec_free (executing_insns);
-              free (ready_ticks);
-            }
+      /* Check if we can choose most probable predecessor.  */
+      if (edge_old == NULL || edge_new == NULL)
+	{
+	  reset_deps_context (FENCE_DC (f));
+	  delete_deps_context (dc);
+	  vec_free (executing_insns);
+	  free (ready_ticks);
+
+	  FENCE_CYCLE (f) = MAX (FENCE_CYCLE (f), cycle);
+	  if (FENCE_EXECUTING_INSNS (f))
+	    FENCE_EXECUTING_INSNS (f)->block_remove (0,
+			      FENCE_EXECUTING_INSNS (f)->length ());
+	  if (FENCE_READY_TICKS (f))
+	    memset (FENCE_READY_TICKS (f), 0, FENCE_READY_TICKS_SIZE (f));
+	}
+      else
+	if (edge_new->probability > edge_old->probability)
+	  {
+	    delete_deps_context (FENCE_DC (f));
+	    FENCE_DC (f) = dc;
+	    vec_free (FENCE_EXECUTING_INSNS (f));
+	    FENCE_EXECUTING_INSNS (f) = executing_insns;
+	    free (FENCE_READY_TICKS (f));
+	    FENCE_READY_TICKS (f) = ready_ticks;
+	    FENCE_READY_TICKS_SIZE (f) = ready_ticks_size;
+	    FENCE_CYCLE (f) = cycle;
+	  }
+	else
+	  {
+	    /* Leave DC and CYCLE untouched.  */
+	    delete_deps_context (dc);
+	    vec_free (executing_insns);
+	    free (ready_ticks);
+	  }
     }
 
   /* Fill remaining invariant fields.  */
diff --git a/gcc/testsuite/c-c++-common/Wmisleading-indentation-3.c b/gcc/testsuite/c-c++-common/Wmisleading-indentation-3.c
index 2314ad42402..245019b6587 100644
--- a/gcc/testsuite/c-c++-common/Wmisleading-indentation-3.c
+++ b/gcc/testsuite/c-c++-common/Wmisleading-indentation-3.c
@@ -57,19 +57,15 @@ fail:
 }
 
 #define FOR_EACH(VAR, START, STOP) \
-  for ((VAR) = (START); (VAR) < (STOP); (VAR++)) /* { dg-warning "3: this 'for' clause does not guard..." } */
+  for ((VAR) = (START); (VAR) < (STOP); (VAR++))
 
 void fn_14 (void)
 {
   int i;
-  FOR_EACH (i, 0, 10) /* { dg-message "in expansion of macro .FOR_EACH." } */
+  FOR_EACH (i, 0, 10) /* { dg-message "3: this 'for' clause does not guard..." } */
     foo (i);
     bar (i, i); /* { dg-message "5: ...this statement, but the latter is misleadingly indented as if it were guarded by the 'for'" } */
 
-/* { dg-begin-multiline-output "" }
-   for ((VAR) = (START); (VAR) < (STOP); (VAR++))
-   ^~~
-   { dg-end-multiline-output "" } */
 /* { dg-begin-multiline-output "" }
    FOR_EACH (i, 0, 10)
    ^~~~~~~~
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 00000000000..f694c3935f2
--- /dev/null
+++ b/gcc/testsuite/c-c++-common/Wmisleading-indentation-5.c
@@ -0,0 +1,52 @@
+/* PR c/80076  */
+/* { dg-options "-Wmisleading-indentation" }  */
+
+void foo(void);
+
+void test01(int flag) {
+#define bar() foo()
+  if (flag) /* { dg-warning "does not guard" }  */
+    foo();
+    bar(); /* { dg-message "this statement" }  */
+#undef bar
+}
+
+void test02(int flag) {
+#define bar() foo()
+  if (flag) /* { dg-warning "does not guard" }  */
+    bar();
+    foo(); /* { dg-message "this statement" }  */
+#undef bar
+}
+
+void test03(int flag) {
+#define bar() foo()
+  if (flag) /* { dg-warning "does not guard" }  */
+    bar();
+    bar(); /* { dg-message "this statement" }  */
+#undef bar
+}
+
+void test04(int flag, int num) {
+#define bar() \
+  {		\
+    if (flag)	  /* { dg-warning "does not guard" }  */ \
+      num = 0;	\
+      num = 1;	  /* { dg-message "this statement" }  */ \
+  }
+  bar();
+#undef bar
+}
+
+void test05(int flag, int num) {
+#define baz() (num = 1)
+#define bar() \
+  {		\
+    if (flag)	  /* { dg-warning "does not guard" }  */ \
+      num = 0;	\
+      baz();	  /* { dg-message "this statement" }  */ \
+  }
+#define wrapper bar
+  wrapper();
+#undef bar
+}
diff --git a/gcc/testsuite/c-c++-common/Wmisleading-indentation.c b/gcc/testsuite/c-c++-common/Wmisleading-indentation.c
index 202c6bc7fdf..4265dcb4dfa 100644
--- a/gcc/testsuite/c-c++-common/Wmisleading-indentation.c
+++ b/gcc/testsuite/c-c++-common/Wmisleading-indentation.c
@@ -140,22 +140,22 @@ void fn_13 (void)
 }
 
 #define FOR_EACH(VAR, START, STOP) \
-  for ((VAR) = (START); (VAR) < (STOP); (VAR++)) /* { dg-warning "3: this 'for' clause does not guard..." } */
+  for ((VAR) = (START); (VAR) < (STOP); (VAR++))
 
 void fn_14 (void)
 {
   int i;
-  FOR_EACH (i, 0, 10) /* { dg-message "in expansion of macro .FOR_EACH." } */
+  FOR_EACH (i, 0, 10) /* { dg-message "3: this 'for' clause does not guard..." } */
     foo (i);
     bar (i, i); /* { dg-message "5: ...this statement, but the latter is misleadingly indented as if it were guarded by the 'for'" } */
 }
 #undef FOR_EACH
 
-#define FOR_EACH(VAR, START, STOP) for ((VAR) = (START); (VAR) < (STOP); (VAR++)) /* { dg-message "36: this 'for' clause does not guard..." } */
+#define FOR_EACH(VAR, START, STOP) for ((VAR) = (START); (VAR) < (STOP); (VAR++))
 void fn_15 (void)
 {
   int i;
-  FOR_EACH (i, 0, 10) /* { dg-message "in expansion of macro .FOR_EACH." } */
+  FOR_EACH (i, 0, 10) /* { dg-message "3: this 'for' clause does not guard..." } */
     foo (i);
     bar (i, i); /* { dg-message "5: ...this statement, but the latter is misleadingly indented as if it were guarded by the 'for'" } */
 }
@@ -701,7 +701,7 @@ fn_37 (void)
   int i;
 
 #define EMPTY
-#define FOR_EACH(VAR, START, STOP) for (VAR = START; VAR < STOP; VAR++) /* { dg-warning "this 'for' clause" } */
+#define FOR_EACH(VAR, START, STOP) for (VAR = START; VAR < STOP; VAR++)
 
   while (flagA); /* { dg-warning "3: this 'while' clause" } */
     foo (0); /* { dg-message "5: ...this statement, but the latter is misleadingly indented as if it were guarded by the 'while'" } */
@@ -759,15 +759,15 @@ fn_37 (void)
   for (i = 0; i < 10; i++); /* { dg-warning "3: this 'for' clause" } */
     foo (2); /* { dg-message "5: ...this statement" } */
 
-  FOR_EACH (i, 0, 10); /* { dg-message "3: in expansion of macro .FOR_EACH." } */
+  FOR_EACH (i, 0, 10); /* { dg-message "3: this 'for' clause does not guard..." } */
     foo (2); /* { dg-message "5: ...this statement" } */
 
-  FOR_EACH (i, 0, 10); /* { dg-message "3: in expansion of macro .FOR_EACH." } */
+  FOR_EACH (i, 0, 10); /* { dg-message "3: this 'for' clause does not guard..." } */
     { /* { dg-message "5: ...this statement" } */
       foo (3);
     }
 
-  FOR_EACH (i, 0, 10); /* { dg-message "3: in expansion of macro .FOR_EACH." } */
+  FOR_EACH (i, 0, 10); /* { dg-message "3: this 'for' clause does not guard..." } */
   { /* { dg-message "3: ...this statement" } */
     foo (3);
   }
diff --git a/libcpp/include/line-map.h b/libcpp/include/line-map.h
index 217f916fc35..44008be5c08 100644
--- a/libcpp/include/line-map.h
+++ b/libcpp/include/line-map.h
@@ -1225,6 +1225,12 @@ LINEMAP_SYSP (const line_map_ordinary *ord_map)
   return ord_map->sysp;
 }
 
+const struct line_map *first_map_in_common (line_maps *set,
+					    location_t loc0,
+					    location_t loc1,
+					    location_t *res_loc0,
+					    location_t *res_loc1);
+
 /* Return a positive value if PRE denotes the location of a token that
    comes before the token of POST, 0 if PRE denotes the location of
    the same token as the token for POST, and a negative value
diff --git a/libcpp/line-map.c b/libcpp/line-map.c
index a8d52861dee..5a74174579f 100644
--- a/libcpp/line-map.c
+++ b/libcpp/line-map.c
@@ -1289,7 +1289,7 @@ first_map_in_common_1 (line_maps *set,
    virtual location of the token inside the resulting macro, upon
    return of a non-NULL result.  */
 
-static const struct line_map*
+const struct line_map*
 first_map_in_common (line_maps *set,
 		     location_t loc0,
 		     location_t loc1,
-- 
2.28.0.497.g54e85e7af1


More information about the Gcc-patches mailing list