On Thu, 10 Sep 2020, Patrick Palka wrote:

> 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!

I committed the original patch just now, and instead split out the
potential refinement to macro diagnostics as a followup patch for
separate consideration:

-- >8 --

Subject: [PATCH] c-family: Refine -Wmisleading-indentation diagnostics for
 macros

This changes the locations of the warning and note emitted by
warn_for_misleading_indentation when the guard or next token is
generated from a macro.  The intent is to make the emitted diagnostics
emphasize the location of the misleading indentation by omitting macro
expansion notes.  For example, for the following fragment:

  #define WHILE while
  #define FOO foo
  #define BAR bar

  WHILE (cond)
    FOO ();
    BAR ();

before this patch we emit:

  5:17: warning: this ‘while’ clause does not guard... 
[-Wmisleading-indentation]
      5 |   #define WHILE while
        |                 ^~~~~
  8:3: note: in expansion of macro ‘WHILE’
      8 |   WHILE (true)
        |   ^~~~~
  7:15: note: ...this statement, but the latter is misleadingly indented as if 
it were guarded by the ‘while’
      7 |   #define BAR bar
        |               ^~~
  10:5: note: in expansion of macro ‘BAR’
     10 |     BAR ();
        |     ^~~

and after the patch we emit:

  8:3: warning: this ‘while’ clause does not guard... [-Wmisleading-indentation]
      8 |   WHILE (true)
        |   ^~~~~
  10:5: note: ...this statement, but the latter is misleadingly indented as if 
it were guarded by the ‘while’
     10 |     BAR ();
        |     ^~~

gcc/c-family/ChangeLog:

        * c-indentation.c (should_warn_for_misleading_indentation): Take
        each token_indent_info argument by reference.  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/testsuite/ChangeLog:

        * 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: Likewise.
---
 gcc/c-family/c-indentation.c                  | 20 +++++++++++++------
 gcc/c-family/c-indentation.h                  |  6 +++---
 .../c-c++-common/Wmisleading-indentation-3.c  |  8 ++------
 .../c-c++-common/Wmisleading-indentation-5.c  | 20 ++++++++-----------
 .../c-c++-common/Wmisleading-indentation.c    | 16 +++++++--------
 5 files changed, 35 insertions(+), 35 deletions(-)

diff --git a/gcc/c-family/c-indentation.c b/gcc/c-family/c-indentation.c
index 8b88a8adc7c..fa864cf2050 100644
--- a/gcc/c-family/c-indentation.c
+++ b/gcc/c-family/c-indentation.c
@@ -209,9 +209,9 @@ 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)
 {
   /* Don't attempt to compare indentation if #line or # 44 "file"-style
      directives are present, suggesting generated code.
@@ -329,6 +329,14 @@ should_warn_for_misleading_indentation (const 
token_indent_info &guard_tinfo,
   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 emphasize the
+     location of 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);
@@ -634,9 +642,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/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
index 12b53569ba7..f694c3935f2 100644
--- a/gcc/testsuite/c-c++-common/Wmisleading-indentation-5.c
+++ b/gcc/testsuite/c-c++-common/Wmisleading-indentation-5.c
@@ -4,10 +4,10 @@
 void foo(void);
 
 void test01(int flag) {
-#define bar() foo() /* { dg-message "this statement" }  */
+#define bar() foo()
   if (flag) /* { dg-warning "does not guard" }  */
     foo();
-    bar(); /* { dg-message "in expansion of macro" }  */
+    bar(); /* { dg-message "this statement" }  */
 #undef bar
 }
 
@@ -20,23 +20,21 @@ void test02(int flag) {
 }
 
 void test03(int flag) {
-#define bar() foo() /* { dg-message "this statement" }  */
+#define bar() foo()
   if (flag) /* { dg-warning "does not guard" }  */
     bar();
-    bar(); /* { dg-message "in expansion of macro" }  */
+    bar(); /* { dg-message "this statement" }  */
 #undef bar
 }
 
 void test04(int flag, int num) {
 #define bar() \
   {            \
-    if (flag)  \
+    if (flag)    /* { dg-warning "does not guard" }  */ \
       num = 0; \
-      num = 1; \
+      num = 1;   /* { dg-message "this statement" }  */ \
   }
   bar();
-/* { dg-warning "does not guard" "" { target *-*-* } .-5 }  */
-/* { dg-message "this statement" "" { target *-*-* } .-4 }  */
 #undef bar
 }
 
@@ -44,13 +42,11 @@ void test05(int flag, int num) {
 #define baz() (num = 1)
 #define bar() \
   {            \
-    if (flag)  \
+    if (flag)    /* { dg-warning "does not guard" }  */ \
       num = 0; \
-      baz();   \
+      baz();     /* { dg-message "this statement" }  */ \
   }
 #define wrapper bar
   wrapper();
-/* { dg-warning "does not guard" "" { target *-*-* } .-6 }  */
-/* { dg-message "this statement" "" { target *-*-* } .-10 }  */
 #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);
   }
-- 
2.28.0.497.g54e85e7af1

> 
> > 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
> 

Reply via email to