testsuite: add coverage for diagnostics relating to inlining (PR tree-optimization/83336)

Message ID 1513025047-19327-1-git-send-email-dmalcolm@redhat.com
State New
Headers show
Series
  • testsuite: add coverage for diagnostics relating to inlining (PR tree-optimization/83336)
Related show

Commit Message

David Malcolm Dec. 11, 2017, 8:44 p.m.
In theory, the diagnostics subsystem can print context information on
code inlining when diagnostics are emitted by the middle-end, describing
the chain of inlined callsites that led to a particular warning,
but PR tree-optimization/83336 describes various issues with this.

An underlying issue is that we have very little automated testing for
this code: gcc.dg/tm/pr52141.c has a test, but in general, prune.exp
filters out the various "inlined from" lines.

The following patch adds test coverage for it for C and C++ via a new
testsuite plugin, which emits a warning from the middle-end; the test
cases use dg-regexp to verify that the "inlined from" lines are
emitted correctly, with the correct function names and source locations.

Doing so requires a change to prune.exp: the dg-regexp lines have to
be handled *before* the "inlined from" lines are stripped.

(I have various followups, but establishing automated test coverage
seems like an important first step)

Successfully bootstrapped&regrtested on x86_64-pc-linux-gnu; adds
7 PASS results to g++.sum and 31 PASS results to gcc.sum.

OK for trunk?

gcc/testsuite/ChangeLog:
	PR tree-optimization/83336
	* g++.dg/cpp0x/missing-initializer_list-include.C: Update for
	changes to prune.exp's handling of dg-regexp.
	* g++.dg/plugin/diagnostic-test-inlining-1.C: New test case.
	* g++.dg/plugin/plugin.exp (plugin_test_list): Add it, via
	gcc.dg's plugin/diagnostic_plugin_test_inlining.c.
	* gcc.dg/plugin/diagnostic-test-inlining-1.c: New test case.
	* gcc.dg/plugin/diagnostic-test-inlining-2.c: Likewise.
	* gcc.dg/plugin/diagnostic-test-inlining-3.c: Likewise.
	* gcc.dg/plugin/diagnostic-test-inlining-4.c: Likewise.
	* gcc.dg/plugin/diagnostic_plugin_test_inlining.c: New test
	plugin.
	* gcc.dg/plugin/plugin.exp (plugin_test_list): Add them.
	* lib/prune.exp (prune_gcc_output): Move call to handle-dg-regexps
	to before the various text stripping regsup invocations,
	in particular, to before the stripping of "inlined from".
---
 .../cpp0x/missing-initializer_list-include.C       |   1 +
 .../g++.dg/plugin/diagnostic-test-inlining-1.C     |  34 ++++
 gcc/testsuite/g++.dg/plugin/plugin.exp             |   2 +
 .../gcc.dg/plugin/diagnostic-test-inlining-1.c     |  34 ++++
 .../gcc.dg/plugin/diagnostic-test-inlining-2.c     |  48 ++++++
 .../gcc.dg/plugin/diagnostic-test-inlining-3.c     |  43 +++++
 .../gcc.dg/plugin/diagnostic-test-inlining-4.c     |  56 +++++++
 .../plugin/diagnostic_plugin_test_inlining.c       | 180 +++++++++++++++++++++
 gcc/testsuite/gcc.dg/plugin/plugin.exp             |   5 +
 gcc/testsuite/lib/prune.exp                        |   6 +-
 10 files changed, 406 insertions(+), 3 deletions(-)
 create mode 100644 gcc/testsuite/g++.dg/plugin/diagnostic-test-inlining-1.C
 create mode 100644 gcc/testsuite/gcc.dg/plugin/diagnostic-test-inlining-1.c
 create mode 100644 gcc/testsuite/gcc.dg/plugin/diagnostic-test-inlining-2.c
 create mode 100644 gcc/testsuite/gcc.dg/plugin/diagnostic-test-inlining-3.c
 create mode 100644 gcc/testsuite/gcc.dg/plugin/diagnostic-test-inlining-4.c
 create mode 100644 gcc/testsuite/gcc.dg/plugin/diagnostic_plugin_test_inlining.c

-- 
1.8.5.3

Comments

David Malcolm Dec. 18, 2017, 5:14 p.m. | #1
Is the tweak to prune.exp at the end of this patch OK?  (I can self-
approve the rest of this).


On Mon, 2017-12-11 at 15:44 -0500, David Malcolm wrote:
> In theory, the diagnostics subsystem can print context information on

> code inlining when diagnostics are emitted by the middle-end,

> describing

> the chain of inlined callsites that led to a particular warning,

> but PR tree-optimization/83336 describes various issues with this.

> 

> An underlying issue is that we have very little automated testing for

> this code: gcc.dg/tm/pr52141.c has a test, but in general, prune.exp

> filters out the various "inlined from" lines.

> 

> The following patch adds test coverage for it for C and C++ via a new

> testsuite plugin, which emits a warning from the middle-end; the test

> cases use dg-regexp to verify that the "inlined from" lines are

> emitted correctly, with the correct function names and source

> locations.

> 

> Doing so requires a change to prune.exp: the dg-regexp lines have to

> be handled *before* the "inlined from" lines are stripped.

> 

> (I have various followups, but establishing automated test coverage

> seems like an important first step)

> 

> Successfully bootstrapped&regrtested on x86_64-pc-linux-gnu; adds

> 7 PASS results to g++.sum and 31 PASS results to gcc.sum.

> 

> OK for trunk?

> 

> gcc/testsuite/ChangeLog:

> 	PR tree-optimization/83336

> 	* g++.dg/cpp0x/missing-initializer_list-include.C: Update for

> 	changes to prune.exp's handling of dg-regexp.

> 	* g++.dg/plugin/diagnostic-test-inlining-1.C: New test case.

> 	* g++.dg/plugin/plugin.exp (plugin_test_list): Add it, via

> 	gcc.dg's plugin/diagnostic_plugin_test_inlining.c.

> 	* gcc.dg/plugin/diagnostic-test-inlining-1.c: New test case.

> 	* gcc.dg/plugin/diagnostic-test-inlining-2.c: Likewise.

> 	* gcc.dg/plugin/diagnostic-test-inlining-3.c: Likewise.

> 	* gcc.dg/plugin/diagnostic-test-inlining-4.c: Likewise.

> 	* gcc.dg/plugin/diagnostic_plugin_test_inlining.c: New test

> 	plugin.

> 	* gcc.dg/plugin/plugin.exp (plugin_test_list): Add them.

> 	* lib/prune.exp (prune_gcc_output): Move call to handle-dg-

> regexps

> 	to before the various text stripping regsup invocations,

> 	in particular, to before the stripping of "inlined from".

> ---

>  .../cpp0x/missing-initializer_list-include.C       |   1 +

>  .../g++.dg/plugin/diagnostic-test-inlining-1.C     |  34 ++++

>  gcc/testsuite/g++.dg/plugin/plugin.exp             |   2 +

>  .../gcc.dg/plugin/diagnostic-test-inlining-1.c     |  34 ++++

>  .../gcc.dg/plugin/diagnostic-test-inlining-2.c     |  48 ++++++

>  .../gcc.dg/plugin/diagnostic-test-inlining-3.c     |  43 +++++

>  .../gcc.dg/plugin/diagnostic-test-inlining-4.c     |  56 +++++++

>  .../plugin/diagnostic_plugin_test_inlining.c       | 180

> +++++++++++++++++++++

>  gcc/testsuite/gcc.dg/plugin/plugin.exp             |   5 +

>  gcc/testsuite/lib/prune.exp                        |   6 +-

>  10 files changed, 406 insertions(+), 3 deletions(-)

>  create mode 100644 gcc/testsuite/g++.dg/plugin/diagnostic-test-

> inlining-1.C

>  create mode 100644 gcc/testsuite/gcc.dg/plugin/diagnostic-test-

> inlining-1.c

>  create mode 100644 gcc/testsuite/gcc.dg/plugin/diagnostic-test-

> inlining-2.c

>  create mode 100644 gcc/testsuite/gcc.dg/plugin/diagnostic-test-

> inlining-3.c

>  create mode 100644 gcc/testsuite/gcc.dg/plugin/diagnostic-test-

> inlining-4.c

>  create mode 100644

> gcc/testsuite/gcc.dg/plugin/diagnostic_plugin_test_inlining.c

> 

> diff --git a/gcc/testsuite/g++.dg/cpp0x/missing-initializer_list-

> include.C b/gcc/testsuite/g++.dg/cpp0x/missing-initializer_list-

> include.C

> index 7d72ec4..1010b0a 100644

> --- a/gcc/testsuite/g++.dg/cpp0x/missing-initializer_list-include.C

> +++ b/gcc/testsuite/g++.dg/cpp0x/missing-initializer_list-include.C

> @@ -24,5 +24,6 @@ void test (int i)

>  +#include <initializer_list>

>   /* This is padding (to avoid the generated patch containing DejaGnu

>      directives).  */

> + 

>  { dg-end-multiline-output "" }

>  #endif

> diff --git a/gcc/testsuite/g++.dg/plugin/diagnostic-test-inlining-1.C 

> b/gcc/testsuite/g++.dg/plugin/diagnostic-test-inlining-1.C

> new file mode 100644

> index 0000000..df7bb1f

> --- /dev/null

> +++ b/gcc/testsuite/g++.dg/plugin/diagnostic-test-inlining-1.C

> @@ -0,0 +1,34 @@

> +/* { dg-do compile } */

> +/* { dg-options "-Wno-attributes -fdiagnostics-show-caret" } */

> +

> +extern void __emit_warning (const char *message);

> +

> +/* Verify that the diagnostic subsytem describes the chain of

> inlining

> +   when reporting the warning.  */

> +

> +__attribute__((always_inline))

> +static void foo (void)

> +{

> +  __emit_warning ("message");

> +}

> +

> +__attribute__((always_inline))

> +static void bar (void)

> +{

> +  foo ();

> +}

> +

> +int main()

> +{

> +  bar ();

> +  return 0;

> +}

> +

> +/* { dg-regexp "In function 'void foo\\(\\)'," "" } */

> +/* { dg-regexp "    inlined from 'void bar\\(\\)' at .+/diagnostic-

> test-inlining-1.C:18:7," "" } */

> +/* { dg-regexp "    inlined from 'int main\\(\\)' at .+/diagnostic-

> test-inlining-1.C:23:7:" "" } */

> +/* { dg-warning "18: message" "" { target *-*-* } 12 } */

> +/* { dg-begin-multiline-output "" }

> +   __emit_warning ("message");

> +   ~~~~~~~~~~~~~~~^~~~~~~~~~~

> +   { dg-end-multiline-output "" } */

> diff --git a/gcc/testsuite/g++.dg/plugin/plugin.exp

> b/gcc/testsuite/g++.dg/plugin/plugin.exp

> index e40cba3..4f9ce16 100644

> --- a/gcc/testsuite/g++.dg/plugin/plugin.exp

> +++ b/gcc/testsuite/g++.dg/plugin/plugin.exp

> @@ -65,6 +65,8 @@ set plugin_test_list [list \

>      { def_plugin.c def-plugin-test.C } \

>      {

> ../../gcc.dg/plugin/diagnostic_plugin_test_tree_expression_range.c \

>  	  diagnostic-test-expressions-1.C } \

> +    { ../../gcc.dg/plugin/diagnostic_plugin_test_inlining.c \

> +	  diagnostic-test-inlining-1.C } \

>      { show_template_tree_color_plugin.c \

>      	  show-template-tree-color.C \

>      	  show-template-tree-color-no-elide-type.C } \

> diff --git a/gcc/testsuite/gcc.dg/plugin/diagnostic-test-inlining-1.c 

> b/gcc/testsuite/gcc.dg/plugin/diagnostic-test-inlining-1.c

> new file mode 100644

> index 0000000..a24b7f8

> --- /dev/null

> +++ b/gcc/testsuite/gcc.dg/plugin/diagnostic-test-inlining-1.c

> @@ -0,0 +1,34 @@

> +/* { dg-do compile } */

> +/* { dg-options "-Wno-attributes -fdiagnostics-show-caret" } */

> +

> +extern void __emit_warning (const char *message);

> +

> +__attribute__((always_inline))

> +static void foo (void)

> +{

> +  __emit_warning ("message");

> +}

> +

> +__attribute__((always_inline))

> +static void bar (void)

> +{

> +  foo ();

> +}

> +

> +int main()

> +{

> +  bar ();

> +  return 0;

> +}

> +

> +/* Verify that the diagnostic subsytem describes the chain of

> inlining

> +   when reporting the warning.  */

> +

> +/* { dg-regexp "In function 'foo'," "" } */

> +/* { dg-regexp "    inlined from 'bar' at .+/diagnostic-test-

> inlining-1.c:15:3," "" } */

> +/* { dg-regexp "    inlined from 'main' at .+/diagnostic-test-

> inlining-1.c:20:3:" "" } */

> +/* { dg-warning "3: message" "" { target *-*-* } 9 } */

> +/* { dg-begin-multiline-output "" }

> +   __emit_warning ("message");

> +   ^~~~~~~~~~~~~~~~~~~~~~~~~~

> +   { dg-end-multiline-output "" } */

> diff --git a/gcc/testsuite/gcc.dg/plugin/diagnostic-test-inlining-2.c 

> b/gcc/testsuite/gcc.dg/plugin/diagnostic-test-inlining-2.c

> new file mode 100644

> index 0000000..52e4825

> --- /dev/null

> +++ b/gcc/testsuite/gcc.dg/plugin/diagnostic-test-inlining-2.c

> @@ -0,0 +1,48 @@

> +/* { dg-do compile } */

> +/* { dg-options "-Wno-attributes -fdiagnostics-show-caret" } */

> +

> +extern void __emit_warning (const char *message);

> +

> +#define INNER_WARNING(MSG) __emit_warning (MSG)

> +

> +#define OUTER_WARNING(MSG) INNER_WARNING (MSG)

> +

> +__attribute__((always_inline))

> +static void foo (void)

> +{

> +  OUTER_WARNING ("message");

> +}

> +

> +__attribute__((always_inline))

> +static void bar (void)

> +{

> +  foo ();

> +}

> +

> +int main()

> +{

> +  bar ();

> +  return 0;

> +}

> +

> +/* Verify that the diagnostic subsytem describes both the chains of

> +   inlining and of macro expansion when reporting the warning.  */

> +

> +/* { dg-regexp "In function 'foo'," "" } */

> +/* { dg-regexp "    inlined from 'bar' at .+/diagnostic-test-

> inlining-2.c:19:3," "" } */

> +/* { dg-regexp "    inlined from 'main' at .+/diagnostic-test-

> inlining-2.c:24:3:" "" } */

> +/* { dg-warning "28: message" "" { target c } 6 } */

> +/* { dg-begin-multiline-output "" }

> + #define INNER_WARNING(MSG) __emit_warning (MSG)

> +                            ^~~~~~~~~~~~~~~~~~~~

> +   { dg-end-multiline-output "" } */

> +/* { dg-message "28: in expansion of macro 'INNER_WARNING'" "" {

> target c } 8 } */

> +/* { dg-begin-multiline-output "" }

> + #define OUTER_WARNING(MSG) INNER_WARNING (MSG)

> +                            ^~~~~~~~~~~~~

> +   { dg-end-multiline-output "" } */

> +/* { dg-message "3: in expansion of macro 'OUTER_WARNING'" "" {

> target c } 13 } */

> +/* { dg-begin-multiline-output "" }

> +   OUTER_WARNING ("message");

> +   ^~~~~~~~~~~~~

> +   { dg-end-multiline-output "" } */

> diff --git a/gcc/testsuite/gcc.dg/plugin/diagnostic-test-inlining-3.c 

> b/gcc/testsuite/gcc.dg/plugin/diagnostic-test-inlining-3.c

> new file mode 100644

> index 0000000..e1a4fca

> --- /dev/null

> +++ b/gcc/testsuite/gcc.dg/plugin/diagnostic-test-inlining-3.c

> @@ -0,0 +1,43 @@

> +/* { dg-do compile } */

> +/* { dg-options "-Wno-attributes -fdiagnostics-show-caret -O1" } */

> +

> +extern void __emit_warning (const char *message);

> +

> +__attribute__((always_inline))

> +static void foo (void)

> +{

> +  __emit_warning ("message");

> +}

> +

> +__attribute__((always_inline))

> +static void bar (void)

> +{

> +  foo ();

> +}

> +

> +int main()

> +{

> +  bar ();

> +  return 0;

> +}

> +

> +/* Reproducer for PR tree-optimization/83336: when optimization is

> +   enabled, but debuginfo isn't, the diagnostics subsystem doesn't

> +   report the full inlining chain at a middle-end warning.

> +

> +   This is a copy of diagnostic-test-inlining-1.c, but with -O1.

> +

> +   Ideally the diagnostics subsystem would report:

> +     In function 'foo', inlined from 'bar' at LOC A, inlined from

> 'main' at LOC B:

> +   but with -O1 it only reports:

> +     In function 'foo', inlined from 'main' at LOC A:

> +

> +   This test case captures this behavior.  */

> +

> +/* { dg-regexp "In function 'foo'," "" } */

> +/* { dg-regexp "    inlined from 'main' at .+/diagnostic-test-

> inlining-3.c:15:3:" "" } */

> +/* { dg-warning "3: message" "" { target *-*-* } 9 } */

> +/* { dg-begin-multiline-output "" }

> +   __emit_warning ("message");

> +   ^~~~~~~~~~~~~~~~~~~~~~~~~~

> +   { dg-end-multiline-output "" } */

> diff --git a/gcc/testsuite/gcc.dg/plugin/diagnostic-test-inlining-4.c 

> b/gcc/testsuite/gcc.dg/plugin/diagnostic-test-inlining-4.c

> new file mode 100644

> index 0000000..dfb939d

> --- /dev/null

> +++ b/gcc/testsuite/gcc.dg/plugin/diagnostic-test-inlining-4.c

> @@ -0,0 +1,56 @@

> +/* { dg-do compile } */

> +/* { dg-options "-Wno-attributes -fdiagnostics-show-caret" } */

> +

> +extern void __emit_warning (const char *message);

> +

> +__attribute__((always_inline))

> +static void depth_0 (void)

> +{

> +  __emit_warning ("message");

> +}

> +

> +__attribute__((always_inline))

> +static void depth_1 (void)

> +{

> +  depth_0 ();

> +}

> +

> +__attribute__((always_inline))

> +static void depth_2 (void)

> +{

> +  depth_1 ();

> +}

> +

> +__attribute__((always_inline))

> +static void depth_3 (void)

> +{

> +  depth_2 ();

> +}

> +

> +__attribute__((always_inline))

> +static void depth_4 (void)

> +{

> +  depth_3 ();

> +}

> +

> +int main()

> +{

> +  depth_4 ();

> +  return 0;

> +}

> +

> +/* Verify that the diagnostic subsytem describes the chain of

> inlining

> +   when reporting the warning, for an example showing many levels of

> +   inlining.  */

> +

> +/* { dg-regexp "In function 'depth_0'," "" } */

> +/* { dg-regexp "    inlined from 'depth_1' at .+/diagnostic-test-

> inlining-4.c:15:3," "" } */

> +/* { dg-regexp "    inlined from 'depth_2' at .+/diagnostic-test-

> inlining-4.c:21:3," "" } */

> +/* { dg-regexp "    inlined from 'depth_3' at .+/diagnostic-test-

> inlining-4.c:27:3," "" } */

> +/* { dg-regexp "    inlined from 'depth_4' at .+/diagnostic-test-

> inlining-4.c:33:3," "" } */

> +/* { dg-regexp "    inlined from 'main' at .+/diagnostic-test-

> inlining-4.c:38:3:" "" } */

> +/* { dg-warning "3: message" "" { target *-*-* } 9 } */

> +/* { dg-begin-multiline-output "" }

> +   __emit_warning ("message");

> +   ^~~~~~~~~~~~~~~~~~~~~~~~~~

> +   { dg-end-multiline-output "" } */

> diff --git

> a/gcc/testsuite/gcc.dg/plugin/diagnostic_plugin_test_inlining.c

> b/gcc/testsuite/gcc.dg/plugin/diagnostic_plugin_test_inlining.c

> new file mode 100644

> index 0000000..49b78cc

> --- /dev/null

> +++ b/gcc/testsuite/gcc.dg/plugin/diagnostic_plugin_test_inlining.c

> @@ -0,0 +1,180 @@

> +/* { dg-options "-O" } */

> +

> +#include "gcc-plugin.h"

> +#include "config.h"

> +#include "system.h"

> +#include "coretypes.h"

> +#include "tm.h"

> +#include "tree.h"

> +#include "stringpool.h"

> +#include "toplev.h"

> +#include "basic-block.h"

> +#include "hash-table.h"

> +#include "vec.h"

> +#include "ggc.h"

> +#include "basic-block.h"

> +#include "tree-ssa-alias.h"

> +#include "internal-fn.h"

> +#include "gimple-fold.h"

> +#include "tree-eh.h"

> +#include "gimple-expr.h"

> +#include "is-a.h"

> +#include "gimple.h"

> +#include "gimple-iterator.h"

> +#include "tree.h"

> +#include "tree-pass.h"

> +#include "intl.h"

> +#include "plugin-version.h"

> +#include "c-family/c-common.h"

> +#include "diagnostic.h"

> +#include "context.h"

> +#include "print-tree.h"

> +#include "cpplib.h"

> +#include "c-family/c-pragma.h"

> +#include "substring-locations.h"

> +

> +int plugin_is_GPL_compatible;

> +

> +/* A custom pass for emitting dummy warnings from the middle-

> end.  */

> +

> +const pass_data pass_data_test_inlining =

> +{

> +  GIMPLE_PASS, /* type */

> +  "test_inlining", /* name */

> +  OPTGROUP_NONE, /* optinfo_flags */

> +  TV_NONE, /* tv_id */

> +  PROP_ssa, /* properties_required */

> +  0, /* properties_provided */

> +  0, /* properties_destroyed */

> +  0, /* todo_flags_start */

> +  0, /* todo_flags_finish */

> +};

> +

> +class pass_test_inlining : public gimple_opt_pass

> +{

> +public:

> +  pass_test_inlining(gcc::context *ctxt)

> +    : gimple_opt_pass(pass_data_test_inlining, ctxt)

> +  {}

> +

> +  /* opt_pass methods: */

> +  bool gate (function *) { return true; }

> +  virtual unsigned int execute (function *);

> +

> +}; // class pass_test_inlining

> +

> +/* Determine if STMT is a call with NUM_ARGS arguments to a function

> +   named FUNCNAME.

> +   If so, return STMT as a gcall *.  Otherwise return NULL.  */

> +

> +static gcall *

> +check_for_named_call (gimple *stmt,

> +		      const char *funcname, unsigned int num_args)

> +{

> +  gcc_assert (funcname);

> +

> +  gcall *call = dyn_cast <gcall *> (stmt);

> +  if (!call)

> +    return NULL;

> +

> +  tree fndecl = gimple_call_fndecl (call);

> +  if (!fndecl)

> +    return NULL;

> +

> +  if (strcmp (IDENTIFIER_POINTER (DECL_NAME (fndecl)), funcname))

> +    return NULL;

> +

> +  if (gimple_call_num_args (call) != num_args)

> +    {

> +      error_at (stmt->location, "expected number of args: %i (got

> %i)",

> +		num_args, gimple_call_num_args (call));

> +      return NULL;

> +    }

> +

> +  return call;

> +}

> +

> +/* Emit a warning at LOC.  */

> +

> +static void

> +emit_warning (location_t loc)

> +{

> +  source_range src_range = get_range_from_loc (line_table, loc);

> +  warning_at (loc, 0, "range %i:%i-%i:%i",

> +	      LOCATION_LINE (src_range.m_start),

> +	      LOCATION_COLUMN (src_range.m_start),

> +	      LOCATION_LINE (src_range.m_finish),

> +	      LOCATION_COLUMN (src_range.m_finish));

> +}

> +

> +/* Code for simulating the emission of a warning from the middle-

> end.

> +   Emit a warning for each call to a function named

> "__emit_warning".  */

> +

> +static void

> +test_inlining (gimple *stmt)

> +{

> +  gcall *call = check_for_named_call (stmt, "__emit_warning", 1);

> +  if (!call)

> +    return;

> +

> +  /* We expect an ADDR_EXPR with a STRING_CST inside it for the

> +     initial arg.  */

> +  tree t_addr_string = gimple_call_arg (call, 0);

> +  if (TREE_CODE (t_addr_string) != ADDR_EXPR)

> +    {

> +      error_at (call->location, "string literal required for arg

> 1");

> +      return;

> +    }

> +

> +  tree t_string = TREE_OPERAND (t_addr_string, 0);

> +  if (TREE_CODE (t_string) != STRING_CST)

> +    {

> +      error_at (call->location, "string literal required for arg

> 1");

> +      return;

> +    }

> +

> +  warning_at (call->location, 0, "%G%s", call,

> +	      TREE_STRING_POINTER (t_string));

> +}

> +

> +/* Call test_inlining on every statement within FUN.  */

> +

> +unsigned int

> +pass_test_inlining::execute (function *fun)

> +{

> +  gimple_stmt_iterator gsi;

> +  basic_block bb;

> +

> +  FOR_EACH_BB_FN (bb, fun)

> +    for (gsi = gsi_start_bb (bb); !gsi_end_p (gsi); gsi_next (&gsi))

> +      {

> +	gimple *stmt = gsi_stmt (gsi);

> +	test_inlining (stmt);

> +      }

> +

> +  return 0;

> +}

> +

> +/* Entrypoint for the plugin.  Create and register the custom

> pass.  */

> +

> +int

> +plugin_init (struct plugin_name_args *plugin_info,

> +	     struct plugin_gcc_version *version)

> +{

> +  struct register_pass_info pass_info;

> +  const char *plugin_name = plugin_info->base_name;

> +  int argc = plugin_info->argc;

> +  struct plugin_argument *argv = plugin_info->argv;

> +

> +  if (!plugin_default_version_check (version, &gcc_version))

> +    return 1;

> +

> +  pass_info.pass = new pass_test_inlining (g);

> +  pass_info.reference_pass_name = "*warn_function_noreturn";

> +  pass_info.ref_pass_instance_number = 1;

> +  pass_info.pos_op = PASS_POS_INSERT_AFTER;

> +  register_callback (plugin_name, PLUGIN_PASS_MANAGER_SETUP, NULL,

> +		     &pass_info);

> +

> +  return 0;

> +}

> diff --git a/gcc/testsuite/gcc.dg/plugin/plugin.exp

> b/gcc/testsuite/gcc.dg/plugin/plugin.exp

> index ff3c976..9da17d0 100644

> --- a/gcc/testsuite/gcc.dg/plugin/plugin.exp

> +++ b/gcc/testsuite/gcc.dg/plugin/plugin.exp

> @@ -76,6 +76,11 @@ set plugin_test_list [list \

>  	  diagnostic-test-string-literals-2.c \

>  	  diagnostic-test-string-literals-3.c \

>  	  diagnostic-test-string-literals-4.c } \

> +    { diagnostic_plugin_test_inlining.c \

> +	  diagnostic-test-inlining-1.c \

> +	  diagnostic-test-inlining-2.c \

> +	  diagnostic-test-inlining-3.c \

> +	  diagnostic-test-inlining-4.c } \

>      { location_overflow_plugin.c \

>  	  location-overflow-test-1.c \

>  	  location-overflow-test-2.c } \

> diff --git a/gcc/testsuite/lib/prune.exp

> b/gcc/testsuite/lib/prune.exp

> index afc1a69..b771da2 100644

> --- a/gcc/testsuite/lib/prune.exp

> +++ b/gcc/testsuite/lib/prune.exp

> @@ -28,6 +28,9 @@ proc prune_gcc_output { text } {

>  

>      #send_user "Before:$text\n"

>  

> +    # Handle any freeform regexps.

> +    set text [handle-dg-regexps $text]

> +

>      regsub -all "(^|\n)(\[^\n\]*: )?In ((static member |lambda

> )?function|member|method|(copy

> )?constructor|destructor|instantiation|substitution|program|subroutin

> e|block-data)\[^\n\]*" $text "" text

>      regsub -all "(^|\n)\[^\n\]*(: )?At (top level|global

> scope):\[^\n\]*" $text "" text

>      regsub -all "(^|\n)\[^\n\]*:   (recursively )?required \[^\n\]*"

> $text "" text

> @@ -73,9 +76,6 @@ proc prune_gcc_output { text } {

>      # Call into multiline.exp to handle any multiline output

> directives.

>      set text [handle-multiline-outputs $text]

>  

> -    # Handle any freeform regexps.

> -    set text [handle-dg-regexps $text]

> -

>      #send_user "After:$text\n"

>  

>      return $text
Jeff Law Dec. 18, 2017, 6:25 p.m. | #2
On 12/18/2017 10:14 AM, David Malcolm wrote:
> Is the tweak to prune.exp at the end of this patch OK?  (I can self-

> approve the rest of this).

Yes.
jeff

Patch

diff --git a/gcc/testsuite/g++.dg/cpp0x/missing-initializer_list-include.C b/gcc/testsuite/g++.dg/cpp0x/missing-initializer_list-include.C
index 7d72ec4..1010b0a 100644
--- a/gcc/testsuite/g++.dg/cpp0x/missing-initializer_list-include.C
+++ b/gcc/testsuite/g++.dg/cpp0x/missing-initializer_list-include.C
@@ -24,5 +24,6 @@  void test (int i)
 +#include <initializer_list>
  /* This is padding (to avoid the generated patch containing DejaGnu
     directives).  */
+ 
 { dg-end-multiline-output "" }
 #endif
diff --git a/gcc/testsuite/g++.dg/plugin/diagnostic-test-inlining-1.C b/gcc/testsuite/g++.dg/plugin/diagnostic-test-inlining-1.C
new file mode 100644
index 0000000..df7bb1f
--- /dev/null
+++ b/gcc/testsuite/g++.dg/plugin/diagnostic-test-inlining-1.C
@@ -0,0 +1,34 @@ 
+/* { dg-do compile } */
+/* { dg-options "-Wno-attributes -fdiagnostics-show-caret" } */
+
+extern void __emit_warning (const char *message);
+
+/* Verify that the diagnostic subsytem describes the chain of inlining
+   when reporting the warning.  */
+
+__attribute__((always_inline))
+static void foo (void)
+{
+  __emit_warning ("message");
+}
+
+__attribute__((always_inline))
+static void bar (void)
+{
+  foo ();
+}
+
+int main()
+{
+  bar ();
+  return 0;
+}
+
+/* { dg-regexp "In function 'void foo\\(\\)'," "" } */
+/* { dg-regexp "    inlined from 'void bar\\(\\)' at .+/diagnostic-test-inlining-1.C:18:7," "" } */
+/* { dg-regexp "    inlined from 'int main\\(\\)' at .+/diagnostic-test-inlining-1.C:23:7:" "" } */
+/* { dg-warning "18: message" "" { target *-*-* } 12 } */
+/* { dg-begin-multiline-output "" }
+   __emit_warning ("message");
+   ~~~~~~~~~~~~~~~^~~~~~~~~~~
+   { dg-end-multiline-output "" } */
diff --git a/gcc/testsuite/g++.dg/plugin/plugin.exp b/gcc/testsuite/g++.dg/plugin/plugin.exp
index e40cba3..4f9ce16 100644
--- a/gcc/testsuite/g++.dg/plugin/plugin.exp
+++ b/gcc/testsuite/g++.dg/plugin/plugin.exp
@@ -65,6 +65,8 @@  set plugin_test_list [list \
     { def_plugin.c def-plugin-test.C } \
     { ../../gcc.dg/plugin/diagnostic_plugin_test_tree_expression_range.c \
 	  diagnostic-test-expressions-1.C } \
+    { ../../gcc.dg/plugin/diagnostic_plugin_test_inlining.c \
+	  diagnostic-test-inlining-1.C } \
     { show_template_tree_color_plugin.c \
     	  show-template-tree-color.C \
     	  show-template-tree-color-no-elide-type.C } \
diff --git a/gcc/testsuite/gcc.dg/plugin/diagnostic-test-inlining-1.c b/gcc/testsuite/gcc.dg/plugin/diagnostic-test-inlining-1.c
new file mode 100644
index 0000000..a24b7f8
--- /dev/null
+++ b/gcc/testsuite/gcc.dg/plugin/diagnostic-test-inlining-1.c
@@ -0,0 +1,34 @@ 
+/* { dg-do compile } */
+/* { dg-options "-Wno-attributes -fdiagnostics-show-caret" } */
+
+extern void __emit_warning (const char *message);
+
+__attribute__((always_inline))
+static void foo (void)
+{
+  __emit_warning ("message");
+}
+
+__attribute__((always_inline))
+static void bar (void)
+{
+  foo ();
+}
+
+int main()
+{
+  bar ();
+  return 0;
+}
+
+/* Verify that the diagnostic subsytem describes the chain of inlining
+   when reporting the warning.  */
+
+/* { dg-regexp "In function 'foo'," "" } */
+/* { dg-regexp "    inlined from 'bar' at .+/diagnostic-test-inlining-1.c:15:3," "" } */
+/* { dg-regexp "    inlined from 'main' at .+/diagnostic-test-inlining-1.c:20:3:" "" } */
+/* { dg-warning "3: message" "" { target *-*-* } 9 } */
+/* { dg-begin-multiline-output "" }
+   __emit_warning ("message");
+   ^~~~~~~~~~~~~~~~~~~~~~~~~~
+   { dg-end-multiline-output "" } */
diff --git a/gcc/testsuite/gcc.dg/plugin/diagnostic-test-inlining-2.c b/gcc/testsuite/gcc.dg/plugin/diagnostic-test-inlining-2.c
new file mode 100644
index 0000000..52e4825
--- /dev/null
+++ b/gcc/testsuite/gcc.dg/plugin/diagnostic-test-inlining-2.c
@@ -0,0 +1,48 @@ 
+/* { dg-do compile } */
+/* { dg-options "-Wno-attributes -fdiagnostics-show-caret" } */
+
+extern void __emit_warning (const char *message);
+
+#define INNER_WARNING(MSG) __emit_warning (MSG)
+
+#define OUTER_WARNING(MSG) INNER_WARNING (MSG)
+
+__attribute__((always_inline))
+static void foo (void)
+{
+  OUTER_WARNING ("message");
+}
+
+__attribute__((always_inline))
+static void bar (void)
+{
+  foo ();
+}
+
+int main()
+{
+  bar ();
+  return 0;
+}
+
+/* Verify that the diagnostic subsytem describes both the chains of
+   inlining and of macro expansion when reporting the warning.  */
+
+/* { dg-regexp "In function 'foo'," "" } */
+/* { dg-regexp "    inlined from 'bar' at .+/diagnostic-test-inlining-2.c:19:3," "" } */
+/* { dg-regexp "    inlined from 'main' at .+/diagnostic-test-inlining-2.c:24:3:" "" } */
+/* { dg-warning "28: message" "" { target c } 6 } */
+/* { dg-begin-multiline-output "" }
+ #define INNER_WARNING(MSG) __emit_warning (MSG)
+                            ^~~~~~~~~~~~~~~~~~~~
+   { dg-end-multiline-output "" } */
+/* { dg-message "28: in expansion of macro 'INNER_WARNING'" "" { target c } 8 } */
+/* { dg-begin-multiline-output "" }
+ #define OUTER_WARNING(MSG) INNER_WARNING (MSG)
+                            ^~~~~~~~~~~~~
+   { dg-end-multiline-output "" } */
+/* { dg-message "3: in expansion of macro 'OUTER_WARNING'" "" { target c } 13 } */
+/* { dg-begin-multiline-output "" }
+   OUTER_WARNING ("message");
+   ^~~~~~~~~~~~~
+   { dg-end-multiline-output "" } */
diff --git a/gcc/testsuite/gcc.dg/plugin/diagnostic-test-inlining-3.c b/gcc/testsuite/gcc.dg/plugin/diagnostic-test-inlining-3.c
new file mode 100644
index 0000000..e1a4fca
--- /dev/null
+++ b/gcc/testsuite/gcc.dg/plugin/diagnostic-test-inlining-3.c
@@ -0,0 +1,43 @@ 
+/* { dg-do compile } */
+/* { dg-options "-Wno-attributes -fdiagnostics-show-caret -O1" } */
+
+extern void __emit_warning (const char *message);
+
+__attribute__((always_inline))
+static void foo (void)
+{
+  __emit_warning ("message");
+}
+
+__attribute__((always_inline))
+static void bar (void)
+{
+  foo ();
+}
+
+int main()
+{
+  bar ();
+  return 0;
+}
+
+/* Reproducer for PR tree-optimization/83336: when optimization is
+   enabled, but debuginfo isn't, the diagnostics subsystem doesn't
+   report the full inlining chain at a middle-end warning.
+
+   This is a copy of diagnostic-test-inlining-1.c, but with -O1.
+
+   Ideally the diagnostics subsystem would report:
+     In function 'foo', inlined from 'bar' at LOC A, inlined from 'main' at LOC B:
+   but with -O1 it only reports:
+     In function 'foo', inlined from 'main' at LOC A:
+
+   This test case captures this behavior.  */
+
+/* { dg-regexp "In function 'foo'," "" } */
+/* { dg-regexp "    inlined from 'main' at .+/diagnostic-test-inlining-3.c:15:3:" "" } */
+/* { dg-warning "3: message" "" { target *-*-* } 9 } */
+/* { dg-begin-multiline-output "" }
+   __emit_warning ("message");
+   ^~~~~~~~~~~~~~~~~~~~~~~~~~
+   { dg-end-multiline-output "" } */
diff --git a/gcc/testsuite/gcc.dg/plugin/diagnostic-test-inlining-4.c b/gcc/testsuite/gcc.dg/plugin/diagnostic-test-inlining-4.c
new file mode 100644
index 0000000..dfb939d
--- /dev/null
+++ b/gcc/testsuite/gcc.dg/plugin/diagnostic-test-inlining-4.c
@@ -0,0 +1,56 @@ 
+/* { dg-do compile } */
+/* { dg-options "-Wno-attributes -fdiagnostics-show-caret" } */
+
+extern void __emit_warning (const char *message);
+
+__attribute__((always_inline))
+static void depth_0 (void)
+{
+  __emit_warning ("message");
+}
+
+__attribute__((always_inline))
+static void depth_1 (void)
+{
+  depth_0 ();
+}
+
+__attribute__((always_inline))
+static void depth_2 (void)
+{
+  depth_1 ();
+}
+
+__attribute__((always_inline))
+static void depth_3 (void)
+{
+  depth_2 ();
+}
+
+__attribute__((always_inline))
+static void depth_4 (void)
+{
+  depth_3 ();
+}
+
+int main()
+{
+  depth_4 ();
+  return 0;
+}
+
+/* Verify that the diagnostic subsytem describes the chain of inlining
+   when reporting the warning, for an example showing many levels of
+   inlining.  */
+
+/* { dg-regexp "In function 'depth_0'," "" } */
+/* { dg-regexp "    inlined from 'depth_1' at .+/diagnostic-test-inlining-4.c:15:3," "" } */
+/* { dg-regexp "    inlined from 'depth_2' at .+/diagnostic-test-inlining-4.c:21:3," "" } */
+/* { dg-regexp "    inlined from 'depth_3' at .+/diagnostic-test-inlining-4.c:27:3," "" } */
+/* { dg-regexp "    inlined from 'depth_4' at .+/diagnostic-test-inlining-4.c:33:3," "" } */
+/* { dg-regexp "    inlined from 'main' at .+/diagnostic-test-inlining-4.c:38:3:" "" } */
+/* { dg-warning "3: message" "" { target *-*-* } 9 } */
+/* { dg-begin-multiline-output "" }
+   __emit_warning ("message");
+   ^~~~~~~~~~~~~~~~~~~~~~~~~~
+   { dg-end-multiline-output "" } */
diff --git a/gcc/testsuite/gcc.dg/plugin/diagnostic_plugin_test_inlining.c b/gcc/testsuite/gcc.dg/plugin/diagnostic_plugin_test_inlining.c
new file mode 100644
index 0000000..49b78cc
--- /dev/null
+++ b/gcc/testsuite/gcc.dg/plugin/diagnostic_plugin_test_inlining.c
@@ -0,0 +1,180 @@ 
+/* { dg-options "-O" } */
+
+#include "gcc-plugin.h"
+#include "config.h"
+#include "system.h"
+#include "coretypes.h"
+#include "tm.h"
+#include "tree.h"
+#include "stringpool.h"
+#include "toplev.h"
+#include "basic-block.h"
+#include "hash-table.h"
+#include "vec.h"
+#include "ggc.h"
+#include "basic-block.h"
+#include "tree-ssa-alias.h"
+#include "internal-fn.h"
+#include "gimple-fold.h"
+#include "tree-eh.h"
+#include "gimple-expr.h"
+#include "is-a.h"
+#include "gimple.h"
+#include "gimple-iterator.h"
+#include "tree.h"
+#include "tree-pass.h"
+#include "intl.h"
+#include "plugin-version.h"
+#include "c-family/c-common.h"
+#include "diagnostic.h"
+#include "context.h"
+#include "print-tree.h"
+#include "cpplib.h"
+#include "c-family/c-pragma.h"
+#include "substring-locations.h"
+
+int plugin_is_GPL_compatible;
+
+/* A custom pass for emitting dummy warnings from the middle-end.  */
+
+const pass_data pass_data_test_inlining =
+{
+  GIMPLE_PASS, /* type */
+  "test_inlining", /* name */
+  OPTGROUP_NONE, /* optinfo_flags */
+  TV_NONE, /* tv_id */
+  PROP_ssa, /* properties_required */
+  0, /* properties_provided */
+  0, /* properties_destroyed */
+  0, /* todo_flags_start */
+  0, /* todo_flags_finish */
+};
+
+class pass_test_inlining : public gimple_opt_pass
+{
+public:
+  pass_test_inlining(gcc::context *ctxt)
+    : gimple_opt_pass(pass_data_test_inlining, ctxt)
+  {}
+
+  /* opt_pass methods: */
+  bool gate (function *) { return true; }
+  virtual unsigned int execute (function *);
+
+}; // class pass_test_inlining
+
+/* Determine if STMT is a call with NUM_ARGS arguments to a function
+   named FUNCNAME.
+   If so, return STMT as a gcall *.  Otherwise return NULL.  */
+
+static gcall *
+check_for_named_call (gimple *stmt,
+		      const char *funcname, unsigned int num_args)
+{
+  gcc_assert (funcname);
+
+  gcall *call = dyn_cast <gcall *> (stmt);
+  if (!call)
+    return NULL;
+
+  tree fndecl = gimple_call_fndecl (call);
+  if (!fndecl)
+    return NULL;
+
+  if (strcmp (IDENTIFIER_POINTER (DECL_NAME (fndecl)), funcname))
+    return NULL;
+
+  if (gimple_call_num_args (call) != num_args)
+    {
+      error_at (stmt->location, "expected number of args: %i (got %i)",
+		num_args, gimple_call_num_args (call));
+      return NULL;
+    }
+
+  return call;
+}
+
+/* Emit a warning at LOC.  */
+
+static void
+emit_warning (location_t loc)
+{
+  source_range src_range = get_range_from_loc (line_table, loc);
+  warning_at (loc, 0, "range %i:%i-%i:%i",
+	      LOCATION_LINE (src_range.m_start),
+	      LOCATION_COLUMN (src_range.m_start),
+	      LOCATION_LINE (src_range.m_finish),
+	      LOCATION_COLUMN (src_range.m_finish));
+}
+
+/* Code for simulating the emission of a warning from the middle-end.
+   Emit a warning for each call to a function named "__emit_warning".  */
+
+static void
+test_inlining (gimple *stmt)
+{
+  gcall *call = check_for_named_call (stmt, "__emit_warning", 1);
+  if (!call)
+    return;
+
+  /* We expect an ADDR_EXPR with a STRING_CST inside it for the
+     initial arg.  */
+  tree t_addr_string = gimple_call_arg (call, 0);
+  if (TREE_CODE (t_addr_string) != ADDR_EXPR)
+    {
+      error_at (call->location, "string literal required for arg 1");
+      return;
+    }
+
+  tree t_string = TREE_OPERAND (t_addr_string, 0);
+  if (TREE_CODE (t_string) != STRING_CST)
+    {
+      error_at (call->location, "string literal required for arg 1");
+      return;
+    }
+
+  warning_at (call->location, 0, "%G%s", call,
+	      TREE_STRING_POINTER (t_string));
+}
+
+/* Call test_inlining on every statement within FUN.  */
+
+unsigned int
+pass_test_inlining::execute (function *fun)
+{
+  gimple_stmt_iterator gsi;
+  basic_block bb;
+
+  FOR_EACH_BB_FN (bb, fun)
+    for (gsi = gsi_start_bb (bb); !gsi_end_p (gsi); gsi_next (&gsi))
+      {
+	gimple *stmt = gsi_stmt (gsi);
+	test_inlining (stmt);
+      }
+
+  return 0;
+}
+
+/* Entrypoint for the plugin.  Create and register the custom pass.  */
+
+int
+plugin_init (struct plugin_name_args *plugin_info,
+	     struct plugin_gcc_version *version)
+{
+  struct register_pass_info pass_info;
+  const char *plugin_name = plugin_info->base_name;
+  int argc = plugin_info->argc;
+  struct plugin_argument *argv = plugin_info->argv;
+
+  if (!plugin_default_version_check (version, &gcc_version))
+    return 1;
+
+  pass_info.pass = new pass_test_inlining (g);
+  pass_info.reference_pass_name = "*warn_function_noreturn";
+  pass_info.ref_pass_instance_number = 1;
+  pass_info.pos_op = PASS_POS_INSERT_AFTER;
+  register_callback (plugin_name, PLUGIN_PASS_MANAGER_SETUP, NULL,
+		     &pass_info);
+
+  return 0;
+}
diff --git a/gcc/testsuite/gcc.dg/plugin/plugin.exp b/gcc/testsuite/gcc.dg/plugin/plugin.exp
index ff3c976..9da17d0 100644
--- a/gcc/testsuite/gcc.dg/plugin/plugin.exp
+++ b/gcc/testsuite/gcc.dg/plugin/plugin.exp
@@ -76,6 +76,11 @@  set plugin_test_list [list \
 	  diagnostic-test-string-literals-2.c \
 	  diagnostic-test-string-literals-3.c \
 	  diagnostic-test-string-literals-4.c } \
+    { diagnostic_plugin_test_inlining.c \
+	  diagnostic-test-inlining-1.c \
+	  diagnostic-test-inlining-2.c \
+	  diagnostic-test-inlining-3.c \
+	  diagnostic-test-inlining-4.c } \
     { location_overflow_plugin.c \
 	  location-overflow-test-1.c \
 	  location-overflow-test-2.c } \
diff --git a/gcc/testsuite/lib/prune.exp b/gcc/testsuite/lib/prune.exp
index afc1a69..b771da2 100644
--- a/gcc/testsuite/lib/prune.exp
+++ b/gcc/testsuite/lib/prune.exp
@@ -28,6 +28,9 @@  proc prune_gcc_output { text } {
 
     #send_user "Before:$text\n"
 
+    # Handle any freeform regexps.
+    set text [handle-dg-regexps $text]
+
     regsub -all "(^|\n)(\[^\n\]*: )?In ((static member |lambda )?function|member|method|(copy )?constructor|destructor|instantiation|substitution|program|subroutine|block-data)\[^\n\]*" $text "" text
     regsub -all "(^|\n)\[^\n\]*(: )?At (top level|global scope):\[^\n\]*" $text "" text
     regsub -all "(^|\n)\[^\n\]*:   (recursively )?required \[^\n\]*" $text "" text
@@ -73,9 +76,6 @@  proc prune_gcc_output { text } {
     # Call into multiline.exp to handle any multiline output directives.
     set text [handle-multiline-outputs $text]
 
-    # Handle any freeform regexps.
-    set text [handle-dg-regexps $text]
-
     #send_user "After:$text\n"
 
     return $text